ScummVM
items_mr.cpp
Go to the documentation of this file.
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_mr.h"
24 #include "kyra/engine/timer.h"
25 
26 #include "common/system.h"
27 
28 namespace Kyra {
29 
31  for (int i = 0; _trashItemList[i] != kItemNone; ++i) {
32  for (int item = findItem(_trashItemList[i]); item != -1; item = findItem(_trashItemList[i])) {
33  if (_itemList[item].sceneId != _mainCharacter.sceneId)
34  resetItem(item);
35  else
36  break;
37  }
38  }
39 }
40 
42  for (int i = 0; i < 10; ++i) {
44  return i;
45  }
46  return -1;
47 }
48 
50  int itemIndex = -1;
51  int maxItemY = -1;
52 
53  for (int i = 0; i < 50; ++i) {
54  if (_itemList[i].id == kItemNone || _itemList[i].sceneId != _mainCharacter.sceneId)
55  continue;
56 
57  const int x1 = _itemList[i].x - 11;
58  const int x2 = _itemList[i].x + 10;
59 
60  if (x < x1 || x > x2)
61  continue;
62 
63  const int y1 = _itemList[i].y - _itemBuffer1[_itemList[i].id] - 3;
64  const int y2 = _itemList[i].y + 3;
65 
66  if (y < y1 || y > y2)
67  continue;
68 
69  if (_itemList[i].y >= maxItemY) {
70  itemIndex = i;
71  maxItemY = _itemList[i].y;
72  }
73  }
74 
75  return itemIndex;
76 }
77 
79  int shape = 0;
80  int hotX = 1;
81  int hotY = 1;
82 
83  if (item != kItemNone) {
84  hotX = 12;
85  hotY = 19;
86  shape = item+248;
87  }
88 
89  _mouseState = item;
90  if ((int16)item >= 0)
91  _screen->setMouseCursor(hotX, hotY, getShapePtr(shape));
92 }
93 
96  if (_itemInHand == kItemNone)
98  else
100 }
101 
102 bool KyraEngine_MR::dropItem(int unk1, Item item, int x, int y, int unk2) {
103  if (_mouseState <= -1)
104  return false;
105 
106  if (processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2))
107  return true;
108 
109  snd_playSoundEffect(13, 200);
110 
111  if (countAllItems() >= 50) {
113  if (processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2))
114  return true;
115 
116  if (countAllItems() >= 50)
117  showMessageFromCCode(14, 0xB3, 0);
118  }
119 
120  if (!_chatText)
121  snd_playSoundEffect(13, 200);
122  return false;
123 }
124 
125 bool KyraEngine_MR::processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2) {
126  int itemPos = checkItemCollision(x, y);
127 
128  if (unk1)
129  itemPos = -1;
130 
131  if (itemPos >= 0) {
132  exchangeMouseItem(itemPos, 1);
133  return true;
134  }
135 
136  int freeItemSlot = -1;
137 
138  if (unk2 != 3) {
139  for (int i = 0; i < 50; ++i) {
140  if (_itemList[i].id == kItemNone) {
141  freeItemSlot = i;
142  break;
143  }
144  }
145  }
146 
147  if (freeItemSlot < 0)
148  return false;
149 
150  if (_mainCharacter.sceneId != sceneId) {
151  _itemList[freeItemSlot].x = x;
152  _itemList[freeItemSlot].y = y;
153  _itemList[freeItemSlot].id = item;
154  _itemList[freeItemSlot].sceneId = sceneId;
155  return true;
156  }
157 
158  int itemHeight = _itemBuffer1[item];
159 
160  // no idea why it's '&&' here and not single checks for x and y
161  if (x == -1 && y == -1) {
162  x = _rnd.getRandomNumberRng(0x18, 0x128);
163  y = _rnd.getRandomNumberRng(0x14, 0x87);
164  }
165 
166  int posX = x, posY = y;
167  int itemX = -1, itemY = -1;
168  bool needRepositioning = true;
169 
170  while (needRepositioning) {
171  if ((_screen->getDrawLayer(posX, posY) <= 1 && _screen->getDrawLayer2(posX, posY, itemHeight) <= 1 && isDropable(posX, posY)) || posY == 187) {
172  int posX2 = posX, posX3 = posX;
173  bool repositioning = true;
174 
175  while (repositioning) {
176  if (isDropable(posX3, posY) && _screen->getDrawLayer2(posX3, posY, itemHeight) < 7 && checkItemCollision(posX3, posY) == -1) {
177  itemX = posX3;
178  itemY = posY;
179  needRepositioning = false;
180  repositioning = false;
181  }
182 
183  if (isDropable(posX2, posY) && _screen->getDrawLayer2(posX2, posY, itemHeight) < 7 && checkItemCollision(posX2, posY) == -1) {
184  itemX = posX2;
185  itemY = posY;
186  needRepositioning = false;
187  repositioning = false;
188  }
189 
190  if (repositioning) {
191  posX3 = MAX(posX3 - 2, 24);
192  posX2 = MIN(posX2 + 2, 296);
193 
194  if (posX3 <= 24 && posX2 >= 296)
195  repositioning = false;
196  }
197  }
198  }
199 
200  if (posY == 187)
201  needRepositioning = false;
202  else
203  posY = MIN(posY + 2, 187);
204  }
205 
206  if (itemX == -1 || itemY == -1)
207  return false;
208 
209  if (unk1 == 3) {
210  _itemList[freeItemSlot].x = itemX;
211  _itemList[freeItemSlot].y = itemY;
212  return true;
213  } else if (unk1 == 2) {
214  itemDropDown(x, y, itemX, itemY, freeItemSlot, item, 0);
215  }
216 
217  itemDropDown(x, y, itemX, itemY, freeItemSlot, item, (unk1 == 0) ? 1 : 0);
218 
219  if (!unk1 && unk2) {
220  int itemStr = 1;
221  if (_lang == 1)
222  itemStr = getItemCommandStringDrop(item);
223  updateItemCommand(item, itemStr, 0xFF);
224  }
225 
226  return true;
227 }
228 
229 void KyraEngine_MR::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item, int remove) {
230  if (startX == dstX && startY == dstY) {
231  _itemList[itemSlot].x = dstX;
232  _itemList[itemSlot].y = dstY;
233  _itemList[itemSlot].id = item;
235  snd_playSoundEffect(0x0C, 0xC8);
236  addItemToAnimList(itemSlot);
237  } else {
238  uint8 *itemShape = getShapePtr(item + 248);
239  _screen->hideMouse();
240 
241  if (startY <= dstY) {
242  int speed = 2;
243  int curY = startY;
244  int curX = startX - 12;
245 
246  backUpGfxRect32x32(curX, curY-16);
247  while (curY < dstY) {
248  restoreGfxRect32x32(curX, curY-16);
249 
250  curY = MIN(curY + speed, dstY);
251  ++speed;
252 
253  backUpGfxRect32x32(curX, curY-16);
254  uint32 endDelay = _system->getMillis() + _tickLength;
255 
256  _screen->drawShape(0, itemShape, curX, curY-16, 0, 0);
258 
259  delayUntil(endDelay);
260  }
261  restoreGfxRect32x32(curX, curY-16);
262 
263  if (dstX != dstY || (dstY - startY > 16)) {
264  snd_playSoundEffect(0x11, 0xC8);
265  speed = MAX(speed, 6);
266  int speedX = ((dstX - startX) << 4) / speed;
267  int origSpeed = speed;
268  speed >>= 1;
269 
270  if (dstY - startY <= 8)
271  speed >>= 1;
272 
273  speed = -speed;
274 
275  curX = startX << 4;
276 
277  int x = 0, y = 0;
278  while (--origSpeed) {
279  curY = MIN(curY + speed, dstY);
280  curX += speedX;
281  ++speed;
282 
283  x = (curX >> 4) - 8;
284  y = curY - 16;
285  backUpGfxRect32x32(x, y);
286 
287  uint16 endDelay = _system->getMillis() + _tickLength;
288  _screen->drawShape(0, itemShape, x, y, 0, 0);
290 
292 
293  delayUntil(endDelay);
294  }
295 
297  }
298  }
299 
300  _itemList[itemSlot].x = dstX;
301  _itemList[itemSlot].y = dstY;
302  _itemList[itemSlot].id = item;
304  snd_playSoundEffect(0x0C, 0xC8);
305  addItemToAnimList(itemSlot);
306  _screen->showMouse();
307  }
308 
309  if (remove)
310  removeHandItem();
311 }
312 
313 void KyraEngine_MR::exchangeMouseItem(int itemPos, int runScript) {
314  if (itemListMagic(_itemInHand, itemPos))
315  return;
316 
317  if (_itemInHand == 43) {
318  removeHandItem();
319  return;
320  }
321 
322  deleteItemAnimEntry(itemPos);
323 
324  Item itemId = _itemList[itemPos].id;
325  _itemList[itemPos].id = _itemInHand;
326  _itemInHand = itemId;
327 
328  addItemToAnimList(itemPos);
329  snd_playSoundEffect(0x0B, 0xC8);
331  int str2 = 0;
332 
333  if (_lang == 1)
334  str2 = getItemCommandStringPickUp(itemId);
335 
336  updateItemCommand(itemId, str2, 0xFF);
337 
338  if (runScript)
339  runSceneScript6();
340 }
341 
342 bool KyraEngine_MR::pickUpItem(int x, int y, int runScript) {
343  int itemPos = checkItemCollision(x, y);
344 
345  if (itemPos <= -1)
346  return false;
347 
348  if (_itemInHand >= 0) {
349  exchangeMouseItem(itemPos, runScript);
350  } else {
351  deleteItemAnimEntry(itemPos);
352  Item itemId = _itemList[itemPos].id;
353  _itemList[itemPos].id = kItemNone;
354  snd_playSoundEffect(0x0B, 0xC8);
355  setMouseCursor(itemId);
356  int itemString = 0;
357 
358  if (_lang == 1)
359  itemString = getItemCommandStringPickUp(itemId);
360 
361  updateItemCommand(itemId, itemString, 0xFF);
362  _itemInHand = itemId;
363 
364  if (runScript)
365  runSceneScript6();
366  }
367 
368  return true;
369 }
370 
371 bool KyraEngine_MR::isDropable(int x, int y) {
372  if (y < 14 || y > 187)
373  return false;
374 
375  x -= 12;
376 
377  for (int xpos = x; xpos < x + 24; ++xpos) {
378  if (_screen->getShapeFlag1(xpos, y) == 0)
379  return false;
380  }
381 
382  return true;
383 }
384 
385 bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) {
386  Item item = _itemList[itemSlot].id;
387 
388  if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) {
389  eelScript();
390  return true;
391  } else if ((handItem == 6 || handItem == 7) && item == 2) {
392  int animObjIndex = -1;
393  for (int i = 17; i <= 66; ++i) {
394  if (_animObjects[i].shapeIndex2 == 250)
395  animObjIndex = i;
396  }
397 
398  assert(animObjIndex != -1);
399 
400  snd_playSoundEffect(0x93, 0xC8);
401  for (int i = 109; i <= 141; ++i) {
402  _animObjects[animObjIndex].shapeIndex1 = i+248;
403  _animObjects[animObjIndex].needRefresh = true;
404  delay(1*_tickLength, true);
405  }
406 
407  deleteItemAnimEntry(itemSlot);
408  _itemList[itemSlot].id = kItemNone;
409  return true;
410  }
411 
412  if (_mainCharacter.sceneId == 51 && queryGameFlag(0x19B) && !queryGameFlag(0x19C)
413  && ((item == 63 && handItem == 56) || (item == 56 && handItem == 63))) {
414 
415  if (queryGameFlag(0x1AC)) {
416  setGameFlag(0x19C);
417  setGameFlag(0x1AD);
418  } else {
419  setGameFlag(0x1AE);
420  }
421 
422  _timer->setCountdown(12, 1);
423  _timer->enable(12);
424  }
425 
426  for (int i = 0; _itemMagicTable[i] != 0xFF; i += 4) {
427  if (_itemMagicTable[i+0] != handItem || (int8)_itemMagicTable[i+1] != item)
428  continue;
429 
430  uint8 resItem = _itemMagicTable[i+2];
431  uint8 newItem = _itemMagicTable[i+3];
432 
433  snd_playSoundEffect(0x0F, 0xC8);
434 
435  _itemList[itemSlot].id = (int8)resItem;
436 
437  deleteItemAnimEntry(itemSlot);
438  addItemToAnimList(itemSlot);
439 
440  if (newItem == 0xFE)
441  removeHandItem();
442  else if (newItem != 0xFF)
443  setHandItem(newItem);
444 
445  if (_lang != 1)
446  updateItemCommand(resItem, 3, 0xFF);
447 
448  // Unlike the original we give points for when combining with scene items
449  if (resItem == 7) {
450  updateScore(35, 100);
451  delay(60*_tickLength, true);
452  }
453 
454  return true;
455  }
456 
457  return false;
458 }
459 
460 bool KyraEngine_MR::itemInventoryMagic(Item handItem, int invSlot) {
461  Item item = _mainCharacter.inventory[invSlot];
462 
463  if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) {
464  eelScript();
465  return true;
466  } else if ((handItem == 6 || handItem == 7) && item == 2) {
467  _screen->hideMouse();
468  snd_playSoundEffect(0x93, 0xC8);
469  for (int i = 109; i <= 141; ++i) {
470  _mainCharacter.inventory[invSlot] = i;
471  _screen->drawShape(2, getShapePtr(invSlot+422), 0, 144, 0, 0);
472  _screen->drawShape(2, getShapePtr(i+248), 0, 144, 0, 0);
473  _screen->copyRegion(0, 144, _inventoryX[invSlot], _inventoryY[invSlot], 24, 20, 2, 0, Screen::CR_NO_P_CHECK);
475  delay(1*_tickLength, true);
476  }
477 
479  clearInventorySlot(invSlot, 0);
480  _screen->showMouse();
481  return true;
482  }
483 
484  for (int i = 0; _itemMagicTable[i] != 0xFF; i += 4) {
485  if (_itemMagicTable[i+0] != handItem || _itemMagicTable[i+1] != item)
486  continue;
487 
488  uint8 resItem = _itemMagicTable[i+2];
489  uint8 newItem = _itemMagicTable[i+3];
490 
491  snd_playSoundEffect(0x0F, 0xC8);
492 
493  _mainCharacter.inventory[invSlot] = (int8)resItem;
494 
495  clearInventorySlot(invSlot, 0);
496  drawInventorySlot(0, resItem, invSlot);
497 
498  if (newItem == 0xFE)
499  removeHandItem();
500  else if (newItem != 0xFF)
501  setHandItem(newItem);
502 
503  if (_lang != 1)
504  updateItemCommand(resItem, 3, 0xFF);
505 
506  // Unlike the original we give points for every language
507  if (resItem == 7) {
508  updateScore(35, 100);
509  delay(60*_tickLength, true);
510  }
511 
512  return true;
513  }
514 
515  return false;
516 }
517 
519  assert(item < _itemStringMapSize);
520  int stringId = _itemStringMap[item];
521  return _itemStringDrop[stringId];
522 }
523 
525  assert(item < _itemStringMapSize);
526  int stringId = _itemStringMap[item];
527  return _itemStringPickUp[stringId];
528 }
529 
531  assert(item < _itemStringMapSize);
532  int stringId = _itemStringMap[item];
533  return _itemStringInv[stringId];
534 }
535 
536 } // End of namespace Kyra
const uint8 * _itemMagicTable
Definition: kyra_mr.h:299
Character _mainCharacter
Definition: kyra_v2.h:330
unsigned short uint16
Definition: cdtypes.h:27
void setMouseCursor(Item item)
Definition: items_mr.cpp:78
static const uint8 _itemStringInv[]
Definition: kyra_mr.h:307
unsigned int uint32
Definition: cdtypes.h:26
void addItemToAnimList(int item)
Screen_MR * _screen
Definition: kyra_mr.h:82
#define assert(s)
Definition: portdefs.h:77
static const uint8 _itemStringDrop[]
Definition: kyra_mr.h:306
signed char int8
Definition: cdtypes.h:31
int findFreeInventorySlot()
Definition: items_mr.cpp:41
uint8 * getShapePtr(int index) const
Definition: kyra_v2.cpp:191
int setGameFlag(int flag)
Definition: kyra_v1.cpp:511
bool itemInventoryMagic(Item handItem, int invSlot)
Definition: items_mr.cpp:460
bool itemListMagic(Item handItem, int itemSlot)
Definition: items_mr.cpp:385
virtual void setMouseCursor(int x, int y, const byte *shape)
Definition: screen.cpp:3059
int y
Definition: dialogs.cpp:409
void resetItem(int index)
Definition: items_v2.cpp:77
void setCountdown(uint8 id, int32 countdown)
Definition: timer.cpp:143
unsigned char uint8
Definition: cdtypes.h:28
void clearInventorySlot(int slot, int page)
Definition: gui_mr.cpp:454
bool processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2)
Definition: items_mr.cpp:125
bool updateScore(int scoreId, int strId)
Definition: kyra_mr.cpp:1289
AnimObj * _animObjects
Definition: kyra_v2.h:124
int8 * _itemBuffer1
Definition: kyra_mr.h:281
void setItemMouseCursor()
Definition: items_mr.cpp:94
int getItemCommandStringDrop(uint16 item)
Definition: items_mr.cpp:518
void drawInventorySlot(int page, Item item, int slot)
Definition: gui_mr.cpp:464
ShapeMap _gameShapes
Definition: kyra_v2.h:256
void updateScreen()
Definition: screen.cpp:324
int getDrawLayer(int x, int y)
Definition: screen_mr.cpp:82
TimerManager * _timer
Definition: kyra_v1.h:268
OSystem * _system
Definition: engine.h:59
int queryGameFlag(int flag) const
Definition: kyra_v1.cpp:517
void showMessageFromCCode(int string, uint8 c0, int)
Definition: gui_mr.cpp:122
virtual uint32 getMillis(bool skipRecord=false)=0
Get the number of milliseconds since the program was started.
void updateItemCommand(Item item, int str, uint8 c0)
Definition: gui_mr.cpp:126
byte getShapeFlag1(int x, int y)
Definition: screen_mr.cpp:59
void hideMouse()
Definition: screen.cpp:3029
void copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags=0)
Definition: screen.cpp:1007
T MIN(T a, T b)
Definition: util.h:49
uint getRandomNumberRng(uint min, uint max)
Generates a random unsigned integer in the interval [min, max].
Definition: random.cpp:58
void showMouse()
Definition: screen.cpp:3034
virtual void delayUntil(uint32 timestamp, bool updateGameTimers=false, bool update=false, bool isMainLoop=false)
Definition: kyra_v1.cpp:528
Constant for invalid item.
Definition: item.h:36
int getDrawLayer2(int x, int y, int height)
Definition: screen_mr.cpp:99
int getItemCommandStringInv(uint16 item)
Definition: items_mr.cpp:530
const uint8 * _itemStringMap
Definition: kyra_mr.h:303
void backUpGfxRect32x32(int x, int y)
Definition: kyra_mr.cpp:1224
InventoryItem item
Definition: action.cpp:650
bool dropItem(int unk1, Item item, int x, int y, int unk2)
Definition: items_mr.cpp:102
ItemDefinition * _itemList
Definition: kyra_v2.h:296
This is the namespace of the Kyra engine.
Definition: chargen.cpp:37
void delay(uint32 time, bool update=false, bool isMainLoop=false)
Definition: kyra_v2.cpp:149
int16 Item
Definition: item.h:30
void enable(uint8 id)
Definition: timer.cpp:230
int getItemCommandStringPickUp(uint16 item)
Definition: items_mr.cpp:524
bool pickUpItem(int x, int y, int runScript)
Definition: items_mr.cpp:342
void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item, int remove)
Definition: items_mr.cpp:229
void setHandItem(Item item)
Definition: items_v2.cpp:84
static const Item _trashItemList[]
Definition: kyra_mr.h:284
uint16 _tickLength
Definition: kyra_v1.h:311
signed short int16
Definition: cdtypes.h:30
static const uint8 _inventoryY[]
Definition: kyra_mr.h:259
bool isDropable(int x, int y)
Definition: items_mr.cpp:371
void removeTrashItems()
Definition: items_mr.cpp:30
static const uint8 _itemStringPickUp[]
Definition: kyra_mr.h:305
static const uint8 _inventoryX[]
Definition: kyra_mr.h:258
int checkItemCollision(int x, int y)
Definition: items_mr.cpp:49
virtual void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags,...)
Definition: screen.cpp:1542
void restoreGfxRect32x32(int x, int y)
Definition: kyra_mr.cpp:1228
void deleteItemAnimEntry(int item)
void exchangeMouseItem(int itemPos, int runScript)
Definition: items_mr.cpp:313
const char * _chatText
Definition: kyra_v2.h:346
T MAX(T a, T b)
Definition: util.h:50
int findItem(uint16 sceneId, Item id)
Definition: items_v2.cpp:56
Common::RandomSource _rnd
Definition: kyra_v1.h:205
void runSceneScript6()
Definition: scene_v2.cpp:68
void snd_playSoundEffect(int item, int volume)
Definition: kyra_mr.cpp:441