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