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 "kyra/engine/kyra_hof.h"
24
25 #include "common/system.h"
26
27 namespace Kyra {
28
checkItemCollision(int x,int y)29 int KyraEngine_HoF::checkItemCollision(int x, int y) {
30 int itemPos = -1, yPos = -1;
31
32 for (int i = 0; i < 30; ++i) {
33 const ItemDefinition &curItem = _itemList[i];
34
35 if (curItem.id == kItemNone || curItem.sceneId != _mainCharacter.sceneId)
36 continue;
37
38 int itemX1 = curItem.x - 8 - 3;
39 int itemX2 = curItem.x + 7 + 3;
40
41 if (x < itemX1 || x > itemX2)
42 continue;
43
44 int itemY1 = curItem.y - _itemHtDat[curItem.id] - 3;
45 int itemY2 = curItem.y + 3;
46
47 if (y < itemY1 || y > itemY2)
48 continue;
49
50 if (curItem.y >= yPos) {
51 itemPos = i;
52 yPos = curItem.y;
53 }
54 }
55
56 return itemPos;
57 }
58
updateWaterFlasks()59 void KyraEngine_HoF::updateWaterFlasks() {
60 for (int i = 22; i < 24; i++) {
61 if (_itemInHand == i)
62 setHandItem(i - 1);
63
64 for (int ii = 0; ii < 20; ii++) {
65 if (_mainCharacter.inventory[ii] == i) {
66 _mainCharacter.inventory[ii]--;
67 if (ii < 10) {
68 clearInventorySlot(ii, 0);
69 _screen->drawShape(0, getShapePtr(i + 63), _inventoryX[ii], _inventoryY[ii], 0, 0);
70 }
71 }
72 }
73
74 for (int ii = 0; ii < 30; ii++) {
75 if (_itemList[ii].id == i)
76 _itemList[ii].id--;
77 }
78 }
79 }
80
dropItem(int unk1,Item item,int x,int y,int unk2)81 bool KyraEngine_HoF::dropItem(int unk1, Item item, int x, int y, int unk2) {
82 if (_mouseState <= -1)
83 return false;
84
85 bool success = processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2);
86 if (!success) {
87 snd_playSoundEffect(0x0D);
88 if (countAllItems() >= 30)
89 showMessageFromCCode(5, 0x84, 0);
90 }
91
92 return success;
93 }
94
processItemDrop(uint16 sceneId,Item item,int x,int y,int unk1,int unk2)95 bool KyraEngine_HoF::processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2) {
96 int itemPos = checkItemCollision(x, y);
97
98 if (unk1)
99 itemPos = -1;
100
101 if (itemPos >= 0) {
102 exchangeMouseItem(itemPos);
103 return false;
104 }
105
106 int freeItemSlot = -1;
107
108 if (unk1 != 3) {
109 for (int i = 0; i < 30; ++i) {
110 if (_itemList[i].id == kItemNone) {
111 freeItemSlot = i;
112 break;
113 }
114 }
115 }
116
117 if (freeItemSlot == -1)
118 return false;
119
120 if (sceneId != _mainCharacter.sceneId) {
121 _itemList[freeItemSlot].x = x;
122 _itemList[freeItemSlot].y = y;
123 _itemList[freeItemSlot].id = item;
124 _itemList[freeItemSlot].sceneId = sceneId;
125 return true;
126 }
127
128 int itemHeight = _itemHtDat[item];
129
130 // no idea why it's '&&' here and not single checks for x and y
131 if (x == -1 && y == -1) {
132 x = _rnd.getRandomNumberRng(0x10, 0x130);
133 y = _rnd.getRandomNumberRng(0x10, 0x87);
134 }
135
136 int posX = x, posY = y;
137 int itemX = -1, itemY = -1;
138 bool needRepositioning = true;
139
140 while (needRepositioning) {
141 if ((_screen->getDrawLayer(posX, posY) <= 1 && _screen->getDrawLayer2(posX, posY, itemHeight) <= 1 && isDropable(posX, posY)) || posY == 136) {
142 int posX2 = posX, posX3 = posX;
143 bool repositioning = true;
144
145 while (repositioning) {
146 if (isDropable(posX3, posY) && _screen->getDrawLayer(posX3, posY) < 7 && checkItemCollision(posX3, posY) == -1) {
147 itemX = posX3;
148 itemY = posY;
149 needRepositioning = false;
150 repositioning = false;
151 }
152
153 if (isDropable(posX2, posY) && _screen->getDrawLayer(posX2, posY) < 7 && checkItemCollision(posX2, posY) == -1) {
154 itemX = posX2;
155 itemY = posY;
156 needRepositioning = false;
157 repositioning = false;
158 }
159
160 if (repositioning) {
161 posX3 = MAX(posX3 - 2, 16);
162 posX2 = MIN(posX2 + 2, 304);
163
164 if (posX3 <= 16 && posX2 >= 304)
165 repositioning = false;
166 }
167 }
168 }
169
170 if (posY == 136)
171 needRepositioning = false;
172 else
173 posY = MIN(posY + 2, 136);
174 }
175
176 if (itemX == -1 || itemY == -1)
177 return false;
178
179 if (unk1 == 3) {
180 _itemList[freeItemSlot].x = itemX;
181 _itemList[freeItemSlot].y = itemY;
182 return true;
183 } else if (unk1 == 2) {
184 itemDropDown(x, y, itemX, itemY, freeItemSlot, item);
185 }
186
187 if (!unk1)
188 removeHandItem();
189
190 itemDropDown(x, y, itemX, itemY, freeItemSlot, item);
191
192 if (!unk1 && unk2) {
193 int itemStr = 3;
194 if (_lang == 1)
195 itemStr = getItemCommandStringDrop(item);
196 updateCommandLineEx(item+54, itemStr, 0xD6);
197 }
198
199 return true;
200 }
201
itemDropDown(int startX,int startY,int dstX,int dstY,int itemSlot,Item item)202 void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item) {
203 uint8 *itemShape = getShapePtr(item + 64);
204
205 if (startX == dstX && startY == dstY) {
206 if (_layerFlagTable[_screen->getLayer(dstX, dstY)] && item != 13) {
207 updateCharFacing();
208 snd_playSoundEffect(0x2D);
209 removeHandItem();
210 objectChat(getTableString(0xFF, _cCodeBuffer, true), 0, 0x83, 0xFF);
211 } else {
212 _itemList[itemSlot].x = dstX;
213 _itemList[itemSlot].y = dstY;
214 _itemList[itemSlot].id = item;
215 _itemList[itemSlot].sceneId = _mainCharacter.sceneId;
216 snd_playSoundEffect(0x0C);
217 addItemToAnimList(itemSlot);
218 }
219 } else {
220 _screen->hideMouse();
221
222 if (startY <= dstY) {
223 int speed = 2;
224 int curY = startY;
225 int curX = startX - 8;
226
227 backUpGfxRect24x24(curX, curY-16);
228 while (curY < dstY) {
229 restoreGfxRect24x24(curX, curY-16);
230
231 curY = MIN(curY + speed, dstY);
232 ++speed;
233
234 backUpGfxRect24x24(curX, curY-16);
235 uint32 endDelay = _system->getMillis() + _tickLength;
236
237 _screen->drawShape(0, itemShape, curX, curY-16, 0, 0);
238 _screen->updateScreen();
239
240 delayUntil(endDelay, false, true);
241 }
242
243 if (dstX != dstY || (dstY - startY > 16)) {
244 snd_playSoundEffect(0x69);
245 speed = MAX(speed, 6);
246 int speedX = ((dstX - startX) << 4) / speed;
247 int origSpeed = speed;
248 speed >>= 1;
249
250 if (dstY - startY <= 8)
251 speed >>= 1;
252
253 speed = -speed;
254
255 curX = startX << 4;
256
257 int x = 0, y = 0;
258 while (--origSpeed) {
259 x = (curX >> 4) - 8;
260 y = curY - 16;
261
262 restoreGfxRect24x24(x, y);
263 curY = MIN(curY + speed, dstY);
264 curX += speedX;
265 ++speed;
266
267 x = (curX >> 4) - 8;
268 y = curY - 16;
269 backUpGfxRect24x24(x, y);
270
271 uint16 endDelay = _system->getMillis() + _tickLength;
272 _screen->drawShape(0, itemShape, x, y, 0, 0);
273 _screen->updateScreen();
274
275 delayUntil(endDelay, false, true);
276 }
277
278 restoreGfxRect24x24(x, y);
279 } else {
280 restoreGfxRect24x24(curX, curY-16);
281 }
282 }
283
284 if (_layerFlagTable[_screen->getLayer(dstX, dstY)] && item != 13) {
285 updateCharFacing();
286 snd_playSoundEffect(0x2D);
287 removeHandItem();
288 _screen->showMouse();
289 objectChat(getTableString(0xFF, _cCodeBuffer, true), 0, 0x83, 0xFF);
290 } else {
291 _itemList[itemSlot].x = dstX;
292 _itemList[itemSlot].y = dstY;
293 _itemList[itemSlot].id = item;
294 _itemList[itemSlot].sceneId = _mainCharacter.sceneId;
295 snd_playSoundEffect(0x0C);
296 addItemToAnimList(itemSlot);
297 _screen->showMouse();
298 }
299 }
300 }
301
exchangeMouseItem(int itemPos)302 void KyraEngine_HoF::exchangeMouseItem(int itemPos) {
303 deleteItemAnimEntry(itemPos);
304
305 int itemId = _itemList[itemPos].id;
306 _itemList[itemPos].id = _itemInHand;
307 _itemInHand = itemId;
308
309 addItemToAnimList(itemPos);
310 snd_playSoundEffect(0x0B);
311 setMouseCursor(_itemInHand);
312 int str2 = 7;
313
314 if (_lang == 1)
315 str2 = getItemCommandStringPickUp(itemId);
316
317 updateCommandLineEx(itemId + 54, str2, 0xD6);
318
319 runSceneScript6();
320 }
321
pickUpItem(int x,int y)322 bool KyraEngine_HoF::pickUpItem(int x, int y) {
323 int itemPos = checkItemCollision(x, y);
324
325 if (itemPos <= -1)
326 return false;
327
328 if (_itemInHand >= 0) {
329 exchangeMouseItem(itemPos);
330 } else {
331 deleteItemAnimEntry(itemPos);
332 int itemId = _itemList[itemPos].id;
333 _itemList[itemPos].id = kItemNone;
334 snd_playSoundEffect(0x0B);
335 setMouseCursor(itemId);
336 int str2 = 7;
337
338 if (_lang == 1)
339 str2 = getItemCommandStringPickUp(itemId);
340
341 updateCommandLineEx(itemId + 54, str2, 0xD6);
342 _itemInHand = itemId;
343
344 runSceneScript6();
345 }
346
347 return true;
348 }
349
isDropable(int x,int y)350 bool KyraEngine_HoF::isDropable(int x, int y) {
351 if (x < 14 || x > 304 || y < 14 || y > 136)
352 return false;
353
354 x -= 8;
355 y -= 1;
356
357 for (int xpos = x; xpos < x + 16; ++xpos) {
358 if (_screen->getShapeFlag1(xpos, y) == 0)
359 return false;
360 }
361
362 return true;
363 }
364
getItemCommandStringDrop(Item item)365 int KyraEngine_HoF::getItemCommandStringDrop(Item item) {
366 assert(item >= 0 && item < _itemStringMapSize);
367 int stringId = _itemStringMap[item];
368
369 static const int dropStringIds[] = {
370 0x2D, 0x103, 0x003, 0x106
371 };
372 assert(stringId < ARRAYSIZE(dropStringIds));
373
374 return dropStringIds[stringId];
375 }
376
getItemCommandStringPickUp(Item item)377 int KyraEngine_HoF::getItemCommandStringPickUp(Item item) {
378 assert(item >= 0 && item < _itemStringMapSize);
379 int stringId = _itemStringMap[item];
380
381 static const int pickUpStringIds[] = {
382 0x02B, 0x102, 0x007, 0x105
383 };
384 assert(stringId < ARRAYSIZE(pickUpStringIds));
385
386 return pickUpStringIds[stringId];
387 }
388
getItemCommandStringInv(Item item)389 int KyraEngine_HoF::getItemCommandStringInv(Item item) {
390 assert(item >= 0 && item < _itemStringMapSize);
391 int stringId = _itemStringMap[item];
392
393 static const int pickUpStringIds[] = {
394 0x02C, 0x104, 0x008, 0x107
395 };
396 assert(stringId < ARRAYSIZE(pickUpStringIds));
397
398 return pickUpStringIds[stringId];
399 }
400
itemIsFlask(Item item)401 bool KyraEngine_HoF::itemIsFlask(Item item) {
402 for (int i = 0; _flaskTable[i] != kItemNone; ++i) {
403 if (_flaskTable[i] == item)
404 return true;
405 }
406
407 return false;
408 }
409
setMouseCursor(Item item)410 void KyraEngine_HoF::setMouseCursor(Item item) {
411 int shape = 0;
412 int hotX = 1;
413 int hotY = 1;
414
415 if (item != kItemNone) {
416 hotX = 8;
417 hotY = 15;
418 shape = item+64;
419 }
420
421 _screen->setMouseCursor(hotX, hotY, getShapePtr(shape));
422 }
423
424 } // End of namespace Kyra
425