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 /*
24 * Based on the Reverse Engineering work of Christophe Fontanel,
25 * maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
26 */
27
28 #include "graphics/surface.h"
29 #include "graphics/thumbnail.h"
30
31 #include "dm/inventory.h"
32 #include "dm/dungeonman.h"
33 #include "dm/eventman.h"
34 #include "dm/group.h"
35 #include "dm/menus.h"
36 #include "dm/gfx.h"
37 #include "dm/text.h"
38 #include "dm/objectman.h"
39 #include "dm/timeline.h"
40 #include "dm/projexpl.h"
41 #include "dm/sounds.h"
42
43
44 namespace DM {
45
initConstants()46 void InventoryMan::initConstants() {
47 static const char* skillLevelNamesEN[15] = {"NEOPHYTE", "NOVICE", "APPRENTICE", "JOURNEYMAN", "CRAFTSMAN",
48 "ARTISAN", "ADEPT", "EXPERT", "` MASTER", "a MASTER","b MASTER", "c MASTER", "d MASTER", "e MASTER", "ARCHMASTER"};
49 static const char* skillLevelNamesDE[15] = {"ANFAENGER", "NEULING", "LEHRLING", "ARBEITER", "GESELLE", "HANDWERKR", "FACHMANN",
50 "EXPERTE", "` MEISTER", "a MEISTER", "b MEISTER", "c MEISTER", "d MEISTER", "e MEISTER", "ERZMEISTR"};
51 static const char* skillLevelNamesFR[15] = {"NEOPHYTE", "NOVICE", "APPRENTI", "COMPAGNON", "ARTISAN", "PATRON",
52 "ADEPTE", "EXPERT", "MAITRE '", "MAITRE a", "MAITRE b", "MAITRE c", "MAITRE d", "MAITRE e", "SUR-MAITRE"};
53 const char **translatedSkillLevel;
54 switch (_vm->getGameLanguage()) { // localized
55 default:
56 case Common::EN_ANY:
57 translatedSkillLevel = skillLevelNamesEN;
58 break;
59 case Common::DE_DEU:
60 translatedSkillLevel = skillLevelNamesDE;
61 break;
62 case Common::FR_FRA:
63 translatedSkillLevel = skillLevelNamesFR;
64 break;
65 }
66 for (int i = 0; i < 15; ++i)
67 _skillLevelNames[i] = translatedSkillLevel[i];
68
69 _boxPanel = Box(80, 223, 52, 124); // @ G0032_s_Graphic562_Box_Panel
70 }
71
InventoryMan(DMEngine * vm)72 InventoryMan::InventoryMan(DMEngine *vm) : _vm(vm) {
73 _inventoryChampionOrdinal = 0;
74 _panelContent = kDMPanelContentFoodWaterPoisoned;
75 for (uint16 i = 0; i < 8; ++i)
76 _chestSlots[i] = Thing(0);
77 _openChest = _vm->_thingNone;
78 _objDescTextXpos = 0;
79 _objDescTextYpos = 0;
80
81 for (int i = 0; i < 15; i++)
82 _skillLevelNames[i] = nullptr;
83
84 initConstants();
85 }
86
toggleInventory(ChampionIndex championIndex)87 void InventoryMan::toggleInventory(ChampionIndex championIndex) {
88 static Box boxFloppyZzzCross(174, 218, 2, 12); // @ G0041_s_Graphic562_Box_ViewportFloppyZzzCross
89
90 DisplayMan &display = *_vm->_displayMan;
91 ChampionMan &championMan = *_vm->_championMan;
92
93 if ((championIndex != kDMChampionCloseInventory) && !championMan._champions[championIndex]._currHealth)
94 return;
95
96 if (_vm->_pressingMouth || _vm->_pressingEye)
97 return;
98
99 _vm->_stopWaitingForPlayerInput = true;
100 uint16 inventoryChampionOrdinal = _inventoryChampionOrdinal;
101 if (_vm->indexToOrdinal(championIndex) == inventoryChampionOrdinal)
102 championIndex = kDMChampionCloseInventory;
103
104 _vm->_eventMan->showMouse();
105 if (inventoryChampionOrdinal) {
106 _inventoryChampionOrdinal = _vm->indexToOrdinal(kDMChampionNone);
107 closeChest();
108 Champion *champion = &championMan._champions[_vm->ordinalToIndex(inventoryChampionOrdinal)];
109 if (champion->_currHealth && !championMan._candidateChampionOrdinal) {
110 setFlag(champion->_attributes, kDMAttributeStatusBox);
111 championMan.drawChampionState((ChampionIndex)_vm->ordinalToIndex(inventoryChampionOrdinal));
112 }
113 if (championMan._partyIsSleeping) {
114 _vm->_eventMan->hideMouse();
115 return;
116 }
117 if (championIndex == kDMChampionCloseInventory) {
118 _vm->_eventMan->_refreshMousePointerInMainLoop = true;
119 _vm->_menuMan->drawMovementArrows();
120 _vm->_eventMan->hideMouse();
121 _vm->_eventMan->_secondaryMouseInput = _vm->_eventMan->_secondaryMouseInputMovement;
122 _vm->_eventMan->_secondaryKeyboardInput = _vm->_eventMan->_secondaryKeyboardInputMovement;
123 _vm->_eventMan->discardAllInput();
124 display.drawFloorAndCeiling();
125 return;
126 }
127 }
128 display._useByteBoxCoordinates = false;
129 _inventoryChampionOrdinal = _vm->indexToOrdinal(championIndex);
130 if (!inventoryChampionOrdinal)
131 display.shadeScreenBox(&display._boxMovementArrows, kDMColorBlack);
132
133 Champion *champion = &championMan._champions[championIndex];
134 display.loadIntoBitmap(kDMGraphicIdxInventory, display._bitmapViewport);
135 if (championMan._candidateChampionOrdinal)
136 display.fillBoxBitmap(display._bitmapViewport, boxFloppyZzzCross, kDMColorDarkestGray, k112_byteWidthViewport, k136_heightViewport);
137
138 switch (_vm->getGameLanguage()) { // localized
139 default:
140 case Common::EN_ANY:
141 _vm->_textMan->printToViewport(5, 116, kDMColorLightestGray, "HEALTH");
142 _vm->_textMan->printToViewport(5, 124, kDMColorLightestGray, "STAMINA");
143 break;
144 case Common::DE_DEU:
145 _vm->_textMan->printToViewport(5, 116, kDMColorLightestGray, "GESUND");
146 _vm->_textMan->printToViewport(5, 124, kDMColorLightestGray, "KRAFT");
147 break;
148 case Common::FR_FRA:
149 _vm->_textMan->printToViewport(5, 116, kDMColorLightestGray, "SANTE");
150 _vm->_textMan->printToViewport(5, 124, kDMColorLightestGray, "VIGUEUR");
151 break;
152 }
153
154 _vm->_textMan->printToViewport(5, 132, kDMColorLightestGray, "MANA");
155
156 for (uint16 i = kDMSlotReadyHand; i < kDMSlotChest1; i++)
157 championMan.drawSlot(championIndex, i);
158
159 setFlag(champion->_attributes, kDMAttributeViewport | kDMAttributeStatusBox | kDMAttributePanel | kDMAttributeLoad | kDMAttributeStatistics | kDMAttributeNameTitle);
160 championMan.drawChampionState(championIndex);
161 _vm->_eventMan->_mousePointerBitmapUpdated = true;
162 _vm->_eventMan->hideMouse();
163 _vm->_eventMan->_secondaryMouseInput = _vm->_eventMan->_secondaryMouseInputChampionInventory;
164 _vm->_eventMan->_secondaryKeyboardInput = nullptr;
165 _vm->_eventMan->discardAllInput();
166 }
167
drawStatusBoxPortrait(ChampionIndex championIndex)168 void InventoryMan::drawStatusBoxPortrait(ChampionIndex championIndex) {
169 DisplayMan &dispMan = *_vm->_displayMan;
170
171 dispMan._useByteBoxCoordinates = false;
172 Box box;
173 box._rect.top = 0;
174 box._rect.bottom = 28;
175 box._rect.left = championIndex * kDMChampionStatusBoxSpacing + 7;
176 box._rect.right = box._rect.left + 31;
177 dispMan.blitToScreen(_vm->_championMan->_champions[championIndex]._portrait, &box, k16_byteWidth, kDMColorNoTransparency, 29);
178 }
179
drawPanelHorizontalBar(int16 x,int16 y,int16 pixelWidth,Color color)180 void InventoryMan::drawPanelHorizontalBar(int16 x, int16 y, int16 pixelWidth, Color color) {
181 DisplayMan &display = *_vm->_displayMan;
182 Box box;
183 box._rect.left = x;
184 box._rect.right = box._rect.left + pixelWidth;
185 box._rect.top = y;
186 box._rect.bottom = box._rect.top + 6;
187 display._useByteBoxCoordinates = false;
188 display.fillBoxBitmap(display._bitmapViewport, box, color, k112_byteWidthViewport, k136_heightViewport);
189 }
190
drawPanelFoodOrWaterBar(int16 amount,int16 y,Color color)191 void InventoryMan::drawPanelFoodOrWaterBar(int16 amount, int16 y, Color color) {
192 if (amount < -512)
193 color = kDMColorRed;
194 else if (amount < 0)
195 color = kDMColorYellow;
196
197 int16 pixelWidth = amount + 1024;
198 if (pixelWidth == 3072)
199 pixelWidth = 3071;
200
201 pixelWidth /= 32;
202 drawPanelHorizontalBar(115, y + 2, pixelWidth, kDMColorBlack);
203 drawPanelHorizontalBar(113, y, pixelWidth, color);
204 }
205
drawPanelFoodWaterPoisoned()206 void InventoryMan::drawPanelFoodWaterPoisoned() {
207 static Box boxFood(112, 159, 60, 68); // @ G0035_s_Graphic562_Box_Food
208 static Box boxWater(112, 159, 83, 91); // @ G0036_s_Graphic562_Box_Water
209 static Box boxPoisoned(112, 207, 105, 119); // @ G0037_s_Graphic562_Box_Poisoned
210
211 Champion &champ = _vm->_championMan->_champions[_inventoryChampionOrdinal];
212 closeChest();
213 DisplayMan &dispMan = *_vm->_displayMan;
214
215 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPanelEmpty), _boxPanel, k72_byteWidth, kDMColorRed, 73);
216
217 switch (_vm->getGameLanguage()) { // localized
218 default:
219 case Common::EN_ANY:
220 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxFoodLabel), boxFood, k24_byteWidth, kDMColorDarkestGray, 9);
221 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxWaterLabel), boxWater, k24_byteWidth, kDMColorDarkestGray, 9);
222 break;
223 case Common::DE_DEU:
224 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxFoodLabel), boxFood, k32_byteWidth, kDMColorDarkestGray, 9);
225 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxWaterLabel), boxWater, k32_byteWidth, kDMColorDarkestGray, 9);
226 break;
227 case Common::FR_FRA:
228 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxFoodLabel), boxFood, k48_byteWidth, kDMColorDarkestGray, 9);
229 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxWaterLabel), boxWater, k24_byteWidth, kDMColorDarkestGray, 9);
230 break;
231 }
232
233 if (champ._poisonEventCount)
234 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPoisionedLabel),
235 boxPoisoned, k48_byteWidth, kDMColorDarkestGray, 15);
236
237 drawPanelFoodOrWaterBar(champ._food, 69, kDMColorLightBrown);
238 drawPanelFoodOrWaterBar(champ._water, 92, kDMColorBlue);
239 }
240
drawPanelResurrectReincarnate()241 void InventoryMan::drawPanelResurrectReincarnate() {
242 DisplayMan &display = *_vm->_displayMan;
243
244 _panelContent = kDMPanelContentResurrectReincarnate;
245 display.blitToViewport(display.getNativeBitmapOrGraphic(kDMGraphicIdxPanelResurectReincarnate),
246 _boxPanel, k72_byteWidth, kDMColorDarkGreen, 73);
247 }
248
drawPanel()249 void InventoryMan::drawPanel() {
250 closeChest();
251
252 ChampionMan &cm = *_vm->_championMan;
253 if (cm._candidateChampionOrdinal) {
254 drawPanelResurrectReincarnate();
255 return;
256 }
257
258 Thing thing = cm._champions[_vm->ordinalToIndex(_inventoryChampionOrdinal)].getSlot(kDMSlotActionHand);
259
260 _panelContent = kDMPanelContentFoodWaterPoisoned;
261 switch (thing.getType()) {
262 case kDMThingTypeContainer:
263 _panelContent = kDMPanelContentChest;
264 break;
265 case kDMThingTypeScroll:
266 _panelContent = kDMPanelContentScroll;
267 break;
268 default:
269 thing = _vm->_thingNone;
270 break;
271 }
272
273 if (thing == _vm->_thingNone)
274 drawPanelFoodWaterPoisoned();
275 else
276 drawPanelObject(thing, false);
277 }
278
closeChest()279 void InventoryMan::closeChest() {
280 DungeonMan &dunMan = *_vm->_dungeonMan;
281
282 bool processFirstChestSlot = true;
283 if (_openChest == _vm->_thingNone)
284 return;
285 Container *container = (Container *)dunMan.getThingData(_openChest);
286 _openChest = _vm->_thingNone;
287 container->getSlot() = _vm->_thingEndOfList;
288 Thing prevThing;
289 for (int16 chestSlotIndex = 0; chestSlotIndex < 8; ++chestSlotIndex) {
290 Thing thing = _chestSlots[chestSlotIndex];
291 if (thing != _vm->_thingNone) {
292 _chestSlots[chestSlotIndex] = _vm->_thingNone; // CHANGE8_09_FIX
293
294 if (processFirstChestSlot) {
295 processFirstChestSlot = false;
296 *dunMan.getThingData(thing) = _vm->_thingEndOfList.toUint16();
297 container->getSlot() = prevThing = thing;
298 } else {
299 dunMan.linkThingToList(thing, prevThing, kDMMapXNotOnASquare, 0);
300 prevThing = thing;
301 }
302 }
303 }
304 }
305
drawPanelScrollTextLine(int16 yPos,char * text)306 void InventoryMan::drawPanelScrollTextLine(int16 yPos, char *text) {
307 for (char *iter = text; *iter != '\0'; ++iter) {
308 if ((*iter >= 'A') && (*iter <= 'Z'))
309 *iter -= 64;
310 else if (*iter >= '{') // this branch is CHANGE5_03_IMPROVEMENT
311 *iter -= 96;
312 }
313 _vm->_textMan->printToViewport(162 - (6 * strlen(text) / 2), yPos, kDMColorBlack, text, kDMColorWhite);
314 }
315
drawPanelScroll(Scroll * scroll)316 void InventoryMan::drawPanelScroll(Scroll *scroll) {
317 DisplayMan &dispMan = *_vm->_displayMan;
318
319 char stringFirstLine[300];
320 _vm->_dungeonMan->decodeText(stringFirstLine, Thing(scroll->getTextStringThingIndex()), (TextType)(kDMTextTypeScroll | kDMMaskDecodeEvenIfInvisible));
321 char *charRed = stringFirstLine;
322 while (*charRed && (*charRed != '\n'))
323 charRed++;
324
325 *charRed = '\0';
326 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPanelOpenScroll),
327 _boxPanel, k72_byteWidth, kDMColorRed, 73);
328 int16 lineCount = 1;
329 charRed++;
330 char *charGreen = charRed; // first char of the second line
331 while (*charGreen) {
332 /* BUG0_47 Graphical glitch when you open a scroll. If there is a single line of text in a scroll
333 (with no carriage return) then charGreen points to undefined data. This may result in a graphical
334 glitch and also corrupt other memory. This is not an issue in the original dungeons where all
335 scrolls contain at least one carriage return character */
336 if (*charGreen == '\n')
337 lineCount++;
338
339 charGreen++;
340 }
341
342 if (*(charGreen - 1) != '\n')
343 lineCount++;
344 else if (*(charGreen - 2) == '\n')
345 lineCount--;
346
347 int16 yPos = 92 - (7 * lineCount) / 2; // center the text vertically
348 drawPanelScrollTextLine(yPos, stringFirstLine);
349 charGreen = charRed;
350 while (*charGreen) {
351 yPos += 7;
352 while (*charRed && (*charRed != '\n'))
353 charRed++;
354
355 if (!(*charRed))
356 charRed[1] = '\0';
357
358 *charRed++ = '\0';
359 drawPanelScrollTextLine(yPos, charGreen);
360 charGreen = charRed;
361 }
362 }
363
openAndDrawChest(Thing thingToOpen,Container * chest,bool isPressingEye)364 void InventoryMan::openAndDrawChest(Thing thingToOpen, Container *chest, bool isPressingEye) {
365 DisplayMan &dispMan = *_vm->_displayMan;
366 ObjectMan &objMan = *_vm->_objectMan;
367
368 if (_openChest == thingToOpen)
369 return;
370
371 if (_openChest != _vm->_thingNone)
372 closeChest(); // CHANGE8_09_FIX
373
374 _openChest = thingToOpen;
375 if (!isPressingEye) {
376 objMan.drawIconInSlotBox(kDMSlotBoxInventoryActionHand, kDMIconIndiceContainerChestOpen);
377 }
378 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPanelOpenChest),
379 _boxPanel, k72_byteWidth, kDMColorRed, 73);
380 int16 chestSlotIndex = 0;
381 Thing thing = chest->getSlot();
382 int16 thingCount = 0;
383 while (thing != _vm->_thingEndOfList) {
384 if (++thingCount > 8)
385 break; // CHANGE8_08_FIX, make sure that no more than the first 8 objects in a chest are drawn
386
387 objMan.drawIconInSlotBox(chestSlotIndex + kDMSlotBoxChestFirstSlot, objMan.getIconIndex(thing));
388 _chestSlots[chestSlotIndex++] = thing;
389 thing = _vm->_dungeonMan->getNextThing(thing);
390 }
391 while (chestSlotIndex < 8) {
392 objMan.drawIconInSlotBox(chestSlotIndex + kDMSlotBoxChestFirstSlot, kDMIconIndiceNone);
393 _chestSlots[chestSlotIndex++] = _vm->_thingNone;
394 }
395 }
396
drawIconToViewport(IconIndice iconIndex,int16 xPos,int16 yPos)397 void InventoryMan::drawIconToViewport(IconIndice iconIndex, int16 xPos, int16 yPos) {
398 static byte iconBitmap[16 * 16];
399 Box boxIcon(xPos, xPos + 15, yPos, yPos + 15);
400
401 _vm->_objectMan->extractIconFromBitmap(iconIndex, iconBitmap);
402 _vm->_displayMan->blitToViewport(iconBitmap, boxIcon, k8_byteWidth, kDMColorNoTransparency, 16);
403 }
404
buildObjectAttributeString(int16 potentialAttribMask,int16 actualAttribMask,const char ** attribStrings,char * destString,const char * prefixString,const char * suffixString)405 void InventoryMan::buildObjectAttributeString(int16 potentialAttribMask, int16 actualAttribMask, const char **attribStrings, char *destString, const char *prefixString, const char *suffixString) {
406 uint16 identicalBitCount = 0;
407 int16 attribMask = 1;
408 for (uint16 stringIndex = 0; stringIndex < 16; stringIndex++, attribMask <<= 1) {
409 if (attribMask & potentialAttribMask & actualAttribMask)
410 identicalBitCount++;
411 }
412
413 if (identicalBitCount == 0) {
414 *destString = '\0';
415 return;
416 }
417
418 strcpy(destString, prefixString);
419
420 attribMask = 1;
421 for (uint16 stringIndex = 0; stringIndex < 16; stringIndex++, attribMask <<= 1) {
422 if (attribMask & potentialAttribMask & actualAttribMask) {
423 strcat(destString, attribStrings[stringIndex]);
424 if (identicalBitCount-- > 2) {
425 strcat(destString, ", ");
426 } else if (identicalBitCount == 1) {
427
428 switch (_vm->getGameLanguage()) { // localized
429 default:
430 case Common::EN_ANY: strcat(destString, " AND "); break;
431 case Common::DE_DEU: strcat(destString, " UND "); break;
432 case Common::FR_FRA: strcat(destString, " ET "); break;
433 }
434 }
435 }
436 }
437
438 strcat(destString, suffixString);
439 }
440
drawPanelObjectDescriptionString(const char * descString)441 void InventoryMan::drawPanelObjectDescriptionString(const char *descString) {
442 if (descString[0] == '\f') { // form feed
443 descString++;
444 _objDescTextXpos = 108;
445 _objDescTextYpos = 59;
446 }
447
448 if (descString[0]) {
449 char stringTmpBuff[128];
450 strcpy(stringTmpBuff, descString);
451
452 char *stringLine = stringTmpBuff;
453 bool severalLines = false;
454 char *string = nullptr;
455 while (*stringLine) {
456 if (strlen(stringLine) > 18) { // if string is too long to fit on one line
457 string = &stringLine[17];
458 while (*string != ' ') // go back to the last space character
459 string--;
460
461 *string = '\0'; // and split the string there
462 severalLines = true;
463 }
464
465 _vm->_textMan->printToViewport(_objDescTextXpos, _objDescTextYpos, kDMColorLightestGray, stringLine);
466 _objDescTextYpos += 7;
467 if (severalLines) {
468 severalLines = false;
469 stringLine = ++string;
470 } else {
471 *stringLine = '\0';
472 }
473 }
474 }
475 }
476
drawPanelArrowOrEye(bool pressingEye)477 void InventoryMan::drawPanelArrowOrEye(bool pressingEye) {
478 static Box boxArrowOrEye(83, 98, 57, 65); // @ G0033_s_Graphic562_Box_ArrowOrEye
479
480 DisplayMan &dispMan = *_vm->_displayMan;
481 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(pressingEye ? kDMGraphicIdxEyeForObjectDescription : kDMGraphicIdxArrowForChestContent),
482 boxArrowOrEye, k8_byteWidth, kDMColorRed, 9);
483 }
484
drawPanelObject(Thing thingToDraw,bool pressingEye)485 void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
486 static Box boxObjectDescCircle(105, 136, 53, 79); // @ G0034_s_Graphic562_Box_ObjectDescriptionCircle
487
488 DungeonMan &dungeon = *_vm->_dungeonMan;
489 ObjectMan &objMan = *_vm->_objectMan;
490 DisplayMan &dispMan = *_vm->_displayMan;
491 ChampionMan &champMan = *_vm->_championMan;
492 TextMan &textMan = *_vm->_textMan;
493
494 if (_vm->_pressingEye || _vm->_pressingMouth)
495 closeChest();
496
497 uint16 *rawThingPtr = dungeon.getThingData(thingToDraw);
498 drawPanelObjectDescriptionString("\f"); // form feed
499 ThingType thingType = thingToDraw.getType();
500 if (thingType == kDMThingTypeScroll)
501 drawPanelScroll((Scroll *)rawThingPtr);
502 else if (thingType == kDMThingTypeContainer)
503 openAndDrawChest(thingToDraw, (Container *)rawThingPtr, pressingEye);
504 else {
505 IconIndice iconIndex = objMan.getIconIndex(thingToDraw);
506 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPanelEmpty),
507 _boxPanel, k72_byteWidth, kDMColorRed, 73);
508 dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxObjectDescCircle),
509 boxObjectDescCircle, k16_byteWidth, kDMColorDarkestGray, 27);
510
511 Common::String descString;
512 Common::String str;
513 if (iconIndex == kDMIconIndiceJunkChampionBones) {
514 switch (_vm->getGameLanguage()) { // localized
515 case Common::FR_FRA:
516 // Fix original bug dur to a cut&paste error: string was concatenated then overwritten by the name
517 str = Common::String::format("%s %s", objMan._objectNames[iconIndex], champMan._champions[((Junk *)rawThingPtr)->getChargeCount()]._name);
518 break;
519 default: // German and English versions are the same
520 str = Common::String::format("%s %s", champMan._champions[((Junk *)rawThingPtr)->getChargeCount()]._name, objMan._objectNames[iconIndex]);
521 break;
522 }
523
524 descString = str;
525 } else if ((thingType == kDMThingTypePotion)
526 && (iconIndex != kDMIconIndicePotionWaterFlask)
527 && (champMan.getSkillLevel((ChampionIndex)_vm->ordinalToIndex(_inventoryChampionOrdinal), kDMSkillPriest) > 1)) {
528 str = ('_' + ((Potion *)rawThingPtr)->getPower() / 40);
529 str += " ";
530 str += objMan._objectNames[iconIndex];
531 descString = str;
532 } else {
533 descString = objMan._objectNames[iconIndex];
534 }
535
536 textMan.printToViewport(134, 68, kDMColorLightestGray, descString.c_str());
537 drawIconToViewport(iconIndex, 111, 59);
538
539
540 _objDescTextYpos = 87;
541
542 uint16 potentialAttribMask = 0;
543 uint16 actualAttribMask = 0;
544 switch (thingType) {
545 case kDMThingTypeWeapon: {
546 potentialAttribMask = kDMDescriptionMaskCursed | kDMDescriptionMaskPoisoned | kDMDescriptionMaskBroken;
547 Weapon *weapon = (Weapon *)rawThingPtr;
548 actualAttribMask = (weapon->getCursed() << 3) | (weapon->getPoisoned() << 1) | (weapon->getBroken() << 2);
549 if ((iconIndex >= kDMIconIndiceWeaponTorchUnlit)
550 && (iconIndex <= kDMIconIndiceWeaponTorchLit)
551 && (weapon->getChargeCount() == 0)) {
552
553 switch (_vm->getGameLanguage()) { // localized
554 default:
555 case Common::EN_ANY:
556 drawPanelObjectDescriptionString("(BURNT OUT)");
557 break;
558 case Common::DE_DEU:
559 drawPanelObjectDescriptionString("(AUSGEBRANNT)");
560 break;
561 case Common::FR_FRA:
562 drawPanelObjectDescriptionString("(CONSUME)");
563 break;
564 }
565 }
566 break;
567 }
568 case kDMThingTypeArmour: {
569 potentialAttribMask = kDMDescriptionMaskCursed | kDMDescriptionMaskBroken;
570 Armour *armour = (Armour *)rawThingPtr;
571 actualAttribMask = (armour->getCursed() << 3) | (armour->getBroken() << 2);
572 break;
573 }
574 case kDMThingTypePotion: {
575 potentialAttribMask = kDMDescriptionMaskConsumable;
576 Potion *potion = (Potion *)rawThingPtr;
577 actualAttribMask = dungeon._objectInfos[kDMObjectInfoIndexFirstPotion + potion->getType()].getAllowedSlots();
578 break;
579 }
580 case kDMThingTypeJunk: {
581 if ((iconIndex >= kDMIconIndiceJunkWater) && (iconIndex <= kDMIconIndiceJunkWaterSkin)) {
582 potentialAttribMask = 0;
583 const char *descStringEN[4] = {"(EMPTY)", "(ALMOST EMPTY)", "(ALMOST FULL)", "(FULL)"};
584 const char *descStringDE[4] = {"(LEER)", "(FAST LEER)", "(FAST VOLL)", "(VOLL)"};
585 const char *descStringFR[4] = {"(VIDE)", "(PRESQUE VIDE)", "(PRESQUE PLEINE)", "(PLEINE)"};
586
587 Junk *junk = (Junk *)rawThingPtr;
588 switch (_vm->getGameLanguage()) { // localized
589 case Common::DE_DEU:
590 descString = descStringDE[junk->getChargeCount()];
591 break;
592 case Common::FR_FRA:
593 descString = descStringFR[junk->getChargeCount()];
594 break;
595 default:
596 descString = descStringEN[junk->getChargeCount()];
597 break;
598 }
599
600 drawPanelObjectDescriptionString(descString.c_str());
601 } else if ((iconIndex >= kDMIconIndiceJunkCompassNorth) && (iconIndex <= kDMIconIndiceJunkCompassWest)) {
602 const static char *directionNameEN[4] = {"NORTH", "EAST", "SOUTH", "WEST"};
603 const static char *directionNameDE[4] = {"NORDEN", "OSTEN", "SUEDEN", "WESTEN"};
604 const static char *directionNameFR[4] = {"AU NORD", "A L'EST", "AU SUD", "A L'OUEST"};
605
606 potentialAttribMask = 0;
607
608 switch (_vm->getGameLanguage()) { // localized
609 case Common::DE_DEU:
610 str = "GRUPPE BLICKT NACH ";
611 str += directionNameDE[iconIndex];
612 break;
613 case Common::FR_FRA:
614 str = "GROUPE FACE ";
615 str += directionNameFR[iconIndex];
616 break;
617 default:
618 str = "PARTY FACING ";
619 str += directionNameEN[iconIndex];
620 break;
621 }
622
623 drawPanelObjectDescriptionString(str.c_str());
624 } else {
625 Junk *junk = (Junk *)rawThingPtr;
626 potentialAttribMask = kDMDescriptionMaskConsumable;
627 actualAttribMask = dungeon._objectInfos[kDMObjectInfoIndexFirstJunk + junk->getType()].getAllowedSlots();
628 }
629 break;
630 }
631 default:
632 break;
633 } // end of switch
634
635 if (potentialAttribMask) {
636 static const char *attribStringEN[4] = {"CONSUMABLE", "POISONED", "BROKEN", "CURSED"};
637 static const char *attribStringDE[4] = {"ESSBAR", "VERGIFTET", "DEFEKT", "VERFLUCHT"};
638 static const char *attribStringFR[4] = {"COMESTIBLE", "EMPOISONNE", "BRISE", "MAUDIT"};
639 const char **attribString = nullptr;
640
641 switch (_vm->getGameLanguage()) { // localized
642 case Common::DE_DEU:
643 attribString = attribStringDE;
644 break;
645 case Common::FR_FRA:
646 attribString = attribStringFR;
647 break;
648 default:
649 attribString = attribStringEN;
650 break;
651 }
652
653 char destString[40];
654 buildObjectAttributeString(potentialAttribMask, actualAttribMask, attribString, destString, "(", ")");
655 drawPanelObjectDescriptionString(destString);
656 }
657
658 uint16 weight = dungeon.getObjectWeight(thingToDraw);
659 switch (_vm->getGameLanguage()) { // localized
660 case Common::DE_DEU:
661 str = "WIEGT " + champMan.getStringFromInteger(weight / 10, false, 3) + ",";
662 break;
663 case Common::FR_FRA:
664 str = "PESE " + champMan.getStringFromInteger(weight / 10, false, 3) + "KG,";
665 break;
666 default:
667 str = "WEIGHS " + champMan.getStringFromInteger(weight / 10, false, 3) + ".";
668 break;
669 }
670
671 weight -= (weight / 10) * 10;
672 str += champMan.getStringFromInteger(weight, false, 1);
673
674 switch (_vm->getGameLanguage()) { // localized
675 case Common::FR_FRA:
676 str += ".";
677 break;
678 default:
679 str += " KG.";
680 break;
681 }
682
683 drawPanelObjectDescriptionString(str.c_str());
684 }
685 drawPanelArrowOrEye(pressingEye);
686 }
687
setDungeonViewPalette()688 void InventoryMan::setDungeonViewPalette() {
689 static const int16 palIndexToLightAmmount[6] = {99, 75, 50, 25, 1, 0}; // @ G0040_ai_Graphic562_PaletteIndexToLightAmount
690 DisplayMan &display = *_vm->_displayMan;
691 ChampionMan &championMan = *_vm->_championMan;
692 DungeonMan &dungeon = *_vm->_dungeonMan;
693
694 if (dungeon._currMap->_difficulty == 0) {
695 display._dungeonViewPaletteIndex = 0; /* Brightest color palette index */
696 } else {
697 /* Get torch light power from both hands of each champion in the party */
698 int16 counter = 4; /* BUG0_01 Coding error without consequence. The hands of four champions are inspected even if there are less champions in the party. No consequence as the data in unused champions is set to 0 and _vm->_objectMan->f32_getObjectType then returns -1 */
699 Champion *curChampion = championMan._champions;
700 int16 torchesLightPower[8];
701 int16 *curTorchLightPower = torchesLightPower;
702 while (counter--) {
703 uint16 slotIndex = kDMSlotActionHand + 1;
704 while (slotIndex--) {
705 Thing slotThing = curChampion->_slots[slotIndex];
706 if ((_vm->_objectMan->getObjectType(slotThing) >= kDMIconIndiceWeaponTorchUnlit) &&
707 (_vm->_objectMan->getObjectType(slotThing) <= kDMIconIndiceWeaponTorchLit)) {
708 Weapon *curWeapon = (Weapon *)dungeon.getThingData(slotThing);
709 *curTorchLightPower = curWeapon->getChargeCount();
710 } else {
711 *curTorchLightPower = 0;
712 }
713 curTorchLightPower++;
714 }
715 curChampion++;
716 }
717 /* Sort torch light power values so that the four highest values are in the first four entries in the array L1045_ai_TorchesLightPower in decreasing order. The last four entries contain the smallest values but they are not sorted */
718 curTorchLightPower = torchesLightPower;
719 int16 torchIndex = 0;
720 while (torchIndex != 4) {
721 counter = 7 - torchIndex;
722 int16 *L1041_pi_TorchLightPower = &torchesLightPower[torchIndex + 1];
723 while (counter--) {
724 if (*L1041_pi_TorchLightPower > *curTorchLightPower) {
725 int16 AL1044_ui_TorchLightPower = *L1041_pi_TorchLightPower;
726 *L1041_pi_TorchLightPower = *curTorchLightPower;
727 *curTorchLightPower = AL1044_ui_TorchLightPower;
728 }
729 L1041_pi_TorchLightPower++;
730 }
731 curTorchLightPower++;
732 torchIndex++;
733 }
734 /* Get total light amount provided by the four torches with the highest light power values and by the fifth torch in the array which may be any one of the four torches with the smallest ligh power values */
735 uint16 torchLightAmountMultiplier = 6;
736 torchIndex = 5;
737 int16 totalLightAmount = 0;
738 curTorchLightPower = torchesLightPower;
739 while (torchIndex--) {
740 if (*curTorchLightPower) {
741 totalLightAmount += (championMan._lightPowerToLightAmount[*curTorchLightPower] << torchLightAmountMultiplier) >> 6;
742 torchLightAmountMultiplier = MAX(0, torchLightAmountMultiplier - 1);
743 }
744 curTorchLightPower++;
745 }
746 totalLightAmount += championMan._party._magicalLightAmount;
747 /* Select palette corresponding to the total light amount */
748 const int16 *curLightAmount = palIndexToLightAmmount;
749 int16 paletteIndex;
750 if (totalLightAmount > 0) {
751 paletteIndex = 0; /* Brightest color palette index */
752 while (*curLightAmount++ > totalLightAmount)
753 paletteIndex++;
754 } else {
755 paletteIndex = 5; /* Darkest color palette index */
756 }
757 display._dungeonViewPaletteIndex = paletteIndex;
758 }
759
760 display._refreshDungeonViewPaleteRequested = true;
761 }
762
decreaseTorchesLightPower()763 void InventoryMan::decreaseTorchesLightPower() {
764 ChampionMan &championMan = *_vm->_championMan;
765 DungeonMan &dungeon = *_vm->_dungeonMan;
766
767 bool torchChargeCountChanged = false;
768 int16 championCount = championMan._partyChampionCount;
769 if (championMan._candidateChampionOrdinal)
770 championCount--;
771
772 Champion *curChampion = championMan._champions;
773 while (championCount--) {
774 int16 slotIndex = kDMSlotActionHand + 1;
775 while (slotIndex--) {
776 int16 iconIndex = _vm->_objectMan->getIconIndex(curChampion->_slots[slotIndex]);
777 if ((iconIndex >= kDMIconIndiceWeaponTorchUnlit) && (iconIndex <= kDMIconIndiceWeaponTorchLit)) {
778 Weapon *curWeapon = (Weapon *)dungeon.getThingData(curChampion->_slots[slotIndex]);
779 if (curWeapon->getChargeCount()) {
780 if (curWeapon->setChargeCount(curWeapon->getChargeCount() - 1) == 0) {
781 curWeapon->setDoNotDiscard(false);
782 }
783 torchChargeCountChanged = true;
784 }
785 }
786 }
787 curChampion++;
788 }
789
790 if (torchChargeCountChanged) {
791 setDungeonViewPalette();
792 championMan.drawChangedObjectIcons();
793 }
794 }
795
drawChampionSkillsAndStatistics()796 void InventoryMan::drawChampionSkillsAndStatistics() {
797 static const char *statisticNamesEN[7] = {"L", "STRENGTH", "DEXTERITY", "WISDOM", "VITALITY", "ANTI-MAGIC", "ANTI-FIRE"};
798 static const char *statisticNamesDE[7] = {"L", "STAERKE", "FLINKHEIT", "WEISHEIT", "VITALITAET", "ANTI-MAGIE", "ANTI-FEUER"};
799 static const char *statisticNamesFR[7] = {"L", "FORCE", "DEXTERITE", "SAGESSE", "VITALITE", "ANTI-MAGIE", "ANTI-FEU"};
800
801 DisplayMan &display = *_vm->_displayMan;
802 ChampionMan &championMan = *_vm->_championMan;
803 const char **statisticNames;
804
805 switch (_vm->getGameLanguage()) { // localized
806 case Common::DE_DEU:
807 statisticNames = statisticNamesDE;
808 break;
809 case Common::FR_FRA:
810 statisticNames = statisticNamesFR;
811 break;
812 default:
813 statisticNames = statisticNamesEN;
814 break;
815 }
816
817 closeChest();
818 uint16 championIndex = _vm->ordinalToIndex(_inventoryChampionOrdinal);
819 Champion *curChampion = &championMan._champions[championIndex];
820 display.blitToViewport(display.getNativeBitmapOrGraphic(kDMGraphicIdxPanelEmpty), _boxPanel, k72_byteWidth, kDMColorRed, 73);
821 int16 textPosY = 58;
822 for (uint16 idx = kDMSkillFighter; idx <= kDMSkillWizard; idx++) {
823 int16 skillLevel = MIN((uint16)16, championMan.getSkillLevel(championIndex, idx | kDMIgnoreTemporaryExperience));
824 if (skillLevel == 1)
825 continue;
826
827 Common::String displayString;
828
829 switch (_vm->getGameLanguage()) { // localized
830 case Common::FR_FRA:
831 // Fix original bug: Due to a copy&paste error, the string was concatenate then overwritten be the last part
832 displayString = Common::String::format("%s %s", championMan._baseSkillName[idx], _skillLevelNames[skillLevel - 2]);
833 break;
834 default: // English and German versions are built the same way
835 displayString = Common::String::format("%s %s", _skillLevelNames[skillLevel - 2], championMan._baseSkillName[idx]);
836 break;
837 }
838 _vm->_textMan->printToViewport(108, textPosY, kDMColorLightestGray, displayString.c_str());
839 textPosY += 7;
840 }
841 textPosY = 86;
842 for (uint16 idx = kDMStatStrength; idx <= kDMStatAntifire; idx++) {
843 _vm->_textMan->printToViewport(108, textPosY, kDMColorLightestGray, statisticNames[idx]);
844 int16 statisticCurrentValue = curChampion->_statistics[idx][kDMStatCurrent];
845 uint16 statisticMaximumValue = curChampion->_statistics[idx][kDMStatMaximum];
846 int16 statisticColor;
847 if (statisticCurrentValue < statisticMaximumValue)
848 statisticColor = kDMColorRed;
849 else if (statisticCurrentValue > statisticMaximumValue)
850 statisticColor = kDMColorLightGreen;
851 else
852 statisticColor = kDMColorLightestGray;
853
854 _vm->_textMan->printToViewport(174, textPosY, (Color)statisticColor, championMan.getStringFromInteger(statisticCurrentValue, true, 3).c_str());
855 Common::String displayString = "/" + championMan.getStringFromInteger(statisticMaximumValue, true, 3);
856 _vm->_textMan->printToViewport(192, textPosY, kDMColorLightestGray, displayString.c_str());
857 textPosY += 7;
858 }
859 }
860
drawStopPressingMouth()861 void InventoryMan::drawStopPressingMouth() {
862 drawPanel();
863 _vm->_displayMan->drawViewport(k0_viewportNotDungeonView);
864 _vm->_eventMan->_hideMousePointerRequestCount = 1;
865 _vm->_eventMan->showMouse();
866 _vm->_eventMan->showMouse();
867 _vm->_eventMan->showMouse();
868 }
869
drawStopPressingEye()870 void InventoryMan::drawStopPressingEye() {
871 drawIconToViewport(kDMIconIndiceEyeNotLooking, 12, 13);
872 drawPanel();
873 _vm->_displayMan->drawViewport(k0_viewportNotDungeonView);
874 Thing leaderHandObject = _vm->_championMan->_leaderHandObject;
875 if (leaderHandObject != _vm->_thingNone)
876 _vm->_objectMan->drawLeaderObjectName(leaderHandObject);
877
878 _vm->_eventMan->showMouse();
879 _vm->_eventMan->showMouse();
880 _vm->_eventMan->showMouse();
881 }
882
clickOnMouth()883 void InventoryMan::clickOnMouth() {
884 static int16 foodAmounts[8] = {
885 500, /* Apple */
886 600, /* Corn */
887 650, /* Bread */
888 820, /* Cheese */
889 550, /* Screamer Slice */
890 350, /* Worm round */
891 990, /* Drumstick / Shank */
892 1400 /* Dragon steak */
893 };
894
895 DisplayMan &display = *_vm->_displayMan;
896 ChampionMan &championMan = *_vm->_championMan;
897 DungeonMan &dungeon = *_vm->_dungeonMan;
898
899
900 if (championMan._leaderEmptyHanded) {
901 if (_panelContent == kDMPanelContentFoodWaterPoisoned)
902 return;
903
904 _vm->_eventMan->_ignoreMouseMovements = true;
905 _vm->_pressingMouth = true;
906 if (!_vm->_eventMan->isMouseButtonDown(kDMMouseButtonLeft)) {
907 _vm->_eventMan->_ignoreMouseMovements = false;
908 _vm->_pressingMouth = false;
909 _vm->_stopPressingMouth = false;
910 } else {
911 _vm->_eventMan->showMouse();
912 _vm->_eventMan->_hideMousePointerRequestCount = 1;
913 drawPanelFoodWaterPoisoned();
914 display.drawViewport(k0_viewportNotDungeonView);
915 }
916 return;
917 }
918
919 if (championMan._candidateChampionOrdinal)
920 return;
921
922 Thing handThing = championMan._leaderHandObject;
923 if (!getFlag(dungeon._objectInfos[dungeon.getObjectInfoIndex(handThing)]._allowedSlots, kDMMaskMouth))
924 return;
925
926 uint16 iconIndex = _vm->_objectMan->getIconIndex(handThing);
927 uint16 handThingType = handThing.getType();
928 uint16 handThingWeight = dungeon.getObjectWeight(handThing);
929 uint16 championIndex = _vm->ordinalToIndex(_inventoryChampionOrdinal);
930 Champion *curChampion = &championMan._champions[championIndex];
931 Junk *junkData = (Junk *)dungeon.getThingData(handThing);
932 bool removeObjectFromLeaderHand;
933 if ((iconIndex >= kDMIconIndiceJunkWater) && (iconIndex <= kDMIconIndiceJunkWaterSkin)) {
934 if (!(junkData->getChargeCount()))
935 return;
936
937 curChampion->_water = MIN(curChampion->_water + 800, 2048);
938 junkData->setChargeCount(junkData->getChargeCount() - 1);
939 removeObjectFromLeaderHand = false;
940 } else if (handThingType == kDMThingTypePotion)
941 removeObjectFromLeaderHand = false;
942 else {
943 junkData->setNextThing(_vm->_thingNone);
944 removeObjectFromLeaderHand = true;
945 }
946 _vm->_eventMan->showMouse();
947 if (removeObjectFromLeaderHand)
948 championMan.getObjectRemovedFromLeaderHand();
949
950 if (handThingType == kDMThingTypePotion) {
951 uint16 potionPower = ((Potion *)junkData)->getPower();
952 uint16 counter = ((511 - potionPower) / (32 + (potionPower + 1) / 8)) >> 1;
953 uint16 adjustedPotionPower = (potionPower / 25) + 8; /* Value between 8 and 18 */
954
955 switch (((Potion *)junkData)->getType()) {
956 case kDMPotionTypeRos:
957 adjustStatisticCurrentValue(curChampion, kDMStatDexterity, adjustedPotionPower);
958 break;
959 case kDMPotionTypeKu:
960 adjustStatisticCurrentValue(curChampion, kDMStatStrength, (((Potion *)junkData)->getPower() / 35) + 5); /* Value between 5 and 12 */
961 break;
962 case kDMPotionTypeDane:
963 adjustStatisticCurrentValue(curChampion, kDMStatWisdom, adjustedPotionPower);
964 break;
965 case kDMPotionTypeNeta:
966 adjustStatisticCurrentValue(curChampion, kDMStatVitality, adjustedPotionPower);
967 break;
968 case kDMPotionTypeAntivenin:
969 championMan.unpoison(championIndex);
970 break;
971 case kDMPotionTypeMon:
972 curChampion->_currStamina += MIN(curChampion->_maxStamina - curChampion->_currStamina, curChampion->_maxStamina / counter);
973 break;
974 case kDMPotionTypeYa: {
975 adjustedPotionPower += adjustedPotionPower >> 1;
976 if (curChampion->_shieldDefense > 50)
977 adjustedPotionPower >>= 2;
978
979 curChampion->_shieldDefense += adjustedPotionPower;
980 TimelineEvent newEvent;
981 newEvent._type = kDMEventTypeChampionShield;
982 newEvent._mapTime = _vm->setMapAndTime(dungeon._partyMapIndex, _vm->_gameTime + (adjustedPotionPower * adjustedPotionPower));
983 newEvent._priority = championIndex;
984 newEvent._Bu._defense = adjustedPotionPower;
985 _vm->_timeline->addEventGetEventIndex(&newEvent);
986 setFlag(curChampion->_attributes, kDMAttributeStatusBox);
987 }
988 break;
989 case kDMPotionTypeEe: {
990 uint16 mana = MIN(900, (curChampion->_currMana + adjustedPotionPower) + (adjustedPotionPower - 8));
991 if (mana > curChampion->_maxMana)
992 mana -= (mana - MAX(curChampion->_currMana, curChampion->_maxMana)) >> 1;
993
994 curChampion->_currMana = mana;
995 }
996 break;
997 case kDMPotionTypeVi: {
998 uint16 healWoundIterationCount = MAX(1, (((Potion *)junkData)->getPower() / 42));
999 curChampion->_currHealth += curChampion->_maxHealth / counter;
1000 int16 wounds = curChampion->_wounds;
1001 if (wounds) { /* If the champion is wounded */
1002 counter = 10;
1003 do {
1004 for (uint16 i = 0; i < healWoundIterationCount; i++)
1005 curChampion->_wounds &= _vm->getRandomNumber(65536);
1006
1007 healWoundIterationCount = 1;
1008 } while ((wounds == curChampion->_wounds) && --counter); /* Loop until at least one wound is healed or there are no more heal iterations */
1009 }
1010 setFlag(curChampion->_attributes, kDMAttributeLoad | kDMAttributeWounds);
1011 }
1012 break;
1013 case kDMPotionTypeWaterFlask:
1014 curChampion->_water = MIN(curChampion->_water + 1600, 2048);
1015 break;
1016 default:
1017 break;
1018 }
1019 ((Potion *)junkData)->setType(kDMPotionTypeEmptyFlask);
1020 } else if ((iconIndex >= kDMIconIndiceJunkApple) && (iconIndex < kDMIconIndiceJunkIronKey))
1021 curChampion->_food = MIN(curChampion->_food + foodAmounts[iconIndex - kDMIconIndiceJunkApple], 2048);
1022
1023 if (curChampion->_currStamina > curChampion->_maxStamina)
1024 curChampion->_currStamina = curChampion->_maxStamina;
1025
1026 if (curChampion->_currHealth > curChampion->_maxHealth)
1027 curChampion->_currHealth = curChampion->_maxHealth;
1028
1029 if (removeObjectFromLeaderHand) {
1030 for (uint16 i = 5; --i; _vm->delay(8)) { /* Animate mouth icon */
1031 _vm->_objectMan->drawIconToScreen(kDMIconIndiceMouthOpen + !(i & 0x0001), 56, 46);
1032 _vm->_eventMan->discardAllInput();
1033 if (_vm->_engineShouldQuit)
1034 return;
1035 display.updateScreen();
1036 }
1037 } else {
1038 championMan.drawChangedObjectIcons();
1039 championMan._champions[championMan._leaderIndex]._load += dungeon.getObjectWeight(handThing) - handThingWeight;
1040 setFlag(championMan._champions[championMan._leaderIndex]._attributes, kDMAttributeLoad);
1041 }
1042 _vm->_sound->requestPlay(kDMSoundIndexSwallow, dungeon._partyMapX, dungeon._partyMapY, kDMSoundModePlayImmediately);
1043 setFlag(curChampion->_attributes, kDMAttributeStatistics);
1044
1045 if (_panelContent == kDMPanelContentFoodWaterPoisoned)
1046 setFlag(curChampion->_attributes, kDMAttributePanel);
1047
1048 championMan.drawChampionState((ChampionIndex)championIndex);
1049 _vm->_eventMan->hideMouse();
1050 }
1051
adjustStatisticCurrentValue(Champion * champ,uint16 statIndex,int16 valueDelta)1052 void InventoryMan::adjustStatisticCurrentValue(Champion *champ, uint16 statIndex, int16 valueDelta) {
1053 int16 delta;
1054 if (valueDelta >= 0) {
1055 int16 currentValue = champ->_statistics[statIndex][kDMStatCurrent];
1056 if (currentValue > 120) {
1057 valueDelta >>= 1;
1058 if (currentValue > 150) {
1059 valueDelta >>= 1;
1060 }
1061 valueDelta++;
1062 }
1063 delta = MIN(valueDelta, (int16)(170 - currentValue));
1064 } else { /* BUG0_00 Useless code. The function is always called with valueDelta having a positive value */
1065 delta = MAX(valueDelta, int16(champ->_statistics[statIndex][kDMStatMinimum] - champ->_statistics[statIndex][kDMStatCurrent]));
1066 }
1067 champ->_statistics[statIndex][kDMStatCurrent] += delta;
1068 }
1069
clickOnEye()1070 void InventoryMan::clickOnEye() {
1071 ChampionMan &championMan = *_vm->_championMan;
1072
1073 _vm->_eventMan->_ignoreMouseMovements = true;
1074 _vm->_pressingEye = true;
1075 if (!_vm->_eventMan->isMouseButtonDown(kDMMouseButtonLeft)) {
1076 _vm->_eventMan->_ignoreMouseMovements = false;
1077 _vm->_pressingEye = false;
1078 _vm->_stopPressingEye = false;
1079 return;
1080 }
1081 _vm->_eventMan->discardAllInput();
1082 _vm->_eventMan->hideMouse();
1083 _vm->_eventMan->hideMouse();
1084 _vm->_eventMan->hideMouse();
1085 _vm->delay(8);
1086 drawIconToViewport(kDMIconIndiceEyeLooking, 12, 13);
1087 if (championMan._leaderEmptyHanded)
1088 drawChampionSkillsAndStatistics();
1089 else {
1090 _vm->_objectMan->clearLeaderObjectName();
1091 drawPanelObject(championMan._leaderHandObject, true);
1092 }
1093 _vm->_displayMan->drawViewport(k0_viewportNotDungeonView);
1094 }
1095
1096 }
1097