1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "trecision/actor.h"
24 #include "trecision/defines.h"
25 #include "trecision/graphics.h"
26 #include "trecision/logic.h"
27 #include "trecision/pathfinding3d.h"
28 #include "trecision/text.h"
29 #include "trecision/trecision.h"
30 #include "trecision/video.h"
31
32 namespace Trecision {
33
refreshInventory(uint8 startIcon,uint8 startLine)34 void TrecisionEngine::refreshInventory(uint8 startIcon, uint8 startLine) {
35 if (startLine > ICONDY)
36 return;
37
38 _graphicsMgr->clearScreenBufferInventory();
39
40 for (uint8 iconSlot = 0; iconSlot < ICONSHOWN; iconSlot++) {
41 uint8 i = iconSlot + startIcon;
42 if (i >= _inventory.size())
43 break;
44 const byte iconIndex = _inventory[i];
45 if (iconIndex == _lightIcon)
46 continue;
47
48 if (iconIndex <= EMPTYSLOT)
49 _graphicsMgr->drawInventoryIcon(iconIndex - 1, iconSlot, startLine);
50 else
51 _graphicsMgr->drawSaveSlotThumbnail(iconIndex - EMPTYSLOT - 1, iconSlot, startLine);
52 }
53
54 if (startIcon != 0)
55 _graphicsMgr->drawLeftInventoryArrow(startLine);
56
57 if (startIcon + ICONSHOWN < (int)_inventory.size())
58 _graphicsMgr->drawRightInventoryArrow(startLine);
59
60 _graphicsMgr->copyToScreen(0, FIRSTLINE, MAXX, ICONDY);
61 }
62
setInventoryStart(uint8 startIcon,uint8 startLine)63 void TrecisionEngine::setInventoryStart(uint8 startIcon, uint8 startLine) {
64 _inventoryRefreshStartIcon = startIcon;
65 _inventoryRefreshStartLine = startLine;
66 }
67
moveInventoryLeft()68 void TrecisionEngine::moveInventoryLeft() {
69 if (_iconBase < _inventory.size() - ICONSHOWN)
70 ++_iconBase;
71 setInventoryStart(_iconBase, INVENTORY_SHOW);
72 }
73
moveInventoryRight()74 void TrecisionEngine::moveInventoryRight() {
75 if (_iconBase > 0)
76 --_iconBase;
77 setInventoryStart(_iconBase, INVENTORY_SHOW);
78 }
79
showIconName()80 void TrecisionEngine::showIconName() {
81 if (isIconArea(_mousePos)) {
82 if (_inventoryStatus != INV_ON)
83 openInventory();
84 _curInventory = whatIcon(_mousePos);
85 showInventoryName(_curInventory, true);
86
87 if (!_flagUseWithStarted && !_flagSomeoneSpeaks) {
88 setInventoryStart(_iconBase, INVENTORY_SHOW);
89 }
90 } else if (isInventoryArea(_mousePos)) {
91 showInventoryName(NO_OBJECTS, true);
92 if (!_flagUseWithStarted) {
93 _lightIcon = 0xFF;
94 setInventoryStart(_iconBase, INVENTORY_SHOW);
95 }
96 }
97 }
98
openInventory()99 void TrecisionEngine::openInventory() {
100 if (!_flagInventoryLocked && (_inventoryStatus == INV_OFF) && !_flagDialogActive) {
101 _inventoryCounter = INVENTORY_HIDE;
102 _inventorySpeedIndex = 0;
103 _inventoryStatus = INV_PAINT;
104 }
105 }
106
closeInventory()107 void TrecisionEngine::closeInventory() {
108 if (!_flagInventoryLocked && (_inventoryStatus == INV_INACTION) && !_flagDialogActive) {
109 _inventoryCounter = INVENTORY_SHOW;
110 _inventorySpeedIndex = 0;
111 _inventoryStatus = INV_DEPAINT;
112 _lightIcon = 0xFF;
113 }
114 }
115
closeInventoryImmediately()116 void TrecisionEngine::closeInventoryImmediately() {
117 _inventoryStatus = INV_OFF;
118 _lightIcon = 0xFF;
119 _flagInventoryLocked = false;
120 _inventoryRefreshStartLine = INVENTORY_HIDE;
121 _inventoryCounter = INVENTORY_HIDE;
122 setInventoryStart(_inventoryRefreshStartIcon, INVENTORY_HIDE);
123 refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
124 }
125
examineItem()126 void TrecisionEngine::examineItem() {
127 _curInventory = whatIcon(_mousePos);
128 _actor->actorStop();
129 _pathFind->nextStep();
130 if (_flagUseWithStarted) {
131 endUseWith();
132 } else
133 doInvExamine();
134 }
135
useItem()136 void TrecisionEngine::useItem() {
137 _curInventory = whatIcon(_mousePos);
138 if (_curInventory == 0)
139 return;
140
141 if (_flagUseWithStarted) {
142 endUseWith();
143 } else if (_inventoryObj[_curInventory].isUseWith()) {
144 if (_curInventory == kItemFlare && _curRoom == kRoom29) {
145 _textMgr->characterSay(kSentenceOnlyGotOne);
146 return;
147 }
148 _animMgr->startSmkAnim(_inventoryObj[_curInventory]._anim);
149 _lightIcon = _curInventory;
150 setInventoryStart(_iconBase, INVENTORY_SHOW);
151 _flagInventoryLocked = true;
152 _flagUseWithStarted = true;
153 _useWith[USED] = _curInventory;
154 _useWithInv[USED] = true;
155 showInventoryName(_curInventory, true);
156 } else
157 doInvOperate();
158 }
159
endUseWith()160 void TrecisionEngine::endUseWith() {
161 _flagInventoryLocked = false;
162 _flagUseWithStarted = false;
163 _useWith[WITH] = _curInventory;
164 _useWithInv[WITH] = true;
165 _lightIcon = 0xFF;
166
167 if (_useWith[USED] != _curInventory) {
168 doUseWith();
169 } else {
170 _animMgr->smkStop(kSmackerIcon);
171 showInventoryName(_curInventory, true);
172 }
173 }
174
clearUseWith()175 void TrecisionEngine::clearUseWith() {
176 if (_flagUseWithStarted) {
177 if (_useWithInv[USED]) {
178 _lightIcon = 0xFF;
179 _animMgr->smkStop(kSmackerIcon);
180 setInventoryStart(_inventoryRefreshStartIcon, INVENTORY_HIDE);
181 _flagInventoryLocked = false;
182 }
183 _useWith[USED] = 0;
184 _useWith[WITH] = 0;
185 _useWithInv[USED] = false;
186 _useWithInv[WITH] = false;
187 _flagUseWithStarted = false;
188 _textMgr->clearLastText();
189 }
190 }
191
whatIcon(Common::Point pos)192 uint8 TrecisionEngine::whatIcon(Common::Point pos) {
193 if (pos.x < ICONMARGSX || pos.x > MAXX - ICONMARGDX)
194 return 0;
195
196 int index = _iconBase + ((pos.x - ICONMARGSX) / (ICONDX));
197
198 return index < (int)_inventory.size() ? _inventory[index] : 0;
199 }
200
iconPos(uint8 icon)201 int8 TrecisionEngine::iconPos(uint8 icon) {
202 for (uint8 i = 0; i < _inventory.size(); i++) {
203 if (_inventory[i] == icon)
204 return i;
205 }
206
207 return -1;
208 }
209
showInventoryName(uint16 obj,bool showhide)210 void TrecisionEngine::showInventoryName(uint16 obj, bool showhide) {
211 if (_logicMgr->isCloseupOrControlRoom() || _flagSomeoneSpeaks)
212 return;
213
214 if (_lastObj) {
215 _textMgr->clearLastText();
216 _lastObj = 0;
217 }
218
219 if (_flagUseWithStarted) {
220 if (!showhide) {
221 _textMgr->clearLastText();
222 _lastInv = 0;
223 return;
224 }
225 if ((obj | 0x8000) == _lastInv)
226 return;
227
228 Common::String desc = _sysText[kMessageUse];
229 if (_useWithInv[USED]) {
230 desc += _objName[_inventoryObj[_useWith[USED]]._name];
231 desc += _sysText[kMessageWith];
232 if (obj && (_inventoryObj[_useWith[USED]]._name != _inventoryObj[obj]._name))
233 desc += _objName[_inventoryObj[obj]._name];
234 } else {
235 if (_obj[_useWith[USED]].isModeHidden())
236 desc += "?"; // dunno
237 else
238 desc += _objName[_obj[_useWith[USED]]._name];
239 desc += _sysText[kMessageWith];
240 if (obj && (_obj[_useWith[USED]]._name != _inventoryObj[obj]._name))
241 desc += _objName[_inventoryObj[obj]._name];
242 }
243
244 const uint16 lenText = textLength(desc);
245 Common::Point pos(CLIP(320 - (lenText / 2), 2, MAXX - 2 - lenText), MAXY - CARHEI);
246
247 _lastInv = (obj | 0x8000);
248 if (_lastInv)
249 _textMgr->clearLastText();
250 _textMgr->addText(pos, desc.c_str(), COLOR_INVENTORY);
251 } else {
252 if (obj == _lastInv)
253 return;
254
255 if (!obj || !showhide) {
256 _textMgr->clearLastText();
257 _lastInv = 0;
258 return;
259 }
260
261 const uint16 lenText = textLength(_objName[_inventoryObj[obj]._name]);
262 uint16 posX = ICONMARGSX + ((iconPos(_curInventory) - _iconBase) * (ICONDX)) + ICONDX / 2;
263 posX = CLIP(posX - (lenText / 2), 2, MAXX - 2 - lenText);
264 Common::Point pos(posX, MAXY - CARHEI);
265
266 _lastInv = obj;
267
268 if (_lastInv)
269 _textMgr->clearLastText();
270
271 if (_inventoryObj[obj]._name)
272 _textMgr->addText(pos, _objName[_inventoryObj[obj]._name], COLOR_INVENTORY);
273 }
274 }
275
removeIcon(uint8 icon)276 void TrecisionEngine::removeIcon(uint8 icon) {
277 const int8 pos = iconPos(icon);
278 if (pos == -1)
279 return;
280
281 _inventory.remove_at(pos);
282 _iconBase = _inventory.size() <= ICONSHOWN ? 0 : _inventory.size() - ICONSHOWN;
283
284 _textMgr->redrawString();
285 }
286
addIcon(uint8 icon)287 void TrecisionEngine::addIcon(uint8 icon) {
288 if (iconPos(icon) != -1)
289 return;
290
291 _inventory.push_back(icon);
292 _iconBase = _inventory.size() <= ICONSHOWN ? 0 : _inventory.size() - ICONSHOWN;
293
294 // To show the icon that enters the inventory
295 // doEvent(MC_INVENTORY,ME_OPEN,MP_DEFAULT,0,0,0,0);
296 // FlagForceRegenInventory = true;
297 _textMgr->redrawString();
298 }
299
replaceIcon(uint8 oldIcon,uint8 newIcon)300 void TrecisionEngine::replaceIcon(uint8 oldIcon, uint8 newIcon) {
301 int8 pos = iconPos(oldIcon);
302 if (pos >= 0)
303 _inventory[pos] = newIcon;
304 }
305
rollInventory(uint8 status)306 void TrecisionEngine::rollInventory(uint8 status) {
307 static const int16 inventorySpeed[8] = { 20, 10, 5, 3, 2, 0, 0, 0 };
308
309 if (status == INV_PAINT) {
310 _inventoryCounter -= inventorySpeed[_inventorySpeedIndex++];
311 if (_inventoryCounter <= INVENTORY_SHOW || _inventorySpeedIndex > 5) {
312 _inventorySpeedIndex = 0;
313 setInventoryStart(_iconBase, INVENTORY_SHOW);
314 _inventoryStatus = INV_INACTION;
315 _inventoryCounter = INVENTORY_SHOW;
316 if (!isInventoryArea(_mousePos))
317 closeInventory();
318 _textMgr->redrawString();
319 return;
320 }
321 } else if (status == INV_DEPAINT) {
322 _inventoryCounter += inventorySpeed[_inventorySpeedIndex++];
323
324 if (_inventoryCounter > INVENTORY_HIDE || _inventorySpeedIndex > 5) {
325 _inventorySpeedIndex = 0;
326 setInventoryStart(_iconBase, INVENTORY_HIDE);
327 _inventoryStatus = INV_OFF;
328 _inventoryCounter = INVENTORY_HIDE;
329 if (isInventoryArea(_mousePos) && !(_flagDialogActive || _flagDialogMenuActive))
330 openInventory();
331 else
332 _textMgr->redrawString();
333 return;
334 }
335 }
336 setInventoryStart(_iconBase, _inventoryCounter);
337 }
338
doScrollInventory(Common::Point pos)339 void TrecisionEngine::doScrollInventory(Common::Point pos) {
340 if (_inventoryStatus != INV_INACTION)
341 return;
342
343 if (pos.x <= ICONMARGSX && _iconBase)
344 moveInventoryRight();
345 else if (isBetween(MAXX - ICONMARGDX, pos.x, MAXX) && (_iconBase + ICONSHOWN < (int)_inventory.size()))
346 moveInventoryLeft();
347 }
348
syncInventory(Common::Serializer & ser)349 void TrecisionEngine::syncInventory(Common::Serializer &ser) {
350 if (ser.isLoading()) {
351 _inventory.clear();
352 _cyberInventory.clear();
353 }
354
355 for (uint which = 0; which <= 1; which++) {
356 for (uint i = 0; i < MAXICON; i++) {
357 byte val = 0;
358 if (ser.isSaving()) {
359 if (which == 0)
360 val = i < _inventory.size() ? _inventory[i] : 0;
361 else
362 val = i < _cyberInventory.size() ? _cyberInventory[i] : 0;
363 ser.syncAsByte(val);
364 } else {
365 ser.syncAsByte(val);
366 if (val != kItemNull) {
367 if (which == 0)
368 _inventory.push_back(val);
369 else
370 _cyberInventory.push_back(val);
371 }
372 }
373 }
374 }
375 }
376
377 } // End of namespace Trecision
378