scummvm/engines/agi/inv.cpp
Martin Kiewitz f5a83adc01 AGI: Fix various CIDs
CID 1350104: regression from graphics rewrite in C64 picture drawing
CID 1350101: potential buffer overflow in set.simple command
CID 1350112: uninitialized variable in TextMgr
CID 1350113: false positive uninitialized variable in SystemUI
CID 1350114: potentially uninitialized variable in IIgsSample
CID 1350117: false positive uninitialized variable in InventoryMgr
CID 1350103: code bug in CGA rendering TextMgr::charAttrib_Set()
CID 1350109: false positive in GfxFont::loadFontAmigaPseudoTopaz()
CID 1350111: original AGI uninitialized memory issue
             in SpritesMgr::showObject
2016-02-09 12:47:45 +01:00

217 lines
5.7 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/inv.h"
#include "agi/text.h"
#include "agi/keyboard.h"
#include "agi/systemui.h"
namespace Agi {
InventoryMgr::InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI) {
_vm = agi;
_gfx = gfx;
_text = text;
_systemUI = systemUI;
_activeItemNr = -1;
}
InventoryMgr::~InventoryMgr() {
}
void InventoryMgr::getPlayerInventory() {
AgiGame game = _vm->_game;
int16 selectedInventoryItem = _vm->getVar(VM_VAR_SELECTED_INVENTORY_ITEM);
uint16 objectNr = 0;
int16 curRow = 2; // starting at position 2,1
int16 curColumn = 1;
_array.clear();
_activeItemNr = 0;
for (objectNr = 0; objectNr < game.numObjects; objectNr++) {
if (_vm->objectGetLocation(objectNr) == EGO_OWNED) {
// item is in the possession of ego, so add it to our internal list
if (objectNr == selectedInventoryItem) {
// it's the currently selected inventory item, remember that
_activeItemNr = _array.size();
}
InventoryEntry inventoryEntry;
inventoryEntry.objectNr = objectNr;
inventoryEntry.name = _vm->objectName(objectNr);
inventoryEntry.row = curRow;
inventoryEntry.column = curColumn;
if (inventoryEntry.column > 1) {
// right side, adjust column accordingly
inventoryEntry.column -= strlen(inventoryEntry.name);
}
_array.push_back(inventoryEntry);
// go to next position
if (curColumn == 1) {
// current position is left side, go to right side
curColumn = 39;
} else {
// current position is right side, so go to left side again and new row
curColumn = 1;
curRow++;
}
}
}
if (_array.size() == 0) {
// empty inventory
InventoryEntry inventoryEntry;
inventoryEntry.objectNr = 0;
inventoryEntry.name = _systemUI->getInventoryTextNothing();
inventoryEntry.row = 2;
inventoryEntry.column = 19 - (strlen(inventoryEntry.name) / 2);
_array.push_back(inventoryEntry);
}
}
void InventoryMgr::drawAll() {
int16 inventoryCount = _array.size();
int16 inventoryNr = 0;
_text->charPos_Set(0, 11);
_text->displayText(_systemUI->getInventoryTextYouAreCarrying());
for (inventoryNr = 0; inventoryNr < inventoryCount; inventoryNr++) {
drawItem(inventoryNr);
}
}
void InventoryMgr::drawItem(int16 itemNr) {
if (itemNr == _activeItemNr) {
_text->charAttrib_Set(15, 0);
} else {
_text->charAttrib_Set(0, 15);
}
_text->charPos_Set(_array[itemNr].row, _array[itemNr].column);
// original interpreter used printf here
// this doesn't really make sense, because for length calculation it's using strlen without printf
// which means right-aligned inventory items on the right side would not be displayed properly
// in case printf-formatting was actually used
// I have to assume that no game uses this, because behavior in original interpreter would have been buggy.
_text->displayText(_array[itemNr].name);
}
void InventoryMgr::show() {
bool selectItems = false;
// figure out current inventory of the player
getPlayerInventory();
if (_vm->getFlag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
selectItems = true;
} else {
_activeItemNr = -1; // so that none is shown as active
}
drawAll();
_text->charAttrib_Set(0, 15);
if (selectItems) {
_text->charPos_Set(24, 2);
_text->displayText(_systemUI->getInventoryTextSelectItems());
} else {
_text->charPos_Set(24, 4);
_text->displayText(_systemUI->getInventoryTextReturnToGame());
}
if (selectItems) {
_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_INVENTORY);
do {
_vm->processAGIEvents();
} while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
if (_activeItemNr >= 0) {
// pass selected object number
_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, _array[_activeItemNr].objectNr);
} else {
// nothing was selected
_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, 0xff);
}
} else {
// no selection is supposed to be possible, just wait for key and exit
_vm->waitAnyKey();
}
}
void InventoryMgr::keyPress(uint16 newKey) {
switch (newKey) {
case AGI_KEY_ENTER: {
_vm->cycleInnerLoopInactive(); // exit show-loop
break;
}
case AGI_KEY_ESCAPE: {
_vm->cycleInnerLoopInactive(); // exit show-loop
_activeItemNr = -1; // no item selected
break;
}
case AGI_KEY_UP:
changeActiveItem(-2);
break;
case AGI_KEY_DOWN:
changeActiveItem(+2);
break;
case AGI_KEY_LEFT:
changeActiveItem(-1);
break;
case AGI_KEY_RIGHT:
changeActiveItem(+1);
break;
default:
break;
}
}
void InventoryMgr::changeActiveItem(int16 direction) {
int16 orgItemNr = _activeItemNr;
_activeItemNr += direction;
if ((_activeItemNr >= 0) && (_activeItemNr < (int16)_array.size())) {
// within bounds
drawItem(orgItemNr);
drawItem(_activeItemNr);
} else {
// out of bounds, revert change
_activeItemNr = orgItemNr;
}
}
} // End of namespace Agi