aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBendegúz Nagy2016-08-26 22:51:17 +0200
committerBendegúz Nagy2016-08-26 23:02:22 +0200
commit50f3cfa625e338276e8a4d38836227877ab93e3a (patch)
tree1b19f1bf9c5ae2fdff42a3e9dca14ce6849241dd
parent36395c5b268e80d01ceda2924a69c0e0d293f220 (diff)
downloadscummvm-rg350-50f3cfa625e338276e8a4d38836227877ab93e3a.tar.gz
scummvm-rg350-50f3cfa625e338276e8a4d38836227877ab93e3a.tar.bz2
scummvm-rg350-50f3cfa625e338276e8a4d38836227877ab93e3a.zip
DM: Add debug command godmode
-rw-r--r--engines/dm/champion.cpp5009
-rw-r--r--engines/dm/champion.h1
-rw-r--r--engines/dm/console.cpp42
-rw-r--r--engines/dm/console.h5
-rw-r--r--engines/dm/dm.cpp13
5 files changed, 2567 insertions, 2503 deletions
diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp
index cd59e2e049..fc24288804 100644
--- a/engines/dm/champion.cpp
+++ b/engines/dm/champion.cpp
@@ -1,2501 +1,2508 @@
-/* ScummVM - Graphic Adventure Engine
-*
-* ScummVM is the legal property of its developers, whose names
-* are too numerous to list here. Please refer to the COPYRIGHT
-* file distributed with this source distribution.
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*
-*/
-
-/*
-* Based on the Reverse Engineering work of Christophe Fontanel,
-* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
-*/
-
-#include "champion.h"
-#include "dungeonman.h"
-#include "eventman.h"
-#include "menus.h"
-#include "inventory.h"
-#include "objectman.h"
-#include "text.h"
-#include "timeline.h"
-#include "projexpl.h"
-#include "group.h"
-#include "movesens.h"
-
-
-namespace DM {
-
-const char *g417_baseSkillName[4] = {"FIGHTER", "NINJA", "PRIEST", "WIZARD"};
-
-Box gBoxMouth = Box(55, 72, 12, 29); // @ G0048_s_Graphic562_Box_Mouth
-Box gBoxEye = Box(11, 28, 12, 29); // @ G0049_s_Graphic562_Box_Eye
-Box g54_BoxChampionIcons[4] = {
- Box(281, 299, 0, 13),
- Box(301, 319, 0, 13),
- Box(301, 319, 15, 28),
- Box(281, 299, 15, 28)};
-Color g46_ChampionColor[4] = {(Color)7, (Color)11, (Color)8, (Color)14};
-
-int16 g39_LightPowerToLightAmount[16] = {0, 5, 12, 24, 33, 40, 46, 51, 59, 68, 76, 82, 89, 94, 97, 100};
-
-uint16 gSlotMasks[38] = { // @ G0038_ai_Graphic562_SlotMasks
- /* 30 for champion inventory, 8 for chest */
- 0xFFFF, /* Ready Hand Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Action Hand Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0x0002, /* Head Head */
- 0x0008, /* Torso Torso */
- 0x0010, /* Legs Legs */
- 0x0020, /* Feet Feet */
- 0x0100, /* Pouch 2 Pouch */
- 0x0080, /* Quiver Line2 1 Quiver 2 */
- 0x0080, /* Quiver Line1 2 Quiver 2 */
- 0x0080, /* Quiver Line2 2 Quiver 2 */
- 0x0004, /* Neck Neck */
- 0x0100, /* Pouch 1 Pouch */
- 0x0040, /* Quiver Line1 1 Quiver 1 */
- 0xFFFF, /* Backpack Line1 1 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 2 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 3 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 4 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 5 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 6 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 7 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 8 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line2 9 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 2 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 3 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 4 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 5 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 6 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 7 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 8 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0xFFFF, /* Backpack Line1 9 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
- 0x0400, /* Chest 1 Chest */
- 0x0400, /* Chest 2 Chest */
- 0x0400, /* Chest 3 Chest */
- 0x0400, /* Chest 4 Chest */
- 0x0400, /* Chest 5 Chest */
- 0x0400, /* Chest 6 Chest */
- 0x0400, /* Chest 7 Chest */
- 0x0400}; /* Chest 8 Chest */
-
-Box gBoxChampionPortrait = Box(0, 31, 0, 28); // @ G0047_s_Graphic562_Box_ChampionPortrait
-
-ChampionMan::ChampionMan(DMEngine *vm) : _vm(vm) {
- for (uint16 i = 0; i < 4; ++i) {
- _g409_championPendingDamage[i] = 0;
- _g410_championPendingWounds[i] = 0;
- _gK71_champions[i].resetToZero();
- }
- _g305_partyChampionCount = 0;
- _g303_partyDead = false;
- _g414_leaderHandObject = Thing(0);
- _g411_leaderIndex = kM1_ChampionNone;
- _g299_candidateChampionOrdinal = 0;
- _g300_partyIsSleeping = false;
- _g506_actingChampionOrdinal = 0;
- _g413_leaderHandObjectIconIndex = (IconIndice)0;
- _g415_leaderEmptyHanded = false;
- _g407_party.resetToZero();
- _g514_magicCasterChampionIndex = kM1_ChampionNone;
- _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = false;
-}
-
-bool ChampionMan::f329_isLeaderHandObjectThrown(int16 side) {
- if (_g411_leaderIndex == kM1_ChampionNone) {
- return false;
- }
- return f328_isObjectThrown(_g411_leaderIndex, kM1_ChampionSlotLeaderHand, side);
-}
-
-bool ChampionMan::f328_isObjectThrown(uint16 champIndex, int16 slotIndex, int16 side) {
- bool throwingLeaderHandObjectFl = false;
- Thing curThing;
- Champion *curChampion = nullptr;
- Thing actionHandThing;
-
- if (slotIndex < 0) { /* Throw object in leader hand, which is temporarily placed in action hand */
- if (_g415_leaderEmptyHanded)
- return false;
-
- curThing = f298_getObjectRemovedFromLeaderHand();
- curChampion = &_gK71_champions[champIndex];
- actionHandThing = curChampion->getSlot(k1_ChampionSlotActionHand);
- curChampion->setSlot(k1_ChampionSlotActionHand, curThing);
- slotIndex = k1_ChampionSlotActionHand;
- throwingLeaderHandObjectFl = true;
- }
-
- int16 kineticEnergy = f312_getStrength(champIndex, slotIndex);
- if (throwingLeaderHandObjectFl) {
- // In this case, curChampion and actionHandThing are set.
- curChampion->setSlot((ChampionSlot)slotIndex, actionHandThing);
- } else {
- curThing = f300_getObjectRemovedFromSlot(champIndex, slotIndex);
- if (curThing == Thing::_none)
- return false;
- }
-
- _vm->f064_SOUND_RequestPlay_CPSD(k16_soundCOMBAT_ATTACK_SKELETON_ANIMATED_ARMOUR_DETH_KNIGHT, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, k1_soundModePlayIfPrioritized);
- f325_decrementStamina(champIndex, f305_getThrowingStaminaCost(curThing));
- f330_disableAction(champIndex, 4);
- int16 experience = 8;
- int16 weaponKineticEnergy = 1;
- if (curThing.getType() == k5_WeaponThingType) {
- experience += 4;
- WeaponInfo *curWeapon = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
- if (curWeapon->_class <= k12_WeaponClassPoisinDart) {
- weaponKineticEnergy = curWeapon->_kineticEnergy;
- experience += weaponKineticEnergy >> 2;
- }
- }
- f304_addSkillExperience(champIndex, k10_ChampionSkillThrow, experience);
- kineticEnergy += weaponKineticEnergy;
- int16 skillLevel = f303_getSkillLevel((ChampionIndex)champIndex, k10_ChampionSkillThrow);
- kineticEnergy += _vm->getRandomNumber(16) + (kineticEnergy >> 1) + skillLevel;
- int16 attack = f26_getBoundedValue((uint16)40, (uint16)((skillLevel << 3) + _vm->getRandomNumber(32)), (uint16)200);
- int16 stepEnergy = MAX(5, 11 - skillLevel);
- _vm->_projexpl->f212_projectileCreate(curThing, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY,
- M21_normalizeModulo4(_vm->_dungeonMan->_g308_partyDir + side),
- _vm->_dungeonMan->_g308_partyDir, kineticEnergy, attack, stepEnergy);
- _vm->_g311_projectileDisableMovementTicks = 4;
- _vm->_g312_lastProjectileDisabledMovementDirection = _vm->_dungeonMan->_g308_partyDir;
- f292_drawChampionState((ChampionIndex)champIndex);
- return true;
-}
-
-uint16 ChampionMan::M27_getChampionPortraitX(uint16 index) {
- return ((index) & 0x7) << 5;
-}
-
-uint16 ChampionMan::M28_getChampionPortraitY(uint16 index) {
- return ((index) >> 3) * 29;
-}
-
-int16 ChampionMan::f279_getDecodedValue(char *string, uint16 characterCount) {
- int val = 0;
- for (uint16 i = 0; i < characterCount; ++i) {
- val = (val << 4) + (string[i] - 'A');
- }
- return val;
-}
-
-void ChampionMan::f289_drawHealthOrStaminaOrManaValue(int16 posY, int16 currVal, int16 maxVal) {
- Common::String tmp = f288_getStringFromInteger(currVal, true, 3);
- _vm->_textMan->f52_printToViewport(55, posY, k13_ColorLightestGray, tmp.c_str());
- _vm->_textMan->f52_printToViewport(73, posY, k13_ColorLightestGray, "/");
- tmp = f288_getStringFromInteger(maxVal, true, 3);
- _vm->_textMan->f52_printToViewport(79, posY, k13_ColorLightestGray, tmp.c_str());
-}
-
-uint16 ChampionMan::M70_handSlotIndex(uint16 slotBoxIndex) {
- return slotBoxIndex & 0x1;
-}
-
-Common::String ChampionMan::f288_getStringFromInteger(uint16 val, bool padding, uint16 paddingCharCount) {
- Common::String valToStr = Common::String::format("%d", val);
- Common::String result;
-
- if (padding) {
- for (int16 i = 0, end = paddingCharCount - valToStr.size(); i < end; ++i)
- result += ' ';
- }
-
- return result += valToStr;
-}
-
-void ChampionMan::f299_applyModifiersToStatistics(Champion *champ, int16 slotIndex, int16 iconIndex, int16 modifierFactor, Thing thing) {
- int16 statIndex = k0_ChampionStatLuck;
- int16 modifier = 0;
- ThingType thingType = thing.getType();
-
- bool cursed = false;
- if (((thingType == k5_WeaponThingType) || (thingType == k6_ArmourThingType))
- && (slotIndex >= k0_ChampionSlotReadyHand) && (slotIndex <= k12_ChampionSlotQuiverLine_1_1)) {
- if (thingType == k5_WeaponThingType) {
- Weapon *weapon = (Weapon *)_vm->_dungeonMan->f156_getThingData(thing);
- cursed = weapon->getCursed();
- } else {
- // k6_ArmourThingType
- Armour *armour = (Armour *)_vm->_dungeonMan->f156_getThingData(thing);
- cursed = armour->getCursed();
- }
-
- if (cursed) {
- statIndex = k0_ChampionStatLuck;
- modifier = -3;
- }
- }
-
- if (!cursed) {
- statIndex = (ChampionStatisticType)thingType; // variable sharing
-
- if ((iconIndex == k137_IconIndiceJunkRabbitsFoot) && (slotIndex < k30_ChampionSlotChest_1)) {
- statIndex = k0_ChampionStatLuck;
- modifier = 10;
- } else if (slotIndex == k1_ChampionSlotActionHand) {
- if (iconIndex == k45_IconIndiceWeaponMaceOfOrder) {
- statIndex = k1_ChampionStatStrength;
- modifier = 5;
- } else {
- statIndex = k8_ChampionStatMana;
- if ((iconIndex >= k20_IconIndiceWeaponStaffOfClawsEmpty) && (iconIndex <= k22_IconIndiceWeaponStaffOfClawsFull)) {
- modifier = 4;
- } else {
- switch (iconIndex) {
- case k38_IconIndiceWeaponDeltaSideSplitter:
- modifier = 1;
- break;
- case k41_IconIndiceWeaponTheInquisitorDragonFang:
- modifier = 2;
- break;
- case k40_IconIndiceWeaponVorpalBlade:
- modifier = 4;
- break;
- case k58_IconIndiceWeaponStaff:
- modifier = 2;
- break;
- case k59_IconIndiceWeaponWand:
- modifier = 1;
- break;
- case k60_IconIndiceWeaponTeowand:
- modifier = 6;
- break;
- case k61_IconIndiceWeaponYewStaff:
- modifier = 4;
- break;
- case k62_IconIndiceWeaponStaffOfManarStaffOfIrra:
- modifier = 10;
- break;
- case k63_IconIndiceWeaponSnakeStaffCrossOfNeta:
- modifier = 8;
- break;
- case k64_IconIndiceWeaponTheConduitSerpentStaff:
- modifier = 16;
- break;
- case k65_IconIndiceWeaponDragonSpit:
- modifier = 7;
- break;
- case k66_IconIndiceWeaponSceptreOfLyf:
- modifier = 5;
- break;
- default:
- break;
- }
- }
- }
- } else if (slotIndex == k4_ChampionSlotLegs) {
- if (iconIndex == k142_IconIndiceArmourPowertowers) {
- statIndex = k1_ChampionStatStrength;
- modifier = 10;
- }
- } else if (slotIndex == k2_ChampionSlotHead) {
- switch (iconIndex) {
- case k104_IconIndiceArmourCrownOfNerra:
- statIndex = k3_ChampionStatWisdom;
- modifier = 10;
- break;
- case k140_IconIndiceArmourDexhelm:
- statIndex = k2_ChampionStatDexterity;
- modifier = 10;
- break;
- default:
- break;
- }
- } else if (slotIndex == k3_ChampionSlotTorso) {
- switch (iconIndex) {
- case k141_IconIndiceArmourFlamebain:
- statIndex = k6_ChampionStatAntifire;
- modifier = 12;
- break;
- case k81_IconIndiceArmourCloakOfNight:
- statIndex = k2_ChampionStatDexterity;
- modifier = 8;
- break;
- default:
- break;
- }
- } else if (slotIndex == k10_ChampionSlotNeck) {
- switch (iconIndex) {
- case k10_IconIndiceJunkJewelSymalUnequipped:
- case k11_IconIndiceJunkJewelSymalEquipped:
- statIndex = k5_ChampionStatAntimagic;
- modifier = 15;
- break;
- case k81_IconIndiceArmourCloakOfNight:
- statIndex = k2_ChampionStatDexterity;
- modifier = 8;
- break;
- case k122_IconIndiceJunkMoonstone:
- statIndex = k8_ChampionStatMana;
- modifier = 3;
- break;
- default:
- break;
- }
- }
- }
-
- if (modifier) {
- modifier *= modifierFactor;
- //statIndex is set when modifier is set
- if (statIndex == k8_ChampionStatMana) {
- champ->_maxMana += modifier;
- } else if (statIndex < k6_ChampionStatAntifire + 1) {
- for (uint16 statValIndex = k0_ChampionStatMaximum; statValIndex <= k2_ChampionStatMinimum; ++statValIndex) {
- champ->getStatistic((ChampionStatisticType)statIndex, (ChampionStatisticValue)statValIndex) += modifier;
- }
- }
- }
-}
-
-bool ChampionMan::f295_hasObjectIconInSlotBoxChanged(int16 slotBoxIndex, Thing thing) {
- ObjectMan &objMan = *_vm->_objectMan;
-
- IconIndice currIconIndex = objMan.f39_getIconIndexInSlotBox(slotBoxIndex);
- if (((currIconIndex < k32_IconIndiceWeaponDagger) && (currIconIndex >= k0_IconIndiceJunkCompassNorth))
- || ((currIconIndex >= k148_IconIndicePotionMaPotionMonPotion) && (currIconIndex <= k163_IconIndicePotionWaterFlask))
- || (currIconIndex == k195_IconIndicePotionEmptyFlask)) {
- IconIndice newIconIndex = objMan.f33_getIconIndex(thing);
- if (newIconIndex != currIconIndex) {
- if ((slotBoxIndex < k8_SlotBoxInventoryFirstSlot) && !_g420_mousePointerHiddenToDrawChangedObjIconOnScreen) {
- _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = true;
- _vm->_eventMan->f77_hideMouse();
- }
- objMan.f38_drawIconInSlotBox(slotBoxIndex, newIconIndex);
- return true;
- }
- }
-
- return false;
-}
-
-void ChampionMan::f296_drawChangedObjectIcons() {
- InventoryMan &invMan = *_vm->_inventoryMan;
- ObjectMan &objMan = *_vm->_objectMan;
- MenuMan &menuMan = *_vm->_menuMan;
-
- uint16 invChampOrdinal = invMan._g432_inventoryChampionOrdinal;
- if (_g299_candidateChampionOrdinal && !invChampOrdinal)
- return;
-
- _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = false;
- IconIndice leaderHandObjIconIndex = _g413_leaderHandObjectIconIndex;
-
- if (((leaderHandObjIconIndex < k32_IconIndiceWeaponDagger) && (leaderHandObjIconIndex >= k0_IconIndiceJunkCompassNorth)) // < instead of <= is correct
- || ((leaderHandObjIconIndex >= k148_IconIndicePotionMaPotionMonPotion) && (leaderHandObjIconIndex <= k163_IconIndicePotionWaterFlask))
- || (leaderHandObjIconIndex == k195_IconIndicePotionEmptyFlask)) {
- IconIndice iconIndex = objMan.f33_getIconIndex(_g414_leaderHandObject);
- if (iconIndex != leaderHandObjIconIndex) {
- _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = true;
- _vm->_eventMan->f77_hideMouse();
- objMan.f36_extractIconFromBitmap(iconIndex, objMan._g412_objectIconForMousePointer);
- _vm->_eventMan->f68_setPointerToObject(_vm->_objectMan->_g412_objectIconForMousePointer);
- _g413_leaderHandObjectIconIndex = iconIndex;
- objMan.f34_drawLeaderObjectName(_g414_leaderHandObject);
- }
- }
-
- for (uint16 slotBoxIndex = 0; slotBoxIndex < (_g305_partyChampionCount * 2); ++slotBoxIndex) {
- int16 champIndex = slotBoxIndex >> 1;
- if (invChampOrdinal == _vm->M0_indexToOrdinal(champIndex))
- continue;
-
- if (f295_hasObjectIconInSlotBoxChanged(slotBoxIndex, _gK71_champions[champIndex].getSlot((ChampionSlot)M70_handSlotIndex(slotBoxIndex)))
- && (M70_handSlotIndex(slotBoxIndex) == k1_ChampionSlotActionHand)) {
-
- menuMan.f386_drawActionIcon((ChampionIndex)champIndex);
- }
- }
-
- if (invChampOrdinal) {
- Champion *champ = &_gK71_champions[_vm->M1_ordinalToIndex(invChampOrdinal)];
- Thing *thing = &champ->getSlot(k0_ChampionSlotReadyHand);
- uint16 drawViewport = 0;
-
- for (uint16 slotIndex = k0_ChampionSlotReadyHand; slotIndex < k30_ChampionSlotChest_1; slotIndex++, thing++) {
- uint16 objIconChanged = f295_hasObjectIconInSlotBoxChanged(slotIndex + k8_SlotBoxInventoryFirstSlot, *thing) ? 1 : 0;
- drawViewport |= objIconChanged;
- if (objIconChanged && (slotIndex == k1_ChampionSlotActionHand)) {
- menuMan.f386_drawActionIcon((ChampionIndex)_vm->M1_ordinalToIndex(invChampOrdinal));
- }
- }
-
- if (invMan._g424_panelContent = k4_PanelContentChest) {
- thing = invMan._g425_chestSlots;
- for (int16 slotIndex = 0; slotIndex < 8; ++slotIndex, thing++) {
- drawViewport |= (f295_hasObjectIconInSlotBoxChanged(slotIndex + k38_SlotBoxChestFirstSlot, *thing) ? 1 : 0);
- }
- }
-
- if (drawViewport) {
- champ->setAttributeFlag(k0x4000_ChampionAttributeViewport, true);
- f292_drawChampionState((ChampionIndex)_vm->M1_ordinalToIndex(invChampOrdinal));
- }
- }
-
- if (_g420_mousePointerHiddenToDrawChangedObjIconOnScreen)
- _vm->_eventMan->f78_showMouse();
-}
-
-void ChampionMan::f301_addObjectInSlot(ChampionIndex champIndex, Thing thing, ChampionSlot slotIndex) {
- InventoryMan &invMan = *_vm->_inventoryMan;
- DungeonMan &dunMan = *_vm->_dungeonMan;
- ObjectMan &objMan = *_vm->_objectMan;
- MenuMan &menuMan = *_vm->_menuMan;
-
- if (thing == Thing::_none)
- return;
-
- Champion *champ = &_gK71_champions[champIndex];
-
- if (slotIndex >= k30_ChampionSlotChest_1) {
- invMan._g425_chestSlots[slotIndex - k30_ChampionSlotChest_1] = thing;
- } else {
- champ->setSlot(slotIndex, thing);
- }
-
- champ->_load += dunMan.f140_getObjectWeight(thing);
- champ->setAttributeFlag(k0x0200_ChampionAttributeLoad, true);
- IconIndice iconIndex = objMan.f33_getIconIndex(thing);
- bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == invMan._g432_inventoryChampionOrdinal);
- f299_applyModifiersToStatistics(champ, slotIndex, iconIndex, 1, thing);
- uint16 *rawObjPtr = dunMan.f156_getThingData(thing);
-
- if (slotIndex < k2_ChampionSlotHead) {
- if (slotIndex == k1_ChampionSlotActionHand) {
- champ->setAttributeFlag(k0x8000_ChampionAttributeActionHand, true);
- if (_g506_actingChampionOrdinal == _vm->M0_indexToOrdinal(champIndex))
- menuMan.f388_clearActingChampion();
-
- if ((iconIndex >= k30_IconIndiceScrollOpen) && (iconIndex <= k31_IconIndiceScrollClosed)) {
- ((Scroll *)rawObjPtr)->setClosed(false);
- f296_drawChangedObjectIcons();
- }
- }
-
- if (iconIndex = k4_IconIndiceWeaponTorchUnlit) {
- ((Weapon *)rawObjPtr)->setLit(true);
- _vm->_inventoryMan->f337_setDungeonViewPalette();
- f296_drawChangedObjectIcons();
- } else if (isInventoryChampion && (slotIndex == k1_ChampionSlotActionHand) &&
- ((iconIndex == k144_IconIndiceContainerChestClosed) || ((iconIndex >= k30_IconIndiceScrollOpen) && (iconIndex <= k31_IconIndiceScrollClosed)))) {
- champ->setAttributeFlag(k0x0800_ChampionAttributePanel, true);
- }
- } else if (slotIndex == k10_ChampionSlotNeck) {
- if ((iconIndex >= k12_IconIndiceJunkIllumuletUnequipped) && (iconIndex <= k13_IconIndiceJunkIllumuletEquipped)) {
- ((Junk *)rawObjPtr)->setChargeCount(1);
- _g407_party._magicalLightAmount += g39_LightPowerToLightAmount[2];
- _vm->_inventoryMan->f337_setDungeonViewPalette();
- iconIndex = (IconIndice)(iconIndex + 1);
- } else if ((iconIndex >= k10_IconIndiceJunkJewelSymalUnequipped) && (iconIndex <= k11_IconIndiceJunkJewelSymalEquipped)) {
- ((Junk *)rawObjPtr)->setChargeCount(1);
- iconIndex = (IconIndice)(iconIndex + 1);
- }
- }
-
- f291_drawSlot(champIndex, slotIndex);
- if (isInventoryChampion)
- champ->setAttributeFlag(k0x4000_ChampionAttributeViewport, true);
-}
-
-int16 ChampionMan::f315_getScentOrdinal(int16 mapX, int16 mapY) {
- int16 scentIndex = _g407_party._scentCount;
-
- if (scentIndex) {
- Scent searchedScent;
- searchedScent.setMapX(mapX);
- searchedScent.setMapY(mapY);
- searchedScent.setMapIndex(_vm->_dungeonMan->_g272_currMapIndex);
- uint16 searchedScentRedEagle = searchedScent.toUint16();
- Scent *scent = &_g407_party._scents[scentIndex--];
- do {
- if ((*(--scent)).toUint16() == searchedScentRedEagle) {
- return _vm->M0_indexToOrdinal(scentIndex);
- }
- } while (scentIndex--);
- }
- return 0;
-}
-
-Thing ChampionMan::f298_getObjectRemovedFromLeaderHand() {
- _g415_leaderEmptyHanded = true;
- Thing leaderHandObject = _g414_leaderHandObject;
-
- if (leaderHandObject != Thing::_none) {
- _g414_leaderHandObject = Thing::_none;
- _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
- _vm->_eventMan->f78_showMouse();
- _vm->_objectMan->f35_clearLeaderObjectName();
- _vm->_eventMan->f69_setMousePointer();
- _vm->_eventMan->f77_hideMouse();
- if (_g411_leaderIndex != kM1_ChampionNone) {
- _gK71_champions[_g411_leaderIndex]._load -= _vm->_dungeonMan->f140_getObjectWeight(leaderHandObject);
- setFlag(_gK71_champions[_g411_leaderIndex]._attributes, k0x0200_ChampionAttributeLoad);
- f292_drawChampionState(_g411_leaderIndex);
- }
- }
- return leaderHandObject;
-}
-
-uint16 ChampionMan::f312_getStrength(int16 champIndex, int16 slotIndex) {
- Champion *curChampion = &_gK71_champions[champIndex];
- int16 strength = _vm->getRandomNumber(16) + curChampion->_statistics[k1_ChampionStatStrength][k1_ChampionStatCurrent];
- Thing curThing = curChampion->_slots[slotIndex];
- uint16 objectWeight = _vm->_dungeonMan->f140_getObjectWeight(curThing);
- uint16 oneSixteenthMaximumLoad = f309_getMaximumLoad(curChampion) >> 4;
-
- if (objectWeight <= oneSixteenthMaximumLoad) {
- strength += objectWeight - 12;
- } else {
- int16 loadThreshold = oneSixteenthMaximumLoad + ((oneSixteenthMaximumLoad - 12) >> 1);
- if (objectWeight <= loadThreshold) {
- strength += (objectWeight - oneSixteenthMaximumLoad) >> 1;
- } else {
- strength -= (objectWeight - loadThreshold) << 1;
- }
- }
- if (curThing.getType() == k5_WeaponThingType) {
- WeaponInfo *weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
- strength += weaponInfo->_strength;
- uint16 skillLevel = 0;
- uint16 weaponClass = weaponInfo->_class;
- if ((weaponClass == k0_WeaponClassSwingWeapon) || (weaponClass == k2_WeaponClassDaggerAndAxes)) {
- skillLevel = f303_getSkillLevel(champIndex, k4_ChampionSkillSwing);
- }
- if ((weaponClass != k0_WeaponClassSwingWeapon) && (weaponClass < k16_WeaponClassFirstBow)) {
- skillLevel += f303_getSkillLevel(champIndex, k10_ChampionSkillThrow);
- }
- if ((weaponClass >= k16_WeaponClassFirstBow) && (weaponClass < k112_WeaponClassFirstMagicWeapon)) {
- skillLevel += f303_getSkillLevel(champIndex, k11_ChampionSkillShoot);
- }
- strength += skillLevel << 1;
- }
- strength = f306_getStaminaAdjustedValue(curChampion, strength);
- if (getFlag(curChampion->_wounds, (slotIndex == k0_ChampionSlotReadyHand) ? k0x0001_ChampionWoundReadHand : k0x0002_ChampionWoundActionHand)) {
- strength >>= 1;
- }
- return f26_getBoundedValue(0, strength >> 1, 100);
-}
-
-Thing ChampionMan::f300_getObjectRemovedFromSlot(uint16 champIndex, uint16 slotIndex) {
- Champion *curChampion = &_gK71_champions[champIndex];
- Thing curThing;
-
- if (slotIndex >= k30_ChampionSlotChest_1) {
- curThing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
- _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1] = Thing::_none;
- } else {
- curThing = curChampion->_slots[slotIndex];
- curChampion->_slots[slotIndex] = Thing::_none;
- }
-
- if (curThing == Thing::_none)
- return Thing::_none;
-
- bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal);
- int16 curIconIndex = _vm->_objectMan->f33_getIconIndex(curThing);
- // Remove object modifiers
- f299_applyModifiersToStatistics(curChampion, slotIndex, curIconIndex, -1, curThing);
-
- Weapon *curWeapon = (Weapon *)_vm->_dungeonMan->f156_getThingData(curThing);
- if (slotIndex == k10_ChampionSlotNeck) {
- if ((curIconIndex >= k12_IconIndiceJunkIllumuletUnequipped) && (curIconIndex <= k13_IconIndiceJunkIllumuletEquipped)) {
- ((Junk *)curWeapon)->setChargeCount(0);
- _g407_party._magicalLightAmount -= g39_LightPowerToLightAmount[2];
- _vm->_inventoryMan->f337_setDungeonViewPalette();
- } else if ((curIconIndex >= k10_IconIndiceJunkJewelSymalUnequipped) && (curIconIndex <= k11_IconIndiceJunkJewelSymalEquipped)) {
- ((Junk *)curWeapon)->setChargeCount(0);
- }
- }
-
- f291_drawSlot(champIndex, slotIndex);
- if (isInventoryChampion)
- setFlag(curChampion->_attributes, k0x4000_ChampionAttributeViewport);
-
- if (slotIndex < k2_ChampionSlotHead) {
- if (slotIndex == k1_ChampionSlotActionHand) {
- setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand);
- if (_g506_actingChampionOrdinal == _vm->M0_indexToOrdinal(champIndex))
- _vm->_menuMan->f388_clearActingChampion();
-
- if ((curIconIndex >= k30_IconIndiceScrollOpen) && (curIconIndex <= k31_IconIndiceScrollClosed)) {
- ((Scroll *)curWeapon)->setClosed(true);
- f296_drawChangedObjectIcons();
- }
- }
-
- if ((curIconIndex >= k4_IconIndiceWeaponTorchUnlit) && (curIconIndex <= k7_IconIndiceWeaponTorchLit)) {
- curWeapon->setLit(false);
- _vm->_inventoryMan->f337_setDungeonViewPalette();
- f296_drawChangedObjectIcons();
- }
-
- if (isInventoryChampion && (slotIndex == k1_ChampionSlotActionHand)) {
- switch (curIconIndex) {
- case k144_IconIndiceContainerChestClosed:
- _vm->_inventoryMan->f334_closeChest();
- // No break on purpose
- case k30_IconIndiceScrollOpen:
- case k31_IconIndiceScrollClosed:
- setFlag(curChampion->_attributes, k0x0800_ChampionAttributePanel);
- break;
- default:
- break;
- }
- }
- }
- curChampion->_load -= _vm->_dungeonMan->f140_getObjectWeight(curThing);
- setFlag(curChampion->_attributes, k0x0200_ChampionAttributeLoad);
- return curThing;
-}
-
-void ChampionMan::f325_decrementStamina(int16 championIndex, int16 decrement) {
- if (championIndex == kM1_ChampionNone)
- return;
-
- Champion *curChampion = &_gK71_champions[championIndex];
- curChampion->_currStamina -= decrement;
-
- int16 stamina = curChampion->_currStamina;
- if (stamina <= 0) {
- curChampion->_currStamina = 0;
- f321_addPendingDamageAndWounds_getDamage(championIndex, (-stamina) >> 1, k0x0000_ChampionWoundNone, k0_attackType_NORMAL);
- } else if (stamina > curChampion->_maxStamina) {
- curChampion->_currStamina = curChampion->_maxStamina;
- }
-
- setFlag(curChampion->_attributes, k0x0200_ChampionAttributeLoad | k0x0100_ChampionAttributeStatistics);
-}
-
-int16 ChampionMan::f321_addPendingDamageAndWounds_getDamage(int16 champIndex, int16 attack, int16 allowedWounds, uint16 attackType) {
- if (attack <= 0)
- return 0;
-
- Champion *curChampion = &_gK71_champions[champIndex];
- if (!curChampion->_currHealth)
- return 0;
-
- bool skipScaling = false;
- if (attackType != k0_attackType_NORMAL) {
- uint16 defense = 0;
- uint16 woundCount = 0;
- for (int16 woundIndex = k0_ChampionSlotReadyHand; woundIndex <= k5_ChampionSlotFeet; woundIndex++) {
- if (allowedWounds & (1 << woundIndex)) {
- woundCount++;
- defense += f313_getWoundDefense(champIndex, woundIndex | ((attackType == k4_attackType_SHARP) ? k0x8000_maskUseSharpDefense : k0x0000_maskDoNotUseSharpDefense));
- }
- }
- if (woundCount)
- defense /= woundCount;
-
- switch (attackType) {
- case k6_attackType_PSYCHIC:
- {
- int16 wisdomFactor = 115 - curChampion->_statistics[k3_ChampionStatWisdom][k1_ChampionStatCurrent];
- if (wisdomFactor <= 0) {
- attack = 0;
- } else {
- attack = _vm->f30_getScaledProduct(attack, 6, wisdomFactor);
- }
-
- skipScaling = true;
- }
- break;
- case k5_attackType_MAGIC:
- attack = f307_getStatisticAdjustedAttack(curChampion, k5_ChampionStatAntimagic, attack);
- attack -= _g407_party._spellShieldDefense;
- skipScaling = true;
- break;
- case k1_attackType_FIRE:
- attack = f307_getStatisticAdjustedAttack(curChampion, k6_ChampionStatAntifire, attack);
- attack -= _g407_party._fireShieldDefense;
- break;
- case k2_attackType_SELF:
- defense >>= 1;
- break;
- default:
- break;
- }
-
- if (!skipScaling) {
- if (attack <= 0)
- return 0;
-
- attack = _vm->f30_getScaledProduct(attack, 6, 130 - defense);
- }
- /* BUG0_44
- A champion may take much more damage than expected after a Black Flame attack or an impact
- with a Fireball projectile. If the party has a fire shield defense value higher than the fire
- attack value then the resulting intermediary attack value is negative and damage should be 0.
- However, the negative value is still used for further computations and the result may be a very
- high positive attack value which may kill a champion. This can occur only for k1_attackType_FIRE
- and if attack is negative before calling F0030_MAIN_GetScaledProduct
- */
-
- if (attack <= 0)
- return 0;
-
- int16 adjustedAttack = f307_getStatisticAdjustedAttack(curChampion, k4_ChampionStatVitality, _vm->getRandomNumber(128) + 10);
- if (attack > adjustedAttack) {
- /* BUG0_45
- This bug is not perceptible because of BUG0_41 that ignores Vitality while determining the
- probability of being wounded. However if it was fixed, the behavior would be the opposite
- of what it should: the higher the vitality of a champion, the lower the result of
- F0307_CHAMPION_GetStatisticAdjustedAttack and the more likely the champion could get
- wounded (because of more iterations in the loop below)
- */
- do {
- setFlag(*(uint16 *)&_g410_championPendingWounds[champIndex], (1 << _vm->getRandomNumber(8)) & allowedWounds);
- } while ((attack > (adjustedAttack <<= 1)) && adjustedAttack);
- }
-
- if (_g300_partyIsSleeping)
- f314_wakeUp();
- }
- _g409_championPendingDamage[champIndex] += attack;
- return attack;
-}
-
-int16 ChampionMan::f313_getWoundDefense(int16 champIndex, uint16 woundIndex) {
- static const byte woundDefenseFactor[6] = {5, 5, 4, 6, 3, 1}; // @ G0050_auc_Graphic562_WoundDefenseFactor
-
- Champion *curChampion = &_gK71_champions[champIndex];
- bool useSharpDefense = getFlag(woundIndex, k0x8000_maskUseSharpDefense);
- if (useSharpDefense)
- clearFlag(woundIndex, k0x8000_maskUseSharpDefense);
-
- uint16 armorShieldDefense = 0;
- for (int16 slotIndex = k0_ChampionSlotReadyHand; slotIndex <= k1_ChampionSlotActionHand; slotIndex++) {
- Thing curThing = curChampion->_slots[slotIndex];
- if (curThing.getType() == k6_ArmourThingType) {
- ArmourInfo *armorInfo = (ArmourInfo *)_vm->_dungeonMan->f156_getThingData(curThing);
- armorInfo = &g239_ArmourInfo[((Armour *)armorInfo)->getType()];
- if (getFlag(armorInfo->_attributes, k0x0080_ArmourAttributeIsAShield))
- armorShieldDefense += ((f312_getStrength(champIndex, slotIndex) + _vm->_dungeonMan->f143_getArmourDefense(armorInfo, useSharpDefense)) * woundDefenseFactor[woundIndex]) >> ((slotIndex == woundIndex) ? 4 : 5);
- }
- }
-
- int16 woundDefense = _vm->getRandomNumber((curChampion->_statistics[k4_ChampionStatVitality][k1_ChampionStatCurrent] >> 3) + 1);
- if (useSharpDefense)
- woundDefense >>= 1;
-
- woundDefense += curChampion->_actionDefense + curChampion->_shieldDefense + _g407_party._shieldDefense + armorShieldDefense;
- if (woundIndex > k1_ChampionSlotActionHand) {
- Thing curThing = curChampion->_slots[woundIndex];
- if (curThing.getType() == k6_ArmourThingType) {
- ArmourInfo *armourInfo = (ArmourInfo *)_vm->_dungeonMan->f156_getThingData(curThing);
- woundDefense += _vm->_dungeonMan->f143_getArmourDefense(&g239_ArmourInfo[((Armour *)armourInfo)->getType()], useSharpDefense);
- }
- }
-
- if (getFlag(curChampion->_wounds, 1 << woundIndex))
- woundDefense -= 8 + _vm->getRandomNumber(4);
-
- if (_g300_partyIsSleeping)
- woundDefense >>= 1;
-
- return f26_getBoundedValue(0, woundDefense >> 1, 100);
-}
-
-uint16 ChampionMan::f307_getStatisticAdjustedAttack(Champion *champ, uint16 statIndex, uint16 attack) {
- int16 factor = 170 - champ->_statistics[statIndex][k1_ChampionStatCurrent];
-
- /* BUG0_41
- The Antifire and Antimagic statistics are completely ignored. The Vitality statistic is ignored
- against poison and to determine the probability of being wounded. Vitality is still used normally
- to compute the defense against wounds and the speed of health regeneration. A bug in the Megamax C
- compiler produces wrong machine code for this statement. It always returns 0 for the current statistic
- value so that factor = 170 in all cases
- */
- if (factor < 16)
- return attack >> 3;
-
- return _vm->f30_getScaledProduct(attack, 7, factor);
-}
-
-void ChampionMan::f314_wakeUp() {
- _vm->_g321_stopWaitingForPlayerInput = true;
- _g300_partyIsSleeping = false;
- _vm->_g318_waitForInputMaxVerticalBlankCount = 10;
- _vm->f22_delay(10);
- _vm->_displayMan->f98_drawFloorAndCeiling();
- _vm->_eventMan->_g441_primaryMouseInput = g447_PrimaryMouseInput_Interface;
- _vm->_eventMan->_g442_secondaryMouseInput = g448_SecondaryMouseInput_Movement;
- _vm->_eventMan->_g443_primaryKeyboardInput = g458_primaryKeyboardInput_interface;
- _vm->_eventMan->_g444_secondaryKeyboardInput = g459_secondaryKeyboardInput_movement;
- _vm->_eventMan->f357_discardAllInput();
- _vm->_menuMan->f457_drawEnabledMenus();
-}
-
-int16 ChampionMan::f305_getThrowingStaminaCost(Thing thing) {
- int16 weight = _vm->_dungeonMan->f140_getObjectWeight(thing) >> 1;
- int16 staminaCost = f26_getBoundedValue<int16>(1, weight, 10);
-
- while ((weight -= 10) > 0)
- staminaCost += weight >> 1;
-
- return staminaCost;
-}
-
-void ChampionMan::f330_disableAction(uint16 champIndex, uint16 ticks) {
- Champion *curChampion = &_gK71_champions[champIndex];
- int32 updatedEnableActionEventTime = _vm->_g313_gameTime + ticks;
-
- TimelineEvent curEvent;
- curEvent._type = k11_TMEventTypeEnableChampionAction;
- curEvent._priority = champIndex;
- curEvent._B._slotOrdinal = 0;
-
- int16 eventIndex = curChampion->_enableActionEventIndex;
- if (eventIndex >= 0) {
- int32 currentEnableActionEventTime = M30_time(_vm->_timeline->_g370_events[eventIndex]._mapTime);
- if (updatedEnableActionEventTime >= currentEnableActionEventTime) {
- updatedEnableActionEventTime += (currentEnableActionEventTime - _vm->_g313_gameTime) >> 1;
- } else {
- updatedEnableActionEventTime = currentEnableActionEventTime + (ticks >> 1);
- }
- _vm->_timeline->f237_deleteEvent(eventIndex);
- } else {
- setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand | k0x0008_ChampionAttributeDisableAction);
- f292_drawChampionState((ChampionIndex)champIndex);
- }
- M33_setMapAndTime(curEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, updatedEnableActionEventTime);
- curChampion->_enableActionEventIndex = _vm->_timeline->f238_addEventGetEventIndex(&curEvent);
-}
-
-void ChampionMan::f304_addSkillExperience(uint16 champIndex, uint16 skillIndex, uint16 exp) {
- if ((skillIndex >= k4_ChampionSkillSwing) && (skillIndex <= k11_ChampionSkillShoot) && (_vm->_projexpl->_g361_lastCreatureAttackTime < _vm->_g313_gameTime - 150))
- exp >>= 1;
-
- if (exp) {
- if (_vm->_dungeonMan->_g269_currMap->_difficulty)
- exp *= _vm->_dungeonMan->_g269_currMap->_difficulty;
-
- Champion *curChampion = &_gK71_champions[champIndex];
- uint16 baseSkillIndex;
- if (skillIndex >= k4_ChampionSkillSwing)
- baseSkillIndex = (skillIndex - k4_ChampionSkillSwing) >> 2;
- else
- baseSkillIndex = skillIndex;
-
- uint16 skillLevelBefore = f303_getSkillLevel(champIndex, baseSkillIndex | (k0x4000_IgnoreObjectModifiers | k0x8000_IgnoreTemporaryExperience));
-
- if ((skillIndex >= k4_ChampionSkillSwing) && (_vm->_projexpl->_g361_lastCreatureAttackTime > _vm->_g313_gameTime - 25))
- exp <<= 1;
-
- Skill *curSkill = &curChampion->_skills[skillIndex];
- curSkill->_experience += exp;
- if (curSkill->_temporaryExperience < 32000)
- curSkill->_temporaryExperience += f26_getBoundedValue(1, exp >> 3, 100);
-
- curSkill = &curChampion->_skills[baseSkillIndex];
- if (skillIndex >= k4_ChampionSkillSwing)
- curSkill->_experience += exp;
-
- uint16 skillLevelAfter = f303_getSkillLevel(champIndex, baseSkillIndex | (k0x4000_IgnoreObjectModifiers | k0x8000_IgnoreTemporaryExperience));
- if (skillLevelAfter > skillLevelBefore) {
- int16 newBaseSkillLevel = skillLevelAfter;
- int16 minorStatIncrease = _vm->getRandomNumber(2);
- int16 majorStatIncrease = 1 + _vm->getRandomNumber(2);
- uint16 vitalityAmount = _vm->getRandomNumber(2); /* For Priest skill, the amount is 0 or 1 for all skill levels */
- if (baseSkillIndex != k2_ChampionSkillPriest) {
- vitalityAmount &= skillLevelAfter; /* For non Priest skills the amount is 0 for even skill levels. The amount is 0 or 1 for odd skill levels */
- }
- curChampion->_statistics[k4_ChampionStatVitality][k0_ChampionStatMaximum] += vitalityAmount;
- uint16 staminaAmount = curChampion->_maxStamina;
- curChampion->_statistics[k6_ChampionStatAntifire][k0_ChampionStatMaximum] += _vm->getRandomNumber(2) & ~skillLevelAfter; /* The amount is 0 for odd skill levels. The amount is 0 or 1 for even skill levels */
- bool increaseManaFl = false;
- switch (baseSkillIndex) {
- case k0_ChampionSkillFighter:
- staminaAmount >>= 4;
- skillLevelAfter *= 3;
- curChampion->_statistics[k1_ChampionStatStrength][k0_ChampionStatMaximum] += majorStatIncrease;
- curChampion->_statistics[k2_ChampionStatDexterity][k0_ChampionStatMaximum] += minorStatIncrease;
- break;
- case k1_ChampionSkillNinja:
- staminaAmount /= 21;
- skillLevelAfter <<= 1;
- curChampion->_statistics[k1_ChampionStatStrength][k0_ChampionStatMaximum] += minorStatIncrease;
- curChampion->_statistics[k2_ChampionStatDexterity][k0_ChampionStatMaximum] += majorStatIncrease;
- break;
- case k3_ChampionSkillWizard:
- staminaAmount >>= 5;
- curChampion->_maxMana += skillLevelAfter + (skillLevelAfter >> 1);
- curChampion->_statistics[k3_ChampionStatWisdom][k0_ChampionStatMaximum] += majorStatIncrease;
- increaseManaFl = true;
- break;
- case k2_ChampionSkillPriest:
- staminaAmount /= 25;
- curChampion->_maxMana += skillLevelAfter;
- skillLevelAfter += (skillLevelAfter + 1) >> 1;
- curChampion->_statistics[k3_ChampionStatWisdom][k0_ChampionStatMaximum] += minorStatIncrease;
- increaseManaFl = true;
- break;
- default:
- break;
- }
- if (increaseManaFl) {
- if ((curChampion->_maxMana += MIN(_vm->getRandomNumber(4), (uint16)(newBaseSkillLevel - 1))) > 900)
- curChampion->_maxMana = 900;
- curChampion->_statistics[k5_ChampionStatAntimagic][k0_ChampionStatMaximum] += _vm->getRandomNumber(3);
- }
-
- if ((curChampion->_maxHealth += skillLevelAfter + _vm->getRandomNumber((skillLevelAfter >> 1) + 1)) > 999)
- curChampion->_maxHealth = 999;
-
- if ((curChampion->_maxStamina += staminaAmount + _vm->getRandomNumber((staminaAmount >> 1) + 1)) > 9999)
- curChampion->_maxStamina = 9999;
-
- setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
- f292_drawChampionState((ChampionIndex)champIndex);
- _vm->_textMan->f51_messageAreaPrintLineFeed();
- Color curChampionColor = g46_ChampionColor[champIndex];
- _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, curChampion->_name);
- // TODO: localization
- _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, " JUST GAINED A ");
- _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, g417_baseSkillName[baseSkillIndex]);
- _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, " LEVEL!");
- }
- }
-}
-
-int16 ChampionMan::f324_damageAll_getDamagedChampionCount(uint16 attack, int16 wounds, int16 attackType) {
- int16 randomMax = (attack >> 3) + 1;
- uint16 reducedAttack = attack - randomMax;
- randomMax <<= 1;
-
- int16 damagedChampionCount = 0;
- for (int16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++) {
- // Actual attack is attack +/- (attack / 8)
- if (f321_addPendingDamageAndWounds_getDamage(championIndex, MAX(1, reducedAttack + _vm->getRandomNumber(randomMax)), wounds, attackType))
- damagedChampionCount++;
- }
-
- return damagedChampionCount;
-}
-
-int16 ChampionMan::f286_getTargetChampionIndex(int16 mapX, int16 mapY, uint16 cell) {
- if (_g305_partyChampionCount && (M38_distance(mapX, mapY, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY) <= 1)) {
- signed char orderedCellsToAttack[4];
- _vm->_groupMan->f229_setOrderedCellsToAttack(orderedCellsToAttack, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, mapX, mapY, cell);
- for (uint16 i = 0; i < 4; i++) {
- int16 championIndex = f285_getIndexInCell(orderedCellsToAttack[i]);
- if (championIndex >= 0)
- return championIndex;
- }
- }
- return kM1_ChampionNone;
-}
-
-int16 ChampionMan::f311_getDexterity(Champion* champ) {
- int16 dexterity = _vm->getRandomNumber(8) + champ->_statistics[k2_ChampionStatDexterity][k1_ChampionStatCurrent];
- dexterity -= ((int32)(dexterity >> 1) * (int32)champ->_load) / f309_getMaximumLoad(champ);
- if (_g300_partyIsSleeping)
- dexterity >>= 1;
-
- return f26_getBoundedValue(1 + _vm->getRandomNumber(8), dexterity >> 1, 100 - _vm->getRandomNumber(8));
-}
-
-bool ChampionMan::f308_isLucky(Champion* champ, uint16 percentage) {
- if (_vm->getRandomNumber(2) && (_vm->getRandomNumber(100) > percentage))
- return true;
-
- unsigned char *curStat = champ->_statistics[k0_ChampionStatLuck];
- bool isLucky = (_vm->getRandomNumber(curStat[k1_ChampionStatCurrent]) > percentage);
- curStat[k1_ChampionStatCurrent] = f26_getBoundedValue<char>(curStat[k2_ChampionStatMinimum], curStat[k1_ChampionStatCurrent] + (isLucky ? -2 : 2), curStat[k0_ChampionStatMaximum]);
- return isLucky;
-}
-
-void ChampionMan::f322_championPoison(int16 champIndex, uint16 attack) {
- if ((champIndex == kM1_ChampionNone) || (_vm->M0_indexToOrdinal(champIndex) == _g299_candidateChampionOrdinal))
- return;
-
- Champion *curChampion = &_gK71_champions[champIndex];
- f321_addPendingDamageAndWounds_getDamage(champIndex, MAX(1, attack >> 6), k0x0000_ChampionWoundNone, k0_attackType_NORMAL);
- setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
- if ((_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) && (_vm->_inventoryMan->_g424_panelContent == k0_PanelContentFoodWaterPoisoned)) {
- setFlag(curChampion->_attributes, k0x0800_ChampionAttributePanel);
- }
-
- if (--attack) {
- curChampion->_poisonEventCount++;
- TimelineEvent newEvent;
- newEvent._type = k75_TMEventTypePoisonChampion;
- newEvent._priority = champIndex;
- M33_setMapAndTime(newEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 36);
- newEvent._B._attack = attack;
- _vm->_timeline->f238_addEventGetEventIndex(&newEvent);
- }
-
- f292_drawChampionState((ChampionIndex)champIndex);
-}
-
-void ChampionMan::f284_setPartyDirection(int16 dir) {
- if (dir == _vm->_dungeonMan->_g308_partyDir)
- return;
-
- int16 L0834_i_Delta = dir - _vm->_dungeonMan->_g308_partyDir;
- if (L0834_i_Delta < 0)
- L0834_i_Delta += 4;
-
- Champion *curChampion = _gK71_champions;
- for (int16 i = k0_ChampionFirst; i < _g305_partyChampionCount; i++) {
- curChampion->_cell = (ViewCell)M21_normalizeModulo4(curChampion->_cell + L0834_i_Delta);
- curChampion->_dir = (Direction)M21_normalizeModulo4(curChampion->_dir + L0834_i_Delta);
- curChampion++;
- }
-
- _vm->_dungeonMan->_g308_partyDir = (Direction)dir;
- f296_drawChangedObjectIcons();
-}
-
-void ChampionMan::f316_deleteScent(uint16 scentIndex) {
- uint16 count = --_g407_party._scentCount - scentIndex;
-
- if (count) {
- for (uint16 i = 0; i < count; ++i) {
- _g407_party._scents[scentIndex + i] = _g407_party._scents[scentIndex + i + 1];
- _g407_party._scentStrengths[scentIndex + i] = _g407_party._scentStrengths[scentIndex + i + 1];
- }
- }
-
- if (scentIndex < _g407_party._firstScentIndex)
- _g407_party._firstScentIndex--;
-
- if (scentIndex < _g407_party._lastScentIndex)
- _g407_party._lastScentIndex--;
-}
-
-void ChampionMan::f317_addScentStrength(int16 mapX, int16 mapY, int32 cycleCount) {
- int16 scentIndex = _g407_party._scentCount;
- if (scentIndex) {
- bool mergeFl = getFlag(cycleCount, k0x8000_mergeCycles);
- if (mergeFl)
- clearFlag(cycleCount, k0x8000_mergeCycles);
-
- Scent newScent; /* BUG0_00 Useless code */
- newScent.setMapX(mapX); /* BUG0_00 Useless code */
- newScent.setMapY(mapY); /* BUG0_00 Useless code */
- newScent.setMapIndex(_vm->_dungeonMan->_g272_currMapIndex); /* BUG0_00 Useless code */
-
- Scent *curScent = _g407_party._scents; /* BUG0_00 Useless code */
- bool cycleCountDefined = false;
- while (scentIndex--) {
- if (&*curScent++ == &newScent) {
- if (!cycleCountDefined) {
- cycleCountDefined = true;
- if (mergeFl) {
- cycleCount = MAX<int32>(_g407_party._scentStrengths[scentIndex], cycleCount);
- } else {
- cycleCount = MIN<int32>(80, _g407_party._scentStrengths[scentIndex] + cycleCount);
- }
- }
- _g407_party._scentStrengths[scentIndex] = cycleCount;
- }
- }
- }
-}
-
-void ChampionMan::f297_putObjectInLeaderHand(Thing thing, bool setMousePointer) {
- if (thing == Thing::_none)
- return;
-
- _g415_leaderEmptyHanded = false;
- _vm->_objectMan->f36_extractIconFromBitmap(_g413_leaderHandObjectIconIndex = _vm->_objectMan->f33_getIconIndex(_g414_leaderHandObject = thing), _vm->_objectMan->_g412_objectIconForMousePointer);
- _vm->_eventMan->f78_showMouse();
- _vm->_objectMan->f34_drawLeaderObjectName(thing);
-
- if (setMousePointer)
- _vm->_g325_setMousePointerToObjectInMainLoop = true;
- else
- _vm->_eventMan->f68_setPointerToObject(_vm->_objectMan->_g412_objectIconForMousePointer);
-
- _vm->_eventMan->f77_hideMouse();
- if (_g411_leaderIndex != kM1_ChampionNone) {
- _gK71_champions[_g411_leaderIndex]._load += _vm->_dungeonMan->f140_getObjectWeight(thing);
- setFlag(_gK71_champions[_g411_leaderIndex]._attributes, k0x0200_ChampionAttributeLoad);
- f292_drawChampionState(_g411_leaderIndex);
- }
-}
-
-int16 ChampionMan::f310_getMovementTicks(Champion *champ) {
- uint16 maximumLoad = f309_getMaximumLoad(champ);
- uint16 curLoad = champ->_load;
- uint16 woundTicks;
- int16 ticks;
- /* BUG0_72 - Fixed
- The party moves very slowly even though no champion 'Load' value is drawn in red.
- When the Load of a champion has exactly the maximum value he can carry then the Load
- is drawn in yellow but the speed is the same as when the champion is overloaded
- (when the Load is drawn in red). The comparison operator should be >= instead of >
- */
- if (maximumLoad >= curLoad) {
- ticks = 2;
- if (((int32)curLoad << 3) > ((int32)maximumLoad * 5))
- ticks++;
-
- woundTicks = 1;
- } else {
- ticks = 4 + (((curLoad - maximumLoad) << 2) / maximumLoad);
- woundTicks = 2;
- }
-
- if (getFlag(champ->_wounds, k0x0020_ChampionWoundFeet))
- ticks += woundTicks;
-
- if (_vm->_objectMan->f33_getIconIndex(champ->_slots[k5_ChampionSlotFeet]) == k194_IconIndiceArmourBootOfSpeed)
- ticks--;
-
- return ticks;
-}
-
-bool ChampionMan::f294_isAmmunitionCompatibleWithWeapon(uint16 champIndex, uint16 weaponSlotIndex, uint16 ammunitionSlotIndex) {
- Champion *curChampion = &_gK71_champions[champIndex];
- Thing curThing = curChampion->_slots[weaponSlotIndex];
- if (curThing.getType() != k5_WeaponThingType)
- return false;
-
- WeaponInfo *weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
- int16 weaponClass = kM1_WeaponClassNone;
-
- if ((weaponInfo->_class >= k16_WeaponClassFirstBow) && (weaponInfo->_class <= k31_WeaponClassLastBow))
- weaponClass = k10_WeaponClassBowAmmunition;
- else if ((weaponInfo->_class >= k32_WeaponClassFirstSling) && (weaponInfo->_class <= k47_WeaponClassLastSling))
- weaponClass = k11_WeaponClassSlingAmmunition;
-
- if (weaponClass == kM1_WeaponClassNone)
- return false;
-
- curThing = curChampion->_slots[ammunitionSlotIndex];
- weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
- return ((curThing.getType() == k5_WeaponThingType) && (weaponInfo->_class == weaponClass));
-}
-
-void ChampionMan::f293_drawAllChampionStates() {
- for (int16 i = k0_ChampionFirst; i < _g305_partyChampionCount; i++)
- f292_drawChampionState((ChampionIndex)i);
-}
-
-void ChampionMan::f283_viAltarRebirth(uint16 champIndex) {
- Champion *curChampion = &_gK71_champions[champIndex];
- if (f285_getIndexInCell(curChampion->_cell) != kM1_ChampionNone) {
- uint16 numCell = k0_CellNorthWest;
- while (f285_getIndexInCell(numCell) != kM1_ChampionNone)
- numCell++;
-
- curChampion->_cell = (ViewCell)numCell;
- }
-
- uint16 maximumHealth = curChampion->_maxHealth;
- curChampion->_maxHealth = MAX(25, maximumHealth - (maximumHealth >> 6) - 1);
- curChampion->_currHealth = curChampion->_maxHealth >> 1;
- _vm->_menuMan->f393_drawSpellAreaControls(_g514_magicCasterChampionIndex);
- curChampion->_dir = _vm->_dungeonMan->_g308_partyDir;
- setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand | k0x1000_ChampionAttributeStatusBox | k0x0400_ChampionAttributeIcon);
- f292_drawChampionState((ChampionIndex)champIndex);
-}
-
-void ChampionMan::f302_processCommands28to65_clickOnSlotBox(uint16 slotBoxIndex) {
- uint16 champIndex;
- uint16 slotIndex;
-
- if (slotBoxIndex < k8_SlotBoxInventoryFirstSlot) {
- if (_g299_candidateChampionOrdinal)
- return;
-
- champIndex = slotBoxIndex >> 1;
- if ((champIndex >= _g305_partyChampionCount) || (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) || !_gK71_champions[champIndex]._currHealth)
- return;
-
- slotIndex = M70_handSlotIndex(slotBoxIndex);
- } else {
- champIndex = _vm->M1_ordinalToIndex(_vm->_inventoryMan->_g432_inventoryChampionOrdinal);
- slotIndex = slotBoxIndex - k8_SlotBoxInventoryFirstSlot;
- }
-
- Thing leaderHandObject = _g414_leaderHandObject;
- Thing slotThing;
- if (slotIndex >= k30_ChampionSlotChest_1) {
- slotThing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
- } else {
- slotThing = _gK71_champions[champIndex]._slots[slotIndex];
- }
-
- if ((slotThing == Thing::_none) && (leaderHandObject == Thing::_none))
- return;
-
- if ((leaderHandObject != Thing::_none) && (!(g237_ObjectInfo[_vm->_dungeonMan->f141_getObjectInfoIndex(leaderHandObject)]._allowedSlots & gSlotMasks[slotIndex])))
- return;
-
- _vm->_eventMan->f78_showMouse();
- if (leaderHandObject != Thing::_none)
- f298_getObjectRemovedFromLeaderHand();
-
- if (slotThing != Thing::_none) {
- f300_getObjectRemovedFromSlot(champIndex, slotIndex);
- f297_putObjectInLeaderHand(slotThing, false);
- }
-
- if (leaderHandObject != Thing::_none)
- f301_addObjectInSlot((ChampionIndex)champIndex, leaderHandObject, (ChampionSlot)slotIndex);
-
- f292_drawChampionState((ChampionIndex)champIndex);
- _vm->_eventMan->f77_hideMouse();
-}
-
-bool ChampionMan::f327_isProjectileSpellCast(uint16 champIndex, Thing thing, int16 kineticEnergy, uint16 requiredManaAmount) {
- Champion *curChampion = &_gK71_champions[champIndex];
- if (curChampion->_currMana < requiredManaAmount)
- return false;
-
- curChampion->_currMana -= requiredManaAmount;
- setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
- int16 stepEnergy = 10 - MIN(8, curChampion->_maxMana >> 3);
- if (kineticEnergy < (stepEnergy << 2)) {
- kineticEnergy += 3;
- stepEnergy--;
- }
-
- f326_championShootProjectile(curChampion, thing, kineticEnergy, 90, stepEnergy);
- return true; // fix BUG_01
-}
-
-void ChampionMan::f326_championShootProjectile(Champion* champ, Thing thing, int16 kineticEnergy, int16 attack, int16 stepEnergy) {
- Direction newDirection = champ->_dir;
- _vm->_projexpl->f212_projectileCreate(thing, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, M21_normalizeModulo4((((champ->_cell - newDirection + 1) & 0x0002) >> 1) + newDirection), newDirection, kineticEnergy, attack, stepEnergy);
- _vm->_g311_projectileDisableMovementTicks = 4;
- _vm->_g312_lastProjectileDisabledMovementDirection = newDirection;
-}
-
-void ChampionMan::f320_applyAndDrawPendingDamageAndWounds() {
- Champion *championPtr = _gK71_champions;
- for (uint16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++, championPtr++) {
- int16 pendingWounds = _g410_championPendingWounds[championIndex];
- setFlag(championPtr->_wounds, pendingWounds);
- _g410_championPendingWounds[championIndex] = 0;
- uint16 pendingDamage = _g409_championPendingDamage[championIndex];
- if (!pendingDamage)
- continue;
-
- _g409_championPendingDamage[championIndex] = 0;
- int16 curHealth = championPtr->_currHealth;
- if (!curHealth)
- continue;
-
- curHealth -= pendingDamage;
- if (curHealth <= 0) {
- f319_championKill(championIndex);
- } else {
- championPtr->_currHealth = curHealth;
- setFlag(championPtr->_attributes, k0x0100_ChampionAttributeStatistics);
- if (pendingWounds) {
- setFlag(championPtr->_attributes, k0x2000_ChampionAttributeWounds);
- }
-
- int16 textPosX = championIndex * k69_ChampionStatusBoxSpacing;
- int16 textPosY;
-
- Box blitBox;
- blitBox._y1 = 0;
- _vm->_eventMan->f78_showMouse();
-
- if (_vm->M0_indexToOrdinal(championIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
- blitBox._y2 = 28;
- blitBox._x1 = textPosX + 7;
- blitBox._x2 = blitBox._x1 + 31; /* Box is over the champion portrait in the status box */
- _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k16_damageToChampionBig), &blitBox, k16_byteWidth, k10_ColorFlesh, 29);
- // Check the number of digits and sets the position accordingly.
- if (pendingDamage < 10) // 1 digit
- textPosX += 21;
- else if (pendingDamage < 100) // 2 digits
- textPosX += 18;
- else // 3 digits
- textPosX += 15;
-
- textPosY = 16;
- } else {
- blitBox._y2 = 6;
- blitBox._x1 = textPosX;
- blitBox._x2 = blitBox._x1 + 47; /* Box is over the champion name in the status box */
- _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k15_damageToChampionSmallIndice), &blitBox, k24_byteWidth, k10_ColorFlesh, 7);
- // Check the number of digits and sets the position accordingly.
- if (pendingDamage < 10) // 1 digit
- textPosX += 19;
- else if (pendingDamage < 100) // 2 digits
- textPosX += 16;
- else //3 digits
- textPosX += 13;
-
- textPosY = 5;
- }
- _vm->_textMan->f53_printToLogicalScreen(textPosX, textPosY, k15_ColorWhite, k8_ColorRed, f288_getStringFromInteger(pendingDamage, false, 3).c_str());
-
- int16 eventIndex = championPtr->_hideDamageReceivedIndex;
- if (eventIndex == -1) {
- TimelineEvent newEvent;
- newEvent._type = k12_TMEventTypeHideDamageReceived;
- M33_setMapAndTime(newEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
- newEvent._priority = championIndex;
- championPtr->_hideDamageReceivedIndex = _vm->_timeline->f238_addEventGetEventIndex(&newEvent);
- } else {
- TimelineEvent *curEvent = &_vm->_timeline->_g370_events[eventIndex];
- M33_setMapAndTime(curEvent->_mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
- _vm->_timeline->f236_fixChronology(_vm->_timeline->f235_getIndex(eventIndex));
- }
- f292_drawChampionState((ChampionIndex)championIndex);
- _vm->_eventMan->f77_hideMouse();
- }
- }
-}
-
-void ChampionMan::f319_championKill(uint16 champIndex) {
- Champion *curChampion = &_gK71_champions[champIndex];
- curChampion->_currHealth = 0;
- setFlag(curChampion->_attributes, k0x1000_ChampionAttributeStatusBox);
- if (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
- if (_vm->_g331_pressingEye) {
- _vm->_g331_pressingEye = false;
- _vm->_eventMan->_g597_ignoreMouseMovements = false;
- if (!_g415_leaderEmptyHanded) {
- _vm->_objectMan->f34_drawLeaderObjectName(_g414_leaderHandObject);
- }
- _vm->_eventMan->_g587_hideMousePointerRequestCount = 1;
- _vm->_eventMan->f77_hideMouse();
- } else if (_vm->_g333_pressingMouth) {
- _vm->_g333_pressingMouth = false;
- _vm->_eventMan->_g597_ignoreMouseMovements = false;
- _vm->_eventMan->_g587_hideMousePointerRequestCount = 1;
- _vm->_eventMan->f77_hideMouse();
- }
- _vm->_inventoryMan->f355_toggleInventory(k4_ChampionCloseInventory);
- }
- f318_dropAllObjects(champIndex);
- Thing unusedThing = _vm->_dungeonMan->f166_getUnusedThing(k0x8000_championBones | k10_JunkThingType);
- uint16 curCell = 0;
- if (unusedThing != Thing::_none) {
- Junk *L0966_ps_Junk = (Junk *)_vm->_dungeonMan->f156_getThingData(unusedThing);
- L0966_ps_Junk->setType(k5_JunkTypeBones);
- L0966_ps_Junk->setDoNotDiscard(true);
- L0966_ps_Junk->setChargeCount(champIndex);
- curCell = curChampion->_cell;
- _vm->_moveSens->f267_getMoveResult(M15_thingWithNewCell(unusedThing, curCell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
- }
- curChampion->_symbolStep = 0;
- curChampion->_symbols[0] = '\0';
- curChampion->_dir = _vm->_dungeonMan->_g308_partyDir;
- curChampion->_maximumDamageReceived = 0;
- uint16 curChampionIconIndex = M26_championIconIndex(curCell, _vm->_dungeonMan->_g308_partyDir);
- if (_vm->M0_indexToOrdinal(curChampionIconIndex) == _vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap) {
- _vm->_eventMan->_g598_mousePointerBitmapUpdated = true;
- _vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap = _vm->M0_indexToOrdinal(kM1_ChampionNone);
- warning(false, "IGNORED CODE:G0592_B_BuildMousePointerScreenAreaRequested = true");
- }
-
- if (curChampion->_poisonEventCount)
- f323_unpoison(champIndex);
-
- _vm->_displayMan->_g578_useByteBoxCoordinates = false;
- _vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[curChampionIconIndex << 2], k0_ColorBlack);
- f292_drawChampionState((ChampionIndex)champIndex);
-
- int16 aliveChampionIndex;
- for (aliveChampionIndex = k0_ChampionFirst, curChampion = _gK71_champions; aliveChampionIndex < _g305_partyChampionCount; aliveChampionIndex++, curChampion++) {
- if (curChampion->_currHealth)
- break;
- }
-
- if (aliveChampionIndex == _g305_partyChampionCount) { /* BUG0_43 The game does not end if the last living champion in the party is killed while looking at a candidate champion in a portrait. The condition to end the game when the whole party is killed is not true because the code considers the candidate champion as alive (in the loop above) */
- _g303_partyDead = true;
- return;
- }
-
- if (champIndex == _g411_leaderIndex)
- _vm->_eventMan->f368_commandSetLeader((ChampionIndex)aliveChampionIndex);
-
- if (champIndex == _g514_magicCasterChampionIndex)
- _vm->_menuMan->f394_setMagicCasterAndDrawSpellArea(aliveChampionIndex);
- else
- _vm->_menuMan->f393_drawSpellAreaControls(_g514_magicCasterChampionIndex);
-}
-
-void ChampionMan::f318_dropAllObjects(uint16 champIndex) {
- static const int16 slotDropOrder[30] = {
- k5_ChampionSlotFeet,
- k4_ChampionSlotLegs,
- k9_ChampionSlotQuiverLine_2_2,
- k8_ChampionSlotQuiverLine_1_2,
- k7_ChampionSlotQuiverLine_2_1,
- k12_ChampionSlotQuiverLine_1_1,
- k6_ChampionSlotPouch_2,
- k11_ChampionSlotPouch_1,
- k3_ChampionSlotTorso,
- k13_ChampionSlotBackpackLine_1_1,
- k14_ChampionSlotBackpackLine_2_2,
- k15_ChampionSlotBackpackLine_2_3,
- k16_ChampionSlotBackpackLine_2_4,
- k17_ChampionSlotBackpackLine_2_5,
- k18_ChampionSlotBackpackLine_2_6,
- k19_ChampionSlotBackpackLine_2_7,
- k20_ChampionSlotBackpackLine_2_8,
- k21_ChampionSlotBackpackLine_2_9,
- k22_ChampionSlotBackpackLine_1_2,
- k23_ChampionSlotBackpackLine_1_3,
- k24_ChampionSlotBackpackLine_1_4,
- k25_ChampionSlotBackpackLine_1_5,
- k26_ChampionSlotBackpackLine_1_6,
- k27_ChampionSlotBackpackLine_1_7,
- k28_ChampionSlotBackpackLine_1_8,
- k29_ChampionSlotBackpackLine_1_9,
- k10_ChampionSlotNeck,
- k2_ChampionSlotHead,
- k0_ChampionSlotReadyHand,
- k1_ChampionSlotActionHand
- };
-
- uint16 curCell = _gK71_champions[champIndex]._cell;
- for (uint16 slotIndex = k0_ChampionSlotReadyHand; slotIndex < k30_ChampionSlotChest_1; slotIndex++) {
- Thing curThing = f300_getObjectRemovedFromSlot(champIndex, slotDropOrder[slotIndex]);
- if (curThing != Thing::_none)
- _vm->_moveSens->f267_getMoveResult(M15_thingWithNewCell(curThing, curCell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
- }
-}
-
-void ChampionMan::f323_unpoison(int16 champIndex) {
- if (champIndex == kM1_ChampionNone)
- return;
-
- TimelineEvent *eventPtr = _vm->_timeline->_g370_events;
- for (uint16 eventIndex = 0; eventIndex < _vm->_timeline->_g369_eventMaxCount; eventPtr++, eventIndex++) {
- if ((eventPtr->_type == k75_TMEventTypePoisonChampion) && (eventPtr->_priority == champIndex))
- _vm->_timeline->f237_deleteEvent(eventIndex);
- }
- _gK71_champions[champIndex]._poisonEventCount = 0;
-}
-
-void ChampionMan::f331_applyTimeEffects() {
- if (!_g305_partyChampionCount)
- return;
-
- Scent checkScent;
- checkScent.setMapX(_vm->_dungeonMan->_g306_partyMapX);
- checkScent.setMapY(_vm->_dungeonMan->_g307_partyMapY);
- checkScent.setMapIndex(_vm->_dungeonMan->_g309_partyMapIndex);
-
- for (byte loopScentIndex = 0; loopScentIndex + 1 < _g407_party._scentCount; loopScentIndex++) {
- if (&_g407_party._scents[loopScentIndex] != &checkScent) {
- _g407_party._scentStrengths[loopScentIndex] = MAX(0, _g407_party._scentStrengths[loopScentIndex] - 1);
- if (!_g407_party._scentStrengths[loopScentIndex] && !loopScentIndex) {
- f316_deleteScent(0);
- continue;
- }
- }
- }
-
- uint16 gameTime = _vm->_g313_gameTime & 0xFFFF;
- uint16 timeCriteria = (((gameTime & 0x0080) + ((gameTime & 0x0100) >> 2)) + ((gameTime & 0x0040) << 2)) >> 2;
- Champion *championPtr = _gK71_champions;
- for (uint16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++, championPtr++) {
- if (championPtr->_currHealth && (_vm->M0_indexToOrdinal(championIndex) != _g299_candidateChampionOrdinal)) {
- uint16 wizardSkillLevel = f303_getSkillLevel(championIndex, k3_ChampionSkillWizard) + f303_getSkillLevel(championIndex, k2_ChampionSkillPriest);
- if ((championPtr->_currMana < championPtr->_maxMana)
- && (timeCriteria < championPtr->_statistics[k3_ChampionStatWisdom][k1_ChampionStatCurrent] + wizardSkillLevel)) {
- int16 manaGain = championPtr->_maxMana / 40;
- if (_g300_partyIsSleeping)
- manaGain <<= 1;
-
- manaGain++;
- f325_decrementStamina(championIndex, manaGain * MAX(7, 16 - wizardSkillLevel));
- championPtr->_currMana += MIN<int16>(manaGain, championPtr->_maxMana - championPtr->_currMana);
- } else if (championPtr->_currMana > championPtr->_maxMana)
- championPtr->_currMana--;
-
- for (int16 idx = k19_ChampionSkillWater; idx >= k0_ChampionSkillFighter; idx--) {
- if (championPtr->_skills[idx]._temporaryExperience > 0)
- championPtr->_skills[idx]._temporaryExperience--;
- }
- uint16 staminaGainCycleCount = 4;
- int16 staminaMagnitude = championPtr->_maxStamina;
- while (championPtr->_currStamina < (staminaMagnitude >>= 1))
- staminaGainCycleCount += 2;
-
- int16 staminaLoss = 0;
- int16 staminaAmount = f26_getBoundedValue(1, (championPtr->_maxStamina >> 8) - 1, 6);
- if (_g300_partyIsSleeping)
- staminaAmount <<= 1;
-
- int32 compDelay = _vm->_g313_gameTime - _vm->_projexpl->_g362_lastPartyMovementTime;
- if (compDelay > 80) {
- staminaAmount++;
- if (compDelay > 250)
- staminaAmount++;
- }
- do {
- bool staminaAboveHalf = (staminaGainCycleCount <= 4);
- if (championPtr->_food < -512) {
- if (staminaAboveHalf) {
- staminaLoss += staminaAmount;
- championPtr->_food -= 2;
- }
- } else {
- if (championPtr->_food >= 0)
- staminaLoss -= staminaAmount;
-
- championPtr->_food -= staminaAboveHalf ? 2 : staminaGainCycleCount >> 1;
- }
- if (championPtr->_water < -512) {
- if (staminaAboveHalf) {
- staminaLoss += staminaAmount;
- championPtr->_water -= 1;
- }
- } else {
- if (championPtr->_water >= 0)
- staminaLoss -= staminaAmount;
-
- championPtr->_water -= staminaAboveHalf ? 1 : staminaGainCycleCount >> 2;
- }
- } while (--staminaGainCycleCount && ((championPtr->_currStamina - staminaLoss) < championPtr->_maxStamina));
- f325_decrementStamina(championIndex, staminaLoss);
- if (championPtr->_food < -1024)
- championPtr->_food = -1024;
-
- if (championPtr->_water < -1024)
- championPtr->_water = -1024;
-
- if ((championPtr->_currHealth < championPtr->_maxHealth) && (championPtr->_currStamina >= (championPtr->_maxStamina >> 2)) && (timeCriteria < (championPtr->_statistics[k4_ChampionStatVitality][k1_ChampionStatCurrent] + 12))) {
- int16 healthGain = (championPtr->_maxHealth >> 7) + 1;
- if (_g300_partyIsSleeping)
- healthGain <<= 1;
-
- if (_vm->_objectMan->f33_getIconIndex(championPtr->_slots[k10_ChampionSlotNeck]) == k121_IconIndiceJunkEkkhardCross)
- healthGain += (healthGain >> 1) + 1;
-
- championPtr->_currHealth += MIN(healthGain, (int16)(championPtr->_maxHealth - championPtr->_currHealth));
- }
- if (!((int)_vm->_g313_gameTime & (_g300_partyIsSleeping ? 63 : 255))) {
- for (uint16 i = k0_ChampionStatLuck; i <= k6_ChampionStatAntifire; i++) {
- byte *curStatistic = championPtr->_statistics[i];
- uint16 statisticMaximum = curStatistic[k0_ChampionStatMaximum];
- if (curStatistic[k1_ChampionStatCurrent] < statisticMaximum)
- curStatistic[k1_ChampionStatCurrent]++;
- else if (curStatistic[k1_ChampionStatCurrent] > statisticMaximum)
- curStatistic[k1_ChampionStatCurrent] -= curStatistic[k1_ChampionStatCurrent] / statisticMaximum;
- }
- }
- if (!_g300_partyIsSleeping && (championPtr->_dir != _vm->_dungeonMan->_g308_partyDir) && (_vm->_projexpl->_g361_lastCreatureAttackTime + 60 < _vm->_g313_gameTime)) {
- championPtr->_dir = _vm->_dungeonMan->_g308_partyDir;
- championPtr->_maximumDamageReceived = 0;
- setFlag(championPtr->_attributes, k0x0400_ChampionAttributeIcon);
- }
- setFlag(championPtr->_attributes, k0x0100_ChampionAttributeStatistics);
- if (_vm->M0_indexToOrdinal(championIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
- if (_vm->_g333_pressingMouth || _vm->_g331_pressingEye || (_vm->_inventoryMan->_g424_panelContent == k0_PanelContentFoodWaterPoisoned)) {
- setFlag(championPtr->_attributes, k0x0800_ChampionAttributePanel);
- }
- }
- }
- }
- f293_drawAllChampionStates();
-}
-
-void ChampionMan::save2_PartyPart(Common::OutSaveFile* file) {
- for (uint16 i = 0; i < 4; ++i) {
- Champion *champ = &_gK71_champions[i];
- file->writeUint16BE(champ->_attributes);
- file->writeUint16BE(champ->_wounds);
- for (uint16 y = 0; y < 7; ++y)
- for (uint16 x = 0; x < 3; ++x)
- file->writeByte(champ->_statistics[y][x]);
- for (uint16 j = 0; j < 30; ++j)
- file->writeUint16BE(champ->_slots[j].toUint16());
- for (uint16 j = 0; j < 20; ++j) {
- file->writeSint16BE(champ->_skills[j]._temporaryExperience);
- file->writeSint32BE(champ->_skills[j]._experience);
- }
- for (uint16 j = 0; j < 8; ++j)
- file->writeByte(champ->_name[j]);
- for (uint16 j = 0; j < 20; ++j)
- file->writeByte(champ->_title[j]);
- file->writeUint16BE(champ->_dir);
- file->writeUint16BE(champ->_cell);
- file->writeUint16BE(champ->_actionIndex);
- file->writeUint16BE(champ->_symbolStep);
- for (uint16 j = 0; j < 5; ++j)
- file->writeByte(champ->_symbols[j]);
- file->writeUint16BE(champ->_directionMaximumDamageReceived);
- file->writeUint16BE(champ->_maximumDamageReceived);
- file->writeUint16BE(champ->_poisonEventCount);
- file->writeSint16BE(champ->_enableActionEventIndex);
- file->writeSint16BE(champ->_hideDamageReceivedIndex);
- file->writeSint16BE(champ->_currHealth);
- file->writeSint16BE(champ->_maxHealth);
- file->writeSint16BE(champ->_currStamina);
- file->writeSint16BE(champ->_maxStamina);
- file->writeSint16BE(champ->_currMana);
- file->writeSint16BE(champ->_maxMana);
- file->writeSint16BE(champ->_actionDefense);
- file->writeSint16BE(champ->_food);
- file->writeSint16BE(champ->_water);
- file->writeUint16BE(champ->_load);
- file->writeSint16BE(champ->_shieldDefense);
- for (uint16 j = 0; j < 928; ++j)
- file->writeByte(champ->_portrait[j]);
- }
-
- Party &party = _g407_party;
- file->writeSint16BE(party._magicalLightAmount);
- file->writeByte(party._event73Count_ThievesEye);
- file->writeByte(party._event79Count_Footprints);
- file->writeSint16BE(party._shieldDefense);
- file->writeSint16BE(party._fireShieldDefense);
- file->writeSint16BE(party._spellShieldDefense);
- file->writeByte(party._scentCount);
- file->writeByte(party._freezeLifeTicks);
- file->writeByte(party._firstScentIndex);
- file->writeByte(party._lastScentIndex);
- for (uint16 i = 0; i < 24; ++i)
- file->writeUint16BE(party._scents[i].toUint16());
- for (uint16 i = 0; i < 24; ++i)
- file->writeByte(party._scentStrengths[i]);
- file->writeByte(party._event71Count_Invisibility);
-}
-
-void ChampionMan::load2_PartyPart(Common::InSaveFile* file) {
- for (uint16 i = 0; i < 4; ++i) {
- Champion *champ = &_gK71_champions[i];
- champ->_attributes = file->readUint16BE();
- champ->_wounds = file->readUint16BE();
- for (uint16 y = 0; y < 7; ++y)
- for (uint16 x = 0; x < 3; ++x)
- champ->_statistics[y][x] = file->readByte();
- for (uint16 j = 0; j < 30; ++j)
- champ->_slots[j] = Thing(file->readUint16BE());
- for (uint16 j = 0; j < 20; ++j) {
- champ->_skills[j]._temporaryExperience = file->readSint16BE();
- champ->_skills[j]._experience = file->readSint32BE();
- }
- for (uint16 j = 0; j < 8; ++j)
- champ->_name[j] = file->readByte();
- for (uint16 j = 0; j < 20; ++j)
- champ->_title[j] = file->readByte();
- champ->_dir = (Direction)file->readUint16BE();
- champ->_cell = (ViewCell)file->readUint16BE();
- champ->_actionIndex = (ChampionAction)file->readUint16BE();
- champ->_symbolStep = file->readUint16BE();
- for (uint16 j = 0; j < 5; ++j)
- champ->_symbols[j] = file->readByte();
- champ->_directionMaximumDamageReceived = file->readUint16BE();
- champ->_maximumDamageReceived = file->readUint16BE();
- champ->_poisonEventCount = file->readUint16BE();
- champ->_enableActionEventIndex = file->readSint16BE();
- champ->_hideDamageReceivedIndex = file->readSint16BE();
- champ->_currHealth = file->readSint16BE();
- champ->_maxHealth = file->readSint16BE();
- champ->_currStamina = file->readSint16BE();
- champ->_maxStamina = file->readSint16BE();
- champ->_currMana = file->readSint16BE();
- champ->_maxMana = file->readSint16BE();
- champ->_actionDefense = file->readSint16BE();
- champ->_food = file->readSint16BE();
- champ->_water = file->readSint16BE();
- champ->_load = file->readUint16BE();
- champ->_shieldDefense = file->readSint16BE();
- for (uint16 j = 0; j < 928; ++j)
- champ->_portrait[j] = file->readByte();
- }
-
- Party &party = _g407_party;
- party._magicalLightAmount = file->readSint16BE();
- party._event73Count_ThievesEye = file->readByte();
- party._event79Count_Footprints = file->readByte();
- party._shieldDefense = file->readSint16BE();
- party._fireShieldDefense = file->readSint16BE();
- party._spellShieldDefense = file->readSint16BE();
- party._scentCount = file->readByte();
- party._freezeLifeTicks = file->readByte();
- party._firstScentIndex = file->readByte();
- party._lastScentIndex = file->readByte();
- for (uint16 i = 0; i < 24; ++i)
- party._scents[i] = Scent(file->readUint16BE());
- for (uint16 i = 0; i < 24; ++i)
- party._scentStrengths[i] = file->readByte();
- party._event71Count_Invisibility = file->readByte();
-}
-
-ChampionIndex ChampionMan::f285_getIndexInCell(int16 cell) {
- for (uint16 i = 0; i < _g305_partyChampionCount; ++i) {
- if ((_gK71_champions[i]._cell == cell) && _gK71_champions[i]._currHealth)
- return (ChampionIndex)i;
- }
-
- return kM1_ChampionNone;
-}
-
-void ChampionMan::f278_resetDataToStartGame() {
- if (!_vm->_g298_newGame) {
- Thing L0787_T_Thing;
- if ((L0787_T_Thing = _g414_leaderHandObject) == Thing::_none) {
- _g415_leaderEmptyHanded = true;
- _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
- _vm->_eventMan->f69_setMousePointer();
- } else {
- f297_putObjectInLeaderHand(L0787_T_Thing, true); /* This call will add the weight of the leader hand object to the Load of the leader a first time */
- }
- Champion *L0788_ps_Champion = _gK71_champions;
- int16 L0785_i_ChampionIndex;
- for (L0785_i_ChampionIndex = k0_ChampionFirst; L0785_i_ChampionIndex < _g305_partyChampionCount; L0785_i_ChampionIndex++, L0788_ps_Champion++) {
- clearFlag(L0788_ps_Champion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
- setFlag(L0788_ps_Champion->_attributes, k0x8000_ChampionAttributeActionHand | k0x1000_ChampionAttributeStatusBox | k0x0400_ChampionAttributeIcon);
- }
- f293_drawAllChampionStates();
- if ((L0785_i_ChampionIndex = _g411_leaderIndex) != kM1_ChampionNone) {
- _g411_leaderIndex = kM1_ChampionNone;
- _vm->_eventMan->f368_commandSetLeader((ChampionIndex)L0785_i_ChampionIndex);
- }
- if ((L0785_i_ChampionIndex = _g514_magicCasterChampionIndex) != kM1_ChampionNone) {
- _g514_magicCasterChampionIndex = kM1_ChampionNone;
- _vm->_menuMan->f394_setMagicCasterAndDrawSpellArea(L0785_i_ChampionIndex);
- }
- return;
- }
-
- _g414_leaderHandObject = Thing::_none;
- _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
- _g415_leaderEmptyHanded = true;
-}
-
-void ChampionMan::f280_addCandidateChampionToParty(uint16 championPortraitIndex) {
- if (!_g415_leaderEmptyHanded)
- return;
-
- if (_g305_partyChampionCount == 4)
- return;
-
- uint16 previousPartyChampionCount = _g305_partyChampionCount;
- Champion *championPtr = &_gK71_champions[previousPartyChampionCount];
- championPtr->resetToZero();
- // Strangerke - TODO: Check if the new code is possible to run on the older version (example: the portraits could be missing in the data)
- _vm->_displayMan->_g578_useByteBoxCoordinates = true;
- _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k26_ChampionPortraitsIndice), championPtr->_portrait, gBoxChampionPortrait, M27_getChampionPortraitX(championPortraitIndex), M28_getChampionPortraitY(championPortraitIndex), k128_byteWidth, k16_byteWidth, kM1_ColorNoTransparency);
- championPtr->_actionIndex = k255_ChampionActionNone;
- championPtr->_enableActionEventIndex = -1;
- championPtr->_hideDamageReceivedIndex = -1;
- championPtr->_dir = _vm->_dungeonMan->_g308_partyDir;
- uint16 viewCell = k0_ViewCellFronLeft;
- while (f285_getIndexInCell(M21_normalizeModulo4(viewCell + _vm->_dungeonMan->_g308_partyDir)) != kM1_ChampionNone)
- viewCell++;
-
- championPtr->_cell = (ViewCell)M21_normalizeModulo4(viewCell + _vm->_dungeonMan->_g308_partyDir);
- championPtr->_attributes = k0x0400_ChampionAttributeIcon;
- championPtr->_directionMaximumDamageReceived = _vm->_dungeonMan->_g308_partyDir;
- championPtr->_food = 1500 + _vm->getRandomNumber(256);
- championPtr->_water = 1500 + _vm->getRandomNumber(256);
- for (int16 slotIdx = k0_ChampionSlotReadyHand; slotIdx < k30_ChampionSlotChest_1; slotIdx++)
- championPtr->_slots[slotIdx] = Thing::_none;
-
- Thing curThing = _vm->_dungeonMan->f161_getSquareFirstThing(_vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
- while (curThing.getType() != k2_TextstringType)
- curThing = _vm->_dungeonMan->f159_getNextThing(curThing);
-
- char L0807_ac_DecodedChampionText[77];
- char *decodedStringPtr = L0807_ac_DecodedChampionText;
- _vm->_dungeonMan->f168_decodeText(decodedStringPtr, curThing, (TextType)(k2_TextTypeScroll | k0x8000_DecodeEvenIfInvisible));
-
- uint16 charIdx = 0;
- char tmpChar;
- while ((tmpChar = *decodedStringPtr++) != '\n')
- championPtr->_name[charIdx++] = tmpChar;
-
- championPtr->_name[charIdx] = '\0';
- charIdx = 0;
- bool championTitleCopiedFl = false;
- for (;;) { /*_Infinite loop_*/
- tmpChar = *decodedStringPtr++;
- if (tmpChar == '\n') { /* New line */
- if (championTitleCopiedFl)
- break;
- championTitleCopiedFl = true;
- } else
- championPtr->_title[charIdx++] = tmpChar;
- }
- championPtr->_title[charIdx] = '\0';
- if (*decodedStringPtr++ == 'M')
- setFlag(championPtr->_attributes, k0x0010_ChampionAttributeMale);
-
- decodedStringPtr++;
- championPtr->_currHealth = championPtr->_maxHealth = f279_getDecodedValue(decodedStringPtr, 4);
- decodedStringPtr += 4;
- championPtr->_currStamina = championPtr->_maxStamina = f279_getDecodedValue(decodedStringPtr, 4);
- decodedStringPtr += 4;
- championPtr->_currMana = championPtr->_maxMana = f279_getDecodedValue(decodedStringPtr, 4);
- decodedStringPtr += 4;
- decodedStringPtr++;
- for (int16 statIdx = k0_ChampionStatLuck; statIdx <= k6_ChampionStatAntifire; statIdx++) {
- championPtr->_statistics[statIdx][k2_ChampionStatMinimum] = 30;
- championPtr->_statistics[statIdx][k1_ChampionStatCurrent] = championPtr->_statistics[statIdx][k0_ChampionStatMaximum] = f279_getDecodedValue(decodedStringPtr, 2);
- decodedStringPtr += 2;
- }
- championPtr->_statistics[k0_ChampionStatLuck][k2_ChampionStatMinimum] = 10;
- decodedStringPtr++;
- for (uint16 skillIdx = k4_ChampionSkillSwing; skillIdx <= k19_ChampionSkillWater; skillIdx++) {
- int skillValue = *decodedStringPtr++ - 'A';
- if (skillValue > 0)
- championPtr->_skills[skillIdx]._experience = 125L << skillValue;
- }
- for (uint16 skillIdx = k0_ChampionSkillFighter; skillIdx <= k3_ChampionSkillWizard; skillIdx++) {
- int32 baseSkillExperience = 0;
- int16 hiddenSkillIndex = (skillIdx + 1) << 2;
- for (uint16 hiddenIdx = 0; hiddenIdx < 4; hiddenIdx++)
- baseSkillExperience += championPtr->_skills[hiddenSkillIndex + hiddenIdx]._experience;
-
- championPtr->_skills[skillIdx]._experience = baseSkillExperience;
- }
- _g299_candidateChampionOrdinal = previousPartyChampionCount + 1;
- if (++_g305_partyChampionCount == 1) {
- _vm->_eventMan->f368_commandSetLeader(k0_ChampionFirst);
- _vm->_menuMan->_g508_refreshActionArea = true;
- } else {
- _vm->_menuMan->f388_clearActingChampion();
- _vm->_menuMan->f386_drawActionIcon((ChampionIndex)(_g305_partyChampionCount - 1));
- }
-
- int16 curMapX = _vm->_dungeonMan->_g306_partyMapX;
- int16 curMapY = _vm->_dungeonMan->_g307_partyMapY;
- uint16 championObjectsCell = returnOppositeDir(_vm->_dungeonMan->_g308_partyDir);
- curMapX += _vm->_dirIntoStepCountEast[_vm->_dungeonMan->_g308_partyDir], curMapY += _vm->_dirIntoStepCountNorth[_vm->_dungeonMan->_g308_partyDir];
- curThing = _vm->_dungeonMan->f161_getSquareFirstThing(curMapX, curMapY);
- int16 slotIdx = k13_ChampionSlotBackpackLine_1_1;
- while (curThing != Thing::_endOfList) {
- ThingType thingType = curThing.getType();
- if ((thingType > k3_SensorThingType) && (curThing.getCell() == championObjectsCell)) {
- int16 objectAllowedSlots = g237_ObjectInfo[_vm->_dungeonMan->f141_getObjectInfoIndex(curThing)]._allowedSlots;
- uint16 curSlotIndex;
- switch (thingType) {
- case k6_ArmourThingType: {
- bool skipCheck = false;
- for (curSlotIndex = k2_ChampionSlotHead; curSlotIndex <= k5_ChampionSlotFeet; curSlotIndex++) {
- if (objectAllowedSlots & gSlotMasks[curSlotIndex]) {
- skipCheck = true;
- break;
- }
- }
-
- if (skipCheck)
- break;
-
- if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
- curSlotIndex = k10_ChampionSlotNeck;
- else
- curSlotIndex = slotIdx++;
-
- break;
- }
- case k5_WeaponThingType:
- if (championPtr->_slots[k1_ChampionSlotActionHand] == Thing::_none)
- curSlotIndex = k1_ChampionSlotActionHand;
- else if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
- curSlotIndex = k10_ChampionSlotNeck;
- else
- curSlotIndex = slotIdx++;
- break;
- case k7_ScrollThingType:
- case k8_PotionThingType:
- if (championPtr->_slots[k11_ChampionSlotPouch_1] == Thing::_none)
- curSlotIndex = k11_ChampionSlotPouch_1;
- else if (championPtr->_slots[k6_ChampionSlotPouch_2] == Thing::_none)
- curSlotIndex = k6_ChampionSlotPouch_2;
- else if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
- curSlotIndex = k10_ChampionSlotNeck;
- else
- curSlotIndex = slotIdx++;
- break;
- case k9_ContainerThingType:
- case k10_JunkThingType:
- if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
- curSlotIndex = k10_ChampionSlotNeck;
- else
- curSlotIndex = slotIdx++;
-
- break;
- default:
- break;
- }
-
- while (championPtr->_slots[curSlotIndex] != Thing::_none) {
- if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
- curSlotIndex = k10_ChampionSlotNeck;
- else
- curSlotIndex = slotIdx++;
- }
- f301_addObjectInSlot((ChampionIndex)previousPartyChampionCount, curThing, (ChampionSlot)curSlotIndex);
- }
- curThing = _vm->_dungeonMan->f159_getNextThing(curThing);
- }
- _vm->_inventoryMan->f355_toggleInventory((ChampionIndex)previousPartyChampionCount);
- _vm->_menuMan->f456_drawDisabledMenu();;
-}
-
-void ChampionMan::f287_drawChampionBarGraphs(ChampionIndex champIndex) {
- int16 barGraphHeights[3];
- Champion *champ = &_gK71_champions[champIndex];
- int16 barGraphIdx = 0;
- if (champ->_currHealth > 0) {
- int32 barGraphHeight = (((int32)champ->_currHealth << 10) * 25) / champ->_maxHealth;
- barGraphHeights[barGraphIdx++] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
- } else
- barGraphHeights[barGraphIdx++] = 0;
-
- if (champ->_currStamina > 0) {
- int32 barGraphHeight = (((int32)champ->_currStamina << 10) * 25) / champ->_maxStamina;
- barGraphHeights[barGraphIdx++] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
- } else
- barGraphHeights[barGraphIdx++] = 0;
-
- if (champ->_currMana > 0) {
- if (champ->_currMana > champ->_maxMana)
- barGraphHeights[barGraphIdx] = 25;
- else {
- int32 barGraphHeight = (((int32)champ->_currMana << 10) * 25) / champ->_maxMana;
- barGraphHeights[barGraphIdx] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
- }
- } else {
- barGraphHeights[barGraphIdx] = 0;
- }
- _vm->_eventMan->f78_showMouse();
-
- // Strangerke - TO CHECK: if portraits, maybe the old (assembly) code is required for older versions
- Box box;
- box._x1 = champIndex * k69_ChampionStatusBoxSpacing + 46;
- box._x2 = box._x1 + 3;
- box._y1 = 2;
- box._y2 = 26;
- for (int16 barGraphIndex = 0; barGraphIndex < 3; barGraphIndex++) {
- int16 barGraphHeight = barGraphHeights[barGraphIndex];
- if (barGraphHeight < 25) {
- box._y1 = 2;
- box._y2 = 27 - barGraphHeight;
- _vm->_displayMan->D24_fillScreenBox(box, k12_ColorDarkestGray);
- }
- if (barGraphHeight) {
- box._y1 = 27 - barGraphHeight;
- box._y2 = 26;
- _vm->_displayMan->D24_fillScreenBox(box, g46_ChampionColor[champIndex]);
- }
- box._x1 += 7;
- box._x2 += 7;
- }
- _vm->_eventMan->f77_hideMouse();
-}
-
-
-uint16 ChampionMan::f306_getStaminaAdjustedValue(Champion *champ, int16 val) {
- int16 currStamina = champ->_currStamina;
- int16 halfMaxStamina = champ->_maxStamina / 2;
- if (currStamina < halfMaxStamina) {
- warning(false, "Possible undefined behavior in the original code");
- val /= 2;
- return val + ((uint32)val * (uint32)currStamina) / halfMaxStamina;
- }
- return val;
-}
-
-uint16 ChampionMan::f309_getMaximumLoad(Champion *champ) {
- uint16 maximumLoad = champ->getStatistic(k1_ChampionStatStrength, k1_ChampionStatCurrent) * 8 + 100;
- maximumLoad = f306_getStaminaAdjustedValue(champ, maximumLoad);
- int16 wounds = champ->getWounds();
- if (wounds)
- maximumLoad -= maximumLoad >> (champ->getWoundsFlag(k0x0010_ChampionWoundLegs) ? 2 : 3);
-
- if (_vm->_objectMan->f33_getIconIndex(champ->getSlot(k5_ChampionSlotFeet)) == k119_IconIndiceArmourElvenBoots)
- maximumLoad += maximumLoad * 16;
-
- maximumLoad += 9;
- maximumLoad -= maximumLoad % 10;
- return maximumLoad;
-}
-
-void ChampionMan::f292_drawChampionState(ChampionIndex champIndex) {
- int16 championStatusBoxX = champIndex * k69_ChampionStatusBoxSpacing;
- Champion *curChampion = &_gK71_champions[champIndex];
- uint16 championAttributes = curChampion->_attributes;
- if (!getFlag(championAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand))
- return;
-
- bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal);
- _vm->_displayMan->_g578_useByteBoxCoordinates = false;
- _vm->_eventMan->f78_showMouse();
- if (getFlag(championAttributes, k0x1000_ChampionAttributeStatusBox)) {
- Box box;
- box._y1 = 0;
- box._y2 = 28;
- box._x1 = championStatusBoxX;
- box._x2 = box._x1 + 66;
- if (curChampion->_currHealth) {
- _vm->_displayMan->D24_fillScreenBox(box, k12_ColorDarkestGray);
- int16 nativeBitmapIndices[3];
- for (uint16 i = 0; i < 3; ++i)
- nativeBitmapIndices[i] = 0;
-
- uint16 borderCount = 0;
- if (_g407_party._fireShieldDefense > 0)
- nativeBitmapIndices[borderCount++] = k38_BorderPartyFireshieldIndice;
-
- if (_g407_party._spellShieldDefense > 0)
- nativeBitmapIndices[borderCount++] = k39_BorderPartySpellshieldIndice;
-
- if ((_g407_party._shieldDefense > 0) || curChampion->_shieldDefense)
- nativeBitmapIndices[borderCount++] = k37_BorderPartyShieldIndice;
-
- while (borderCount--)
- _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndices[borderCount]), &box, k40_byteWidth, k10_ColorFlesh, 29);
-
- if (isInventoryChampion) {
- _vm->_inventoryMan->f354_drawStatusBoxPortrait(champIndex);
- setFlag(championAttributes, k0x0100_ChampionAttributeStatistics);
- } else
- setFlag(championAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x2000_ChampionAttributeWounds | k0x8000_ChampionAttributeActionHand);
- } else {
- _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k8_StatusBoxDeadChampion), &box, k40_byteWidth, kM1_ColorNoTransparency, 29);
- _vm->_textMan->f53_printToLogicalScreen(championStatusBoxX + 1, 5, k13_ColorLightestGray, k1_ColorDarkGary, curChampion->_name);
- _vm->_menuMan->f386_drawActionIcon(champIndex);
-
- clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
- _vm->_eventMan->f77_hideMouse();
- return;
- }
- }
- if (!(curChampion->_currHealth)) {
- clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
- _vm->_eventMan->f77_hideMouse();
- return;
- }
-
- if (getFlag(championAttributes, k0x0080_ChampionAttributeNameTitle)) {
- Color nameColor = (champIndex == _g411_leaderIndex) ? k9_ColorGold : k13_ColorLightestGray;
- if (isInventoryChampion) {
- char *championName = curChampion->_name;
- _vm->_textMan->f52_printToViewport(3, 7, nameColor, championName);
- int16 championTitleX = 6 * strlen(championName) + 3;
- char titleFirstCharacter = curChampion->_title[0];
- if ((titleFirstCharacter != ',') && (titleFirstCharacter != ';') && (titleFirstCharacter != '-'))
- championTitleX += 6;
-
- _vm->_textMan->f52_printToViewport(championTitleX, 7, nameColor, curChampion->_title);
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- } else {
- Box box;
- box._y1 = 0;
- box._y2 = 6;
- box._x1 = championStatusBoxX;
- box._x2 = box._x1 + 42;
- _vm->_displayMan->D24_fillScreenBox(box, k1_ColorDarkGary);
- _vm->_textMan->f53_printToLogicalScreen(championStatusBoxX + 1, 5, nameColor, k1_ColorDarkGary, curChampion->_name);
- }
- }
- if (getFlag(championAttributes, k0x0100_ChampionAttributeStatistics)) {
- f287_drawChampionBarGraphs(champIndex);
- if (isInventoryChampion) {
- f290_drawHealthStaminaManaValues(curChampion);
- int16 nativeBitmapIndex;
- if ((curChampion->_food < 0) || (curChampion->_water < 0) || (curChampion->_poisonEventCount))
- nativeBitmapIndex = k34_SlotBoxWoundedIndice;
- else
- nativeBitmapIndex = k33_SlotBoxNormalIndice;
-
- _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex), gBoxMouth, k16_byteWidth, k12_ColorDarkestGray, 18);
- nativeBitmapIndex = k33_SlotBoxNormalIndice;
- for (int i = k1_ChampionStatStrength; i <= k6_ChampionStatAntifire; i++) {
- if ((curChampion->_statistics[i][k1_ChampionStatCurrent] < curChampion->_statistics[i][k0_ChampionStatMaximum])) {
- nativeBitmapIndex = k34_SlotBoxWoundedIndice;
- break;
- }
- }
- _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex), gBoxEye, k16_byteWidth, k12_ColorDarkestGray, 18);
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- }
- }
- if (getFlag(championAttributes, k0x2000_ChampionAttributeWounds)) {
- for (int i = isInventoryChampion ? k5_ChampionSlotFeet : k1_ChampionSlotActionHand; i >= k0_ChampionSlotReadyHand; i--)
- f291_drawSlot(champIndex, i);
-
- if (isInventoryChampion)
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- }
- if (getFlag(championAttributes, k0x0200_ChampionAttributeLoad) && isInventoryChampion) {
- uint16 maxLoad = f309_getMaximumLoad(curChampion);
- Color loadColor;
- if (curChampion->_load > maxLoad)
- loadColor = k8_ColorRed;
- else if (((long)curChampion->_load << 3) > ((long)maxLoad * 5))
- loadColor = k11_ColorYellow;
- else
- loadColor = k13_ColorLightestGray;
-
- _vm->_textMan->f52_printToViewport(104, 132, loadColor, "LOAD ");
- maxLoad = curChampion->_load / 10;
- strcpy(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, true, 3).c_str());
- strcat(_vm->_g353_stringBuildBuffer, ".");
- maxLoad = curChampion->_load - (maxLoad * 10);
- strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, false, 1).c_str());
- strcat(_vm->_g353_stringBuildBuffer, "/");
- maxLoad = (f309_getMaximumLoad(curChampion) + 5) / 10;
- strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, true, 3).c_str());
- strcat(_vm->_g353_stringBuildBuffer, " KG");
- _vm->_textMan->f52_printToViewport(148, 132, loadColor, _vm->_g353_stringBuildBuffer);
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- }
- uint16 championIconIndex = M26_championIconIndex(curChampion->_cell, _vm->_dungeonMan->_g308_partyDir);
- if (getFlag(championAttributes, k0x0400_ChampionAttributeIcon) && (_vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap != _vm->M0_indexToOrdinal(championIconIndex))) {
- _vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[championIconIndex], g46_ChampionColor[champIndex]);
- _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k28_ChampionIcons), _vm->_displayMan->_g348_bitmapScreen, g54_BoxChampionIcons[championIconIndex], M26_championIconIndex(curChampion->_dir, _vm->_dungeonMan->_g308_partyDir) * 19, 0, k40_byteWidth, k160_byteWidthScreen, k12_ColorDarkestGray, 14, k200_heightScreen);
- }
- if (getFlag(championAttributes, k0x0800_ChampionAttributePanel) && isInventoryChampion) {
- if (_vm->_g333_pressingMouth)
- _vm->_inventoryMan->f345_drawPanelFoodWaterPoisoned();
- else if (_vm->_g331_pressingEye) {
- if (_g415_leaderEmptyHanded)
- _vm->_inventoryMan->f351_drawChampionSkillsAndStatistics();
- } else
- _vm->_inventoryMan->f347_drawPanel();
-
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- }
- if (getFlag(championAttributes, k0x8000_ChampionAttributeActionHand)) {
- f291_drawSlot(champIndex, k1_ChampionSlotActionHand);
- _vm->_menuMan->f386_drawActionIcon(champIndex);
- if (isInventoryChampion)
- setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
- }
- if (getFlag(championAttributes, k0x4000_ChampionAttributeViewport))
- _vm->_displayMan->f97_drawViewport(k0_viewportNotDungeonView);
-
- clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
- _vm->_eventMan->f77_hideMouse();
-}
-
-uint16 ChampionMan::M26_championIconIndex(int16 val, Direction dir) {
- return ((val + 4 - dir) & 0x3);
-}
-
-void ChampionMan::f290_drawHealthStaminaManaValues(Champion* champ) {
- f289_drawHealthOrStaminaOrManaValue(116, champ->_currHealth, champ->_maxHealth);
- f289_drawHealthOrStaminaOrManaValue(124, champ->_currStamina, champ->_maxStamina);
- f289_drawHealthOrStaminaOrManaValue(132, champ->_currMana, champ->_maxMana);
-}
-
-void ChampionMan::f291_drawSlot(uint16 champIndex, int16 slotIndex) {
- int16 nativeBitmapIndex = -1;
- Champion *champ = &_gK71_champions[champIndex];
- bool isInventoryChamp = (_vm->_inventoryMan->_g432_inventoryChampionOrdinal == _vm->M0_indexToOrdinal(champIndex));
-
- uint16 slotBoxIndex;
- if (!isInventoryChamp) {
- // If drawing a slot for a champion other than the champion whose inventory is open
- if ((slotIndex > k1_ChampionSlotActionHand) || (_g299_candidateChampionOrdinal == _vm->M0_indexToOrdinal(champIndex)))
- return;
- slotBoxIndex = (champIndex << 1) + slotIndex;
- } else
- slotBoxIndex = k8_SlotBoxInventoryFirstSlot + slotIndex;
-
- Thing thing;
- if (slotIndex >= k30_ChampionSlotChest_1)
- thing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
- else
- thing = champ->getSlot((ChampionSlot)slotIndex);
-
- SlotBox *slotBox = &_vm->_objectMan->_g30_slotBoxes[slotBoxIndex];
- Box box;
- box._x1 = slotBox->_x - 1;
- box._y1 = slotBox->_y - 1;
- box._x2 = box._x1 + 17;
- box._y2 = box._y1 + 17;
-
- if (!isInventoryChamp)
- _vm->_eventMan->f77_hideMouse();
-
- int16 iconIndex;
- if (thing == Thing::_none) {
- if (slotIndex <= k5_ChampionSlotFeet) {
- iconIndex = k212_IconIndiceReadyHand + (slotIndex << 1);
- if (champ->getWoundsFlag((ChampionWound)(1 << slotIndex))) {
- iconIndex++;
- nativeBitmapIndex = k34_SlotBoxWoundedIndice;
- } else
- nativeBitmapIndex = k33_SlotBoxNormalIndice;
- } else {
- if ((slotIndex >= k10_ChampionSlotNeck) && (slotIndex <= k13_ChampionSlotBackpackLine_1_1))
- iconIndex = k208_IconIndiceNeck + (slotIndex - k10_ChampionSlotNeck);
- else
- iconIndex = k204_IconIndiceEmptyBox;
- }
- } else {
- iconIndex = _vm->_objectMan->f33_getIconIndex(thing); // BUG0_35
- if (isInventoryChamp && (slotIndex == k1_ChampionSlotActionHand) && ((iconIndex == k144_IconIndiceContainerChestClosed) || (iconIndex == k30_IconIndiceScrollOpen))) {
- iconIndex++;
- } // BUG2_00
- if (slotIndex <= k5_ChampionSlotFeet) {
- if (champ->getWoundsFlag((ChampionWound)(1 << slotIndex)))
- nativeBitmapIndex = k34_SlotBoxWoundedIndice;
- else
- nativeBitmapIndex = k33_SlotBoxNormalIndice;
- }
- }
-
- if ((slotIndex == k1_ChampionSlotActionHand) && (_vm->M0_indexToOrdinal(champIndex) == _g506_actingChampionOrdinal))
- nativeBitmapIndex = k35_SlotBoxActingHandIndice;
-
- if (nativeBitmapIndex != -1) {
- _vm->_displayMan->_g578_useByteBoxCoordinates = false;
- if (isInventoryChamp)
- _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex),
- _vm->_displayMan->_g296_bitmapViewport, box, 0, 0, 16, k112_byteWidthViewport, k12_ColorDarkestGray);
- else
- _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex),
- _vm->_displayMan->_g348_bitmapScreen, box, 0, 0, 16, k160_byteWidthScreen, k12_ColorDarkestGray);
- }
-
- _vm->_objectMan->f38_drawIconInSlotBox(slotBoxIndex, iconIndex);
-
- if (!isInventoryChamp)
- _vm->_eventMan->f78_showMouse();
-}
-
-void ChampionMan::f281_renameChampion(Champion* champ) {
-#define k1_RENAME_CHAMPION_NAME 1
-#define k2_RENAME_CHAMPION_TITLE 2
- static const char underscoreCharacterString[2] = "_";
- static char renameChampionInputCharacterString[2] = " ";
- static const char reincarnateSpecialCharacters[6] = {',', '.', ';', ':', ' '};
-
- Box displayBox;
- displayBox._y1 = 3;
- displayBox._y2 = 8;
- displayBox._x1 = 3;
- displayBox._x2 = displayBox._x1 + 167;
-
- _vm->_displayMan->f135_fillBoxBitmap(_vm->_displayMan->_g296_bitmapViewport, displayBox, k12_ColorDarkestGray, k112_byteWidthViewport, k136_heightViewport);
- _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k27_PanelRenameChampionIndice), g32_BoxPanel, k72_byteWidth, k4_ColorCyan, 73);
- _vm->_textMan->f52_printToViewport(177, 58, k13_ColorLightestGray, "_______");
- _vm->_textMan->f52_printToViewport(105, 76, k13_ColorLightestGray, "___________________");
- _vm->_eventMan->f78_showMouse();
- _vm->_displayMan->f97_drawViewport(k0_viewportNotDungeonView);
- _vm->_eventMan->f67_setMousePointerToNormal(k0_pointerArrow);
- _vm->_eventMan->f77_hideMouse();
- uint16 curCharacterIndex = 0;
- champ->_name[curCharacterIndex] = '\0';
- champ->_title[0] = '\0';
- int16 renamedChampionStringMode = k1_RENAME_CHAMPION_NAME;
- char *renamedChampionString = champ->_name;
- int16 textPosX = 177;
- int16 textPosY = 91;
-
- for (;;) { /*_Infinite loop_*/
- bool championTitleIsFull = ((renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE) && (curCharacterIndex == 19));
- if (!championTitleIsFull) {
- _vm->_eventMan->f78_showMouse();
- _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k9_ColorGold, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
- _vm->_eventMan->f77_hideMouse();
- }
-
- int16 curCharacter = 256;
- while (curCharacter == 256) {
- Common::Event event;
- Common::EventType eventType = _vm->_eventMan->processInput(&event, &event);
- _vm->_displayMan->updateScreen();
- _vm->f22_delay(1);
-
- if (eventType == Common::EVENT_LBUTTONDOWN) {
- // If left mouse button status has changed
- Common::Point mousePos = _vm->_eventMan->getMousePos();
- if ((renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE || (curCharacterIndex > 0)) && (mousePos.x >= 197) && (mousePos.x <= 215) && (mousePos.y >= 147) && (mousePos.y <= 155)) { /* Coordinates of 'OK' button */
- int16 characterIndexBackup = curCharacterIndex;
- char L0821_ac_ChampionNameBackupString[8];
- renamedChampionString = champ->_name;
- strcpy(L0821_ac_ChampionNameBackupString, renamedChampionString);
- curCharacterIndex = strlen(renamedChampionString);
- // Replace space characters on the right of the champion name by '\0' characters
- while (renamedChampionString[--curCharacterIndex] == ' ')
- renamedChampionString[curCharacterIndex] = '\0';
-
- bool found = false;
- for (uint16 idx = k0_ChampionFirst; idx < _g305_partyChampionCount - 1; idx++) {
- if (!strcmp(_gK71_champions[idx]._name, renamedChampionString)) {
- // If an existing champion already has the specified name for the new champion
- found = true;
- break;
- }
- }
- if (!found)
- return;
-
- if (renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE)
- renamedChampionString = champ->_title;
-
- strcpy(renamedChampionString = champ->_name, L0821_ac_ChampionNameBackupString);
- curCharacterIndex = characterIndexBackup;
- } else {
- if ((mousePos.x >= 107) && (mousePos.x <= 175) && (mousePos.y >= 147) && (mousePos.y <= 155)) { /* Coordinates of 'BACKSPACE' button */
- curCharacter = '\b';
- break;
- }
-#if 0
- if ((mousePos.x < 107) || (mousePos.x > 215) || (mousePos.y < 116) || (mousePos.y > 144)) {/* Coordinates of table of all other characters */
- //goto T0281023;
- }
- if (!((mousePos.x + 4) % 10) || (!((mousePos.y + 5) % 10) && ((mousePos.x < 207) || (mousePos.y != 135)))) {
- //goto T0281023;
- }
-#endif
- curCharacter = 'A' + (11 * ((mousePos.y - 116) / 10)) + ((mousePos.x - 107) / 10);
- if ((curCharacter == 86) || (curCharacter == 97)) {
- // The 'Return' button occupies two cells in the table
- curCharacter = '\r'; /* Carriage return */
- break;
- }
-
- if (curCharacter >= 87)
- // Compensate for the first cell occupied by 'Return' button
- curCharacter--;
-
- if (curCharacter > 'Z')
- curCharacter = reincarnateSpecialCharacters[(curCharacter - 'Z') - 1];
-
- break;
- }
- } else if (eventType == Common::EVENT_KEYDOWN)
- curCharacter = event.kbd.ascii;
- }
-
- if ((curCharacter >= 'a') && (curCharacter <= 'z'))
- curCharacter -= 32; // Convert to uppercase
-
- if (((curCharacter >= 'A') && (curCharacter <= 'Z')) || (curCharacter == '.') || (curCharacter == ',') || (curCharacter == ';') || (curCharacter == ':') || (curCharacter == ' ')) {
- if ((curCharacter != ' ') || curCharacterIndex != 0) {
- if (!championTitleIsFull) {
- renameChampionInputCharacterString[0] = curCharacter;
- _vm->_eventMan->f78_showMouse();
- _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, renameChampionInputCharacterString, k200_heightScreen);
- _vm->_eventMan->f77_hideMouse();
- renamedChampionString[curCharacterIndex++] = curCharacter;
- renamedChampionString[curCharacterIndex] = '\0';
- textPosX += 6;
- if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex == 7)) {
- renamedChampionStringMode = k2_RENAME_CHAMPION_TITLE;
- renamedChampionString = champ->_title;
- textPosX = 105;
- textPosY = 109;
- curCharacterIndex = 0;
- }
- }
- }
- } else if (curCharacter == '\r') { // Carriage return
- if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex > 0)) {
- _vm->_eventMan->f78_showMouse();
- _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
- _vm->_eventMan->f77_hideMouse();
- renamedChampionStringMode = k2_RENAME_CHAMPION_TITLE;
- renamedChampionString = champ->_title;
- textPosX = 105;
- textPosY = 109;
- curCharacterIndex = 0;
- }
- } else if (curCharacter == '\b') { // Backspace
- if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex == 0))
- continue;
-
- if (!championTitleIsFull) {
- _vm->_eventMan->f78_showMouse();
- _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
- _vm->_eventMan->f77_hideMouse();
- }
- if (curCharacterIndex == 0) {
- renamedChampionString = champ->_name;
- curCharacterIndex = strlen(renamedChampionString) - 1;
- renamedChampionStringMode = k1_RENAME_CHAMPION_NAME;
- textPosX = 177 + (curCharacterIndex * 6);
- textPosY = 91;
- } else {
- curCharacterIndex--;
- textPosX -= 6;
- }
- renamedChampionString[curCharacterIndex] = '\0';
- }
- }
-}
-
-uint16 ChampionMan::f303_getSkillLevel(int16 champIndex, uint16 skillIndex) {
- if (_g300_partyIsSleeping)
- return 1;
-
- bool ignoreTmpExp = getFlag(skillIndex, k0x8000_IgnoreTemporaryExperience);
- bool ignoreObjModifiers = getFlag(skillIndex, k0x4000_IgnoreObjectModifiers);
- clearFlag(skillIndex, k0x8000_IgnoreTemporaryExperience | k0x4000_IgnoreObjectModifiers);
- Champion *champ = &_gK71_champions[champIndex];
- Skill *skill = &champ->_skills[skillIndex];
- int32 exp = skill->_experience;
- if (!ignoreTmpExp)
- exp += skill->_temporaryExperience;
-
- if (skillIndex > k3_ChampionSkillWizard) {
- // Hidden skill
- skill = &champ->_skills[(skillIndex - k4_ChampionSkillSwing) >> 2];
- exp += skill->_experience; // Add experience in the base skill
- if (!ignoreTmpExp)
- exp += skill->_temporaryExperience;
-
- exp >>= 1; // Halve experience to get average of base skill + hidden skill experience
- }
- int16 skillLevel = 1;
- while (exp >= 500) {
- exp >>= 1;
- skillLevel++;
- }
- if (!ignoreObjModifiers) {
- int16 actionHandIconIndex = _vm->_objectMan->f33_getIconIndex(champ->_slots[k1_ChampionSlotActionHand]);
- if (actionHandIconIndex == k27_IconIndiceWeaponTheFirestaff)
- skillLevel++;
- else if (actionHandIconIndex == k28_IconIndiceWeaponTheFirestaffComplete)
- skillLevel += 2;
-
- int16 neckIconIndex = _vm->_objectMan->f33_getIconIndex(champ->_slots[k10_ChampionSlotNeck]);
- switch (skillIndex) {
- case k3_ChampionSkillWizard:
- if (neckIconIndex == k124_IconIndiceJunkPendantFeral)
- skillLevel += 1;
- break;
- case k13_ChampionSkillHeal:
- // The skill modifiers of these two objects are not cumulative
- if ((neckIconIndex == k120_IconIndiceJunkGemOfAges) || (actionHandIconIndex == k66_IconIndiceWeaponSceptreOfLyf))
- skillLevel += 1;
- break;
- case k14_ChampionSkillInfluence:
- if (neckIconIndex == k122_IconIndiceJunkMoonstone)
- skillLevel += 1;
- break;
- case k15_ChampionSkillDefend:
- if (neckIconIndex == k121_IconIndiceJunkEkkhardCross)
- skillLevel += 1;
- break;
- default:
- break;
- }
- }
- return skillLevel;
-}
-
-}
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+* Based on the Reverse Engineering work of Christophe Fontanel,
+* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
+*/
+
+#include "champion.h"
+#include "dungeonman.h"
+#include "eventman.h"
+#include "menus.h"
+#include "inventory.h"
+#include "objectman.h"
+#include "text.h"
+#include "timeline.h"
+#include "projexpl.h"
+#include "group.h"
+#include "movesens.h"
+
+
+namespace DM {
+
+const char *g417_baseSkillName[4] = {"FIGHTER", "NINJA", "PRIEST", "WIZARD"};
+
+Box gBoxMouth = Box(55, 72, 12, 29); // @ G0048_s_Graphic562_Box_Mouth
+Box gBoxEye = Box(11, 28, 12, 29); // @ G0049_s_Graphic562_Box_Eye
+Box g54_BoxChampionIcons[4] = {
+ Box(281, 299, 0, 13),
+ Box(301, 319, 0, 13),
+ Box(301, 319, 15, 28),
+ Box(281, 299, 15, 28)};
+Color g46_ChampionColor[4] = {(Color)7, (Color)11, (Color)8, (Color)14};
+
+int16 g39_LightPowerToLightAmount[16] = {0, 5, 12, 24, 33, 40, 46, 51, 59, 68, 76, 82, 89, 94, 97, 100};
+
+uint16 gSlotMasks[38] = { // @ G0038_ai_Graphic562_SlotMasks
+ /* 30 for champion inventory, 8 for chest */
+ 0xFFFF, /* Ready Hand Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Action Hand Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0x0002, /* Head Head */
+ 0x0008, /* Torso Torso */
+ 0x0010, /* Legs Legs */
+ 0x0020, /* Feet Feet */
+ 0x0100, /* Pouch 2 Pouch */
+ 0x0080, /* Quiver Line2 1 Quiver 2 */
+ 0x0080, /* Quiver Line1 2 Quiver 2 */
+ 0x0080, /* Quiver Line2 2 Quiver 2 */
+ 0x0004, /* Neck Neck */
+ 0x0100, /* Pouch 1 Pouch */
+ 0x0040, /* Quiver Line1 1 Quiver 1 */
+ 0xFFFF, /* Backpack Line1 1 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 2 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 3 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 4 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 5 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 6 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 7 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 8 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line2 9 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 2 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 3 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 4 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 5 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 6 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 7 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 8 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0xFFFF, /* Backpack Line1 9 Mouth/Head/Neck/Torso/Legs/Feet/Quiver 1/Quiver 2/Pouch/Hands/Chest */
+ 0x0400, /* Chest 1 Chest */
+ 0x0400, /* Chest 2 Chest */
+ 0x0400, /* Chest 3 Chest */
+ 0x0400, /* Chest 4 Chest */
+ 0x0400, /* Chest 5 Chest */
+ 0x0400, /* Chest 6 Chest */
+ 0x0400, /* Chest 7 Chest */
+ 0x0400}; /* Chest 8 Chest */
+
+Box gBoxChampionPortrait = Box(0, 31, 0, 28); // @ G0047_s_Graphic562_Box_ChampionPortrait
+
+ChampionMan::ChampionMan(DMEngine *vm) : _vm(vm) {
+ for (uint16 i = 0; i < 4; ++i) {
+ _g409_championPendingDamage[i] = 0;
+ _g410_championPendingWounds[i] = 0;
+ _gK71_champions[i].resetToZero();
+ }
+ _g305_partyChampionCount = 0;
+ _g303_partyDead = false;
+ _g414_leaderHandObject = Thing(0);
+ _g411_leaderIndex = kM1_ChampionNone;
+ _g299_candidateChampionOrdinal = 0;
+ _g300_partyIsSleeping = false;
+ _g506_actingChampionOrdinal = 0;
+ _g413_leaderHandObjectIconIndex = (IconIndice)0;
+ _g415_leaderEmptyHanded = false;
+ _g407_party.resetToZero();
+ _g514_magicCasterChampionIndex = kM1_ChampionNone;
+ _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = false;
+}
+
+bool ChampionMan::f329_isLeaderHandObjectThrown(int16 side) {
+ if (_g411_leaderIndex == kM1_ChampionNone) {
+ return false;
+ }
+ return f328_isObjectThrown(_g411_leaderIndex, kM1_ChampionSlotLeaderHand, side);
+}
+
+bool ChampionMan::f328_isObjectThrown(uint16 champIndex, int16 slotIndex, int16 side) {
+ bool throwingLeaderHandObjectFl = false;
+ Thing curThing;
+ Champion *curChampion = nullptr;
+ Thing actionHandThing;
+
+ if (slotIndex < 0) { /* Throw object in leader hand, which is temporarily placed in action hand */
+ if (_g415_leaderEmptyHanded)
+ return false;
+
+ curThing = f298_getObjectRemovedFromLeaderHand();
+ curChampion = &_gK71_champions[champIndex];
+ actionHandThing = curChampion->getSlot(k1_ChampionSlotActionHand);
+ curChampion->setSlot(k1_ChampionSlotActionHand, curThing);
+ slotIndex = k1_ChampionSlotActionHand;
+ throwingLeaderHandObjectFl = true;
+ }
+
+ int16 kineticEnergy = f312_getStrength(champIndex, slotIndex);
+ if (throwingLeaderHandObjectFl) {
+ // In this case, curChampion and actionHandThing are set.
+ curChampion->setSlot((ChampionSlot)slotIndex, actionHandThing);
+ } else {
+ curThing = f300_getObjectRemovedFromSlot(champIndex, slotIndex);
+ if (curThing == Thing::_none)
+ return false;
+ }
+
+ _vm->f064_SOUND_RequestPlay_CPSD(k16_soundCOMBAT_ATTACK_SKELETON_ANIMATED_ARMOUR_DETH_KNIGHT, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, k1_soundModePlayIfPrioritized);
+ f325_decrementStamina(champIndex, f305_getThrowingStaminaCost(curThing));
+ f330_disableAction(champIndex, 4);
+ int16 experience = 8;
+ int16 weaponKineticEnergy = 1;
+ if (curThing.getType() == k5_WeaponThingType) {
+ experience += 4;
+ WeaponInfo *curWeapon = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
+ if (curWeapon->_class <= k12_WeaponClassPoisinDart) {
+ weaponKineticEnergy = curWeapon->_kineticEnergy;
+ experience += weaponKineticEnergy >> 2;
+ }
+ }
+ f304_addSkillExperience(champIndex, k10_ChampionSkillThrow, experience);
+ kineticEnergy += weaponKineticEnergy;
+ int16 skillLevel = f303_getSkillLevel((ChampionIndex)champIndex, k10_ChampionSkillThrow);
+ kineticEnergy += _vm->getRandomNumber(16) + (kineticEnergy >> 1) + skillLevel;
+ int16 attack = f26_getBoundedValue((uint16)40, (uint16)((skillLevel << 3) + _vm->getRandomNumber(32)), (uint16)200);
+ int16 stepEnergy = MAX(5, 11 - skillLevel);
+ _vm->_projexpl->f212_projectileCreate(curThing, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY,
+ M21_normalizeModulo4(_vm->_dungeonMan->_g308_partyDir + side),
+ _vm->_dungeonMan->_g308_partyDir, kineticEnergy, attack, stepEnergy);
+ _vm->_g311_projectileDisableMovementTicks = 4;
+ _vm->_g312_lastProjectileDisabledMovementDirection = _vm->_dungeonMan->_g308_partyDir;
+ f292_drawChampionState((ChampionIndex)champIndex);
+ return true;
+}
+
+uint16 ChampionMan::M27_getChampionPortraitX(uint16 index) {
+ return ((index) & 0x7) << 5;
+}
+
+uint16 ChampionMan::M28_getChampionPortraitY(uint16 index) {
+ return ((index) >> 3) * 29;
+}
+
+int16 ChampionMan::f279_getDecodedValue(char *string, uint16 characterCount) {
+ int val = 0;
+ for (uint16 i = 0; i < characterCount; ++i) {
+ val = (val << 4) + (string[i] - 'A');
+ }
+ return val;
+}
+
+void ChampionMan::f289_drawHealthOrStaminaOrManaValue(int16 posY, int16 currVal, int16 maxVal) {
+ Common::String tmp = f288_getStringFromInteger(currVal, true, 3);
+ _vm->_textMan->f52_printToViewport(55, posY, k13_ColorLightestGray, tmp.c_str());
+ _vm->_textMan->f52_printToViewport(73, posY, k13_ColorLightestGray, "/");
+ tmp = f288_getStringFromInteger(maxVal, true, 3);
+ _vm->_textMan->f52_printToViewport(79, posY, k13_ColorLightestGray, tmp.c_str());
+}
+
+uint16 ChampionMan::M70_handSlotIndex(uint16 slotBoxIndex) {
+ return slotBoxIndex & 0x1;
+}
+
+Common::String ChampionMan::f288_getStringFromInteger(uint16 val, bool padding, uint16 paddingCharCount) {
+ Common::String valToStr = Common::String::format("%d", val);
+ Common::String result;
+
+ if (padding) {
+ for (int16 i = 0, end = paddingCharCount - valToStr.size(); i < end; ++i)
+ result += ' ';
+ }
+
+ return result += valToStr;
+}
+
+void ChampionMan::f299_applyModifiersToStatistics(Champion *champ, int16 slotIndex, int16 iconIndex, int16 modifierFactor, Thing thing) {
+ int16 statIndex = k0_ChampionStatLuck;
+ int16 modifier = 0;
+ ThingType thingType = thing.getType();
+
+ bool cursed = false;
+ if (((thingType == k5_WeaponThingType) || (thingType == k6_ArmourThingType))
+ && (slotIndex >= k0_ChampionSlotReadyHand) && (slotIndex <= k12_ChampionSlotQuiverLine_1_1)) {
+ if (thingType == k5_WeaponThingType) {
+ Weapon *weapon = (Weapon *)_vm->_dungeonMan->f156_getThingData(thing);
+ cursed = weapon->getCursed();
+ } else {
+ // k6_ArmourThingType
+ Armour *armour = (Armour *)_vm->_dungeonMan->f156_getThingData(thing);
+ cursed = armour->getCursed();
+ }
+
+ if (cursed) {
+ statIndex = k0_ChampionStatLuck;
+ modifier = -3;
+ }
+ }
+
+ if (!cursed) {
+ statIndex = (ChampionStatisticType)thingType; // variable sharing
+
+ if ((iconIndex == k137_IconIndiceJunkRabbitsFoot) && (slotIndex < k30_ChampionSlotChest_1)) {
+ statIndex = k0_ChampionStatLuck;
+ modifier = 10;
+ } else if (slotIndex == k1_ChampionSlotActionHand) {
+ if (iconIndex == k45_IconIndiceWeaponMaceOfOrder) {
+ statIndex = k1_ChampionStatStrength;
+ modifier = 5;
+ } else {
+ statIndex = k8_ChampionStatMana;
+ if ((iconIndex >= k20_IconIndiceWeaponStaffOfClawsEmpty) && (iconIndex <= k22_IconIndiceWeaponStaffOfClawsFull)) {
+ modifier = 4;
+ } else {
+ switch (iconIndex) {
+ case k38_IconIndiceWeaponDeltaSideSplitter:
+ modifier = 1;
+ break;
+ case k41_IconIndiceWeaponTheInquisitorDragonFang:
+ modifier = 2;
+ break;
+ case k40_IconIndiceWeaponVorpalBlade:
+ modifier = 4;
+ break;
+ case k58_IconIndiceWeaponStaff:
+ modifier = 2;
+ break;
+ case k59_IconIndiceWeaponWand:
+ modifier = 1;
+ break;
+ case k60_IconIndiceWeaponTeowand:
+ modifier = 6;
+ break;
+ case k61_IconIndiceWeaponYewStaff:
+ modifier = 4;
+ break;
+ case k62_IconIndiceWeaponStaffOfManarStaffOfIrra:
+ modifier = 10;
+ break;
+ case k63_IconIndiceWeaponSnakeStaffCrossOfNeta:
+ modifier = 8;
+ break;
+ case k64_IconIndiceWeaponTheConduitSerpentStaff:
+ modifier = 16;
+ break;
+ case k65_IconIndiceWeaponDragonSpit:
+ modifier = 7;
+ break;
+ case k66_IconIndiceWeaponSceptreOfLyf:
+ modifier = 5;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ } else if (slotIndex == k4_ChampionSlotLegs) {
+ if (iconIndex == k142_IconIndiceArmourPowertowers) {
+ statIndex = k1_ChampionStatStrength;
+ modifier = 10;
+ }
+ } else if (slotIndex == k2_ChampionSlotHead) {
+ switch (iconIndex) {
+ case k104_IconIndiceArmourCrownOfNerra:
+ statIndex = k3_ChampionStatWisdom;
+ modifier = 10;
+ break;
+ case k140_IconIndiceArmourDexhelm:
+ statIndex = k2_ChampionStatDexterity;
+ modifier = 10;
+ break;
+ default:
+ break;
+ }
+ } else if (slotIndex == k3_ChampionSlotTorso) {
+ switch (iconIndex) {
+ case k141_IconIndiceArmourFlamebain:
+ statIndex = k6_ChampionStatAntifire;
+ modifier = 12;
+ break;
+ case k81_IconIndiceArmourCloakOfNight:
+ statIndex = k2_ChampionStatDexterity;
+ modifier = 8;
+ break;
+ default:
+ break;
+ }
+ } else if (slotIndex == k10_ChampionSlotNeck) {
+ switch (iconIndex) {
+ case k10_IconIndiceJunkJewelSymalUnequipped:
+ case k11_IconIndiceJunkJewelSymalEquipped:
+ statIndex = k5_ChampionStatAntimagic;
+ modifier = 15;
+ break;
+ case k81_IconIndiceArmourCloakOfNight:
+ statIndex = k2_ChampionStatDexterity;
+ modifier = 8;
+ break;
+ case k122_IconIndiceJunkMoonstone:
+ statIndex = k8_ChampionStatMana;
+ modifier = 3;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (modifier) {
+ modifier *= modifierFactor;
+ //statIndex is set when modifier is set
+ if (statIndex == k8_ChampionStatMana) {
+ champ->_maxMana += modifier;
+ } else if (statIndex < k6_ChampionStatAntifire + 1) {
+ for (uint16 statValIndex = k0_ChampionStatMaximum; statValIndex <= k2_ChampionStatMinimum; ++statValIndex) {
+ champ->getStatistic((ChampionStatisticType)statIndex, (ChampionStatisticValue)statValIndex) += modifier;
+ }
+ }
+ }
+}
+
+bool ChampionMan::f295_hasObjectIconInSlotBoxChanged(int16 slotBoxIndex, Thing thing) {
+ ObjectMan &objMan = *_vm->_objectMan;
+
+ IconIndice currIconIndex = objMan.f39_getIconIndexInSlotBox(slotBoxIndex);
+ if (((currIconIndex < k32_IconIndiceWeaponDagger) && (currIconIndex >= k0_IconIndiceJunkCompassNorth))
+ || ((currIconIndex >= k148_IconIndicePotionMaPotionMonPotion) && (currIconIndex <= k163_IconIndicePotionWaterFlask))
+ || (currIconIndex == k195_IconIndicePotionEmptyFlask)) {
+ IconIndice newIconIndex = objMan.f33_getIconIndex(thing);
+ if (newIconIndex != currIconIndex) {
+ if ((slotBoxIndex < k8_SlotBoxInventoryFirstSlot) && !_g420_mousePointerHiddenToDrawChangedObjIconOnScreen) {
+ _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = true;
+ _vm->_eventMan->f77_hideMouse();
+ }
+ objMan.f38_drawIconInSlotBox(slotBoxIndex, newIconIndex);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ChampionMan::f296_drawChangedObjectIcons() {
+ InventoryMan &invMan = *_vm->_inventoryMan;
+ ObjectMan &objMan = *_vm->_objectMan;
+ MenuMan &menuMan = *_vm->_menuMan;
+
+ uint16 invChampOrdinal = invMan._g432_inventoryChampionOrdinal;
+ if (_g299_candidateChampionOrdinal && !invChampOrdinal)
+ return;
+
+ _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = false;
+ IconIndice leaderHandObjIconIndex = _g413_leaderHandObjectIconIndex;
+
+ if (((leaderHandObjIconIndex < k32_IconIndiceWeaponDagger) && (leaderHandObjIconIndex >= k0_IconIndiceJunkCompassNorth)) // < instead of <= is correct
+ || ((leaderHandObjIconIndex >= k148_IconIndicePotionMaPotionMonPotion) && (leaderHandObjIconIndex <= k163_IconIndicePotionWaterFlask))
+ || (leaderHandObjIconIndex == k195_IconIndicePotionEmptyFlask)) {
+ IconIndice iconIndex = objMan.f33_getIconIndex(_g414_leaderHandObject);
+ if (iconIndex != leaderHandObjIconIndex) {
+ _g420_mousePointerHiddenToDrawChangedObjIconOnScreen = true;
+ _vm->_eventMan->f77_hideMouse();
+ objMan.f36_extractIconFromBitmap(iconIndex, objMan._g412_objectIconForMousePointer);
+ _vm->_eventMan->f68_setPointerToObject(_vm->_objectMan->_g412_objectIconForMousePointer);
+ _g413_leaderHandObjectIconIndex = iconIndex;
+ objMan.f34_drawLeaderObjectName(_g414_leaderHandObject);
+ }
+ }
+
+ for (uint16 slotBoxIndex = 0; slotBoxIndex < (_g305_partyChampionCount * 2); ++slotBoxIndex) {
+ int16 champIndex = slotBoxIndex >> 1;
+ if (invChampOrdinal == _vm->M0_indexToOrdinal(champIndex))
+ continue;
+
+ if (f295_hasObjectIconInSlotBoxChanged(slotBoxIndex, _gK71_champions[champIndex].getSlot((ChampionSlot)M70_handSlotIndex(slotBoxIndex)))
+ && (M70_handSlotIndex(slotBoxIndex) == k1_ChampionSlotActionHand)) {
+
+ menuMan.f386_drawActionIcon((ChampionIndex)champIndex);
+ }
+ }
+
+ if (invChampOrdinal) {
+ Champion *champ = &_gK71_champions[_vm->M1_ordinalToIndex(invChampOrdinal)];
+ Thing *thing = &champ->getSlot(k0_ChampionSlotReadyHand);
+ uint16 drawViewport = 0;
+
+ for (uint16 slotIndex = k0_ChampionSlotReadyHand; slotIndex < k30_ChampionSlotChest_1; slotIndex++, thing++) {
+ uint16 objIconChanged = f295_hasObjectIconInSlotBoxChanged(slotIndex + k8_SlotBoxInventoryFirstSlot, *thing) ? 1 : 0;
+ drawViewport |= objIconChanged;
+ if (objIconChanged && (slotIndex == k1_ChampionSlotActionHand)) {
+ menuMan.f386_drawActionIcon((ChampionIndex)_vm->M1_ordinalToIndex(invChampOrdinal));
+ }
+ }
+
+ if (invMan._g424_panelContent = k4_PanelContentChest) {
+ thing = invMan._g425_chestSlots;
+ for (int16 slotIndex = 0; slotIndex < 8; ++slotIndex, thing++) {
+ drawViewport |= (f295_hasObjectIconInSlotBoxChanged(slotIndex + k38_SlotBoxChestFirstSlot, *thing) ? 1 : 0);
+ }
+ }
+
+ if (drawViewport) {
+ champ->setAttributeFlag(k0x4000_ChampionAttributeViewport, true);
+ f292_drawChampionState((ChampionIndex)_vm->M1_ordinalToIndex(invChampOrdinal));
+ }
+ }
+
+ if (_g420_mousePointerHiddenToDrawChangedObjIconOnScreen)
+ _vm->_eventMan->f78_showMouse();
+}
+
+void ChampionMan::f301_addObjectInSlot(ChampionIndex champIndex, Thing thing, ChampionSlot slotIndex) {
+ InventoryMan &invMan = *_vm->_inventoryMan;
+ DungeonMan &dunMan = *_vm->_dungeonMan;
+ ObjectMan &objMan = *_vm->_objectMan;
+ MenuMan &menuMan = *_vm->_menuMan;
+
+ if (thing == Thing::_none)
+ return;
+
+ Champion *champ = &_gK71_champions[champIndex];
+
+ if (slotIndex >= k30_ChampionSlotChest_1) {
+ invMan._g425_chestSlots[slotIndex - k30_ChampionSlotChest_1] = thing;
+ } else {
+ champ->setSlot(slotIndex, thing);
+ }
+
+ champ->_load += dunMan.f140_getObjectWeight(thing);
+ champ->setAttributeFlag(k0x0200_ChampionAttributeLoad, true);
+ IconIndice iconIndex = objMan.f33_getIconIndex(thing);
+ bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == invMan._g432_inventoryChampionOrdinal);
+ f299_applyModifiersToStatistics(champ, slotIndex, iconIndex, 1, thing);
+ uint16 *rawObjPtr = dunMan.f156_getThingData(thing);
+
+ if (slotIndex < k2_ChampionSlotHead) {
+ if (slotIndex == k1_ChampionSlotActionHand) {
+ champ->setAttributeFlag(k0x8000_ChampionAttributeActionHand, true);
+ if (_g506_actingChampionOrdinal == _vm->M0_indexToOrdinal(champIndex))
+ menuMan.f388_clearActingChampion();
+
+ if ((iconIndex >= k30_IconIndiceScrollOpen) && (iconIndex <= k31_IconIndiceScrollClosed)) {
+ ((Scroll *)rawObjPtr)->setClosed(false);
+ f296_drawChangedObjectIcons();
+ }
+ }
+
+ if (iconIndex = k4_IconIndiceWeaponTorchUnlit) {
+ ((Weapon *)rawObjPtr)->setLit(true);
+ _vm->_inventoryMan->f337_setDungeonViewPalette();
+ f296_drawChangedObjectIcons();
+ } else if (isInventoryChampion && (slotIndex == k1_ChampionSlotActionHand) &&
+ ((iconIndex == k144_IconIndiceContainerChestClosed) || ((iconIndex >= k30_IconIndiceScrollOpen) && (iconIndex <= k31_IconIndiceScrollClosed)))) {
+ champ->setAttributeFlag(k0x0800_ChampionAttributePanel, true);
+ }
+ } else if (slotIndex == k10_ChampionSlotNeck) {
+ if ((iconIndex >= k12_IconIndiceJunkIllumuletUnequipped) && (iconIndex <= k13_IconIndiceJunkIllumuletEquipped)) {
+ ((Junk *)rawObjPtr)->setChargeCount(1);
+ _g407_party._magicalLightAmount += g39_LightPowerToLightAmount[2];
+ _vm->_inventoryMan->f337_setDungeonViewPalette();
+ iconIndex = (IconIndice)(iconIndex + 1);
+ } else if ((iconIndex >= k10_IconIndiceJunkJewelSymalUnequipped) && (iconIndex <= k11_IconIndiceJunkJewelSymalEquipped)) {
+ ((Junk *)rawObjPtr)->setChargeCount(1);
+ iconIndex = (IconIndice)(iconIndex + 1);
+ }
+ }
+
+ f291_drawSlot(champIndex, slotIndex);
+ if (isInventoryChampion)
+ champ->setAttributeFlag(k0x4000_ChampionAttributeViewport, true);
+}
+
+int16 ChampionMan::f315_getScentOrdinal(int16 mapX, int16 mapY) {
+ int16 scentIndex = _g407_party._scentCount;
+
+ if (scentIndex) {
+ Scent searchedScent;
+ searchedScent.setMapX(mapX);
+ searchedScent.setMapY(mapY);
+ searchedScent.setMapIndex(_vm->_dungeonMan->_g272_currMapIndex);
+ uint16 searchedScentRedEagle = searchedScent.toUint16();
+ Scent *scent = &_g407_party._scents[scentIndex--];
+ do {
+ if ((*(--scent)).toUint16() == searchedScentRedEagle) {
+ return _vm->M0_indexToOrdinal(scentIndex);
+ }
+ } while (scentIndex--);
+ }
+ return 0;
+}
+
+Thing ChampionMan::f298_getObjectRemovedFromLeaderHand() {
+ _g415_leaderEmptyHanded = true;
+ Thing leaderHandObject = _g414_leaderHandObject;
+
+ if (leaderHandObject != Thing::_none) {
+ _g414_leaderHandObject = Thing::_none;
+ _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
+ _vm->_eventMan->f78_showMouse();
+ _vm->_objectMan->f35_clearLeaderObjectName();
+ _vm->_eventMan->f69_setMousePointer();
+ _vm->_eventMan->f77_hideMouse();
+ if (_g411_leaderIndex != kM1_ChampionNone) {
+ _gK71_champions[_g411_leaderIndex]._load -= _vm->_dungeonMan->f140_getObjectWeight(leaderHandObject);
+ setFlag(_gK71_champions[_g411_leaderIndex]._attributes, k0x0200_ChampionAttributeLoad);
+ f292_drawChampionState(_g411_leaderIndex);
+ }
+ }
+ return leaderHandObject;
+}
+
+uint16 ChampionMan::f312_getStrength(int16 champIndex, int16 slotIndex) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ int16 strength = _vm->getRandomNumber(16) + curChampion->_statistics[k1_ChampionStatStrength][k1_ChampionStatCurrent];
+ Thing curThing = curChampion->_slots[slotIndex];
+ uint16 objectWeight = _vm->_dungeonMan->f140_getObjectWeight(curThing);
+ uint16 oneSixteenthMaximumLoad = f309_getMaximumLoad(curChampion) >> 4;
+
+ if (objectWeight <= oneSixteenthMaximumLoad) {
+ strength += objectWeight - 12;
+ } else {
+ int16 loadThreshold = oneSixteenthMaximumLoad + ((oneSixteenthMaximumLoad - 12) >> 1);
+ if (objectWeight <= loadThreshold) {
+ strength += (objectWeight - oneSixteenthMaximumLoad) >> 1;
+ } else {
+ strength -= (objectWeight - loadThreshold) << 1;
+ }
+ }
+ if (curThing.getType() == k5_WeaponThingType) {
+ WeaponInfo *weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
+ strength += weaponInfo->_strength;
+ uint16 skillLevel = 0;
+ uint16 weaponClass = weaponInfo->_class;
+ if ((weaponClass == k0_WeaponClassSwingWeapon) || (weaponClass == k2_WeaponClassDaggerAndAxes)) {
+ skillLevel = f303_getSkillLevel(champIndex, k4_ChampionSkillSwing);
+ }
+ if ((weaponClass != k0_WeaponClassSwingWeapon) && (weaponClass < k16_WeaponClassFirstBow)) {
+ skillLevel += f303_getSkillLevel(champIndex, k10_ChampionSkillThrow);
+ }
+ if ((weaponClass >= k16_WeaponClassFirstBow) && (weaponClass < k112_WeaponClassFirstMagicWeapon)) {
+ skillLevel += f303_getSkillLevel(champIndex, k11_ChampionSkillShoot);
+ }
+ strength += skillLevel << 1;
+ }
+ strength = f306_getStaminaAdjustedValue(curChampion, strength);
+ if (getFlag(curChampion->_wounds, (slotIndex == k0_ChampionSlotReadyHand) ? k0x0001_ChampionWoundReadHand : k0x0002_ChampionWoundActionHand)) {
+ strength >>= 1;
+ }
+ return f26_getBoundedValue(0, strength >> 1, 100);
+}
+
+Thing ChampionMan::f300_getObjectRemovedFromSlot(uint16 champIndex, uint16 slotIndex) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ Thing curThing;
+
+ if (slotIndex >= k30_ChampionSlotChest_1) {
+ curThing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
+ _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1] = Thing::_none;
+ } else {
+ curThing = curChampion->_slots[slotIndex];
+ curChampion->_slots[slotIndex] = Thing::_none;
+ }
+
+ if (curThing == Thing::_none)
+ return Thing::_none;
+
+ bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal);
+ int16 curIconIndex = _vm->_objectMan->f33_getIconIndex(curThing);
+ // Remove object modifiers
+ f299_applyModifiersToStatistics(curChampion, slotIndex, curIconIndex, -1, curThing);
+
+ Weapon *curWeapon = (Weapon *)_vm->_dungeonMan->f156_getThingData(curThing);
+ if (slotIndex == k10_ChampionSlotNeck) {
+ if ((curIconIndex >= k12_IconIndiceJunkIllumuletUnequipped) && (curIconIndex <= k13_IconIndiceJunkIllumuletEquipped)) {
+ ((Junk *)curWeapon)->setChargeCount(0);
+ _g407_party._magicalLightAmount -= g39_LightPowerToLightAmount[2];
+ _vm->_inventoryMan->f337_setDungeonViewPalette();
+ } else if ((curIconIndex >= k10_IconIndiceJunkJewelSymalUnequipped) && (curIconIndex <= k11_IconIndiceJunkJewelSymalEquipped)) {
+ ((Junk *)curWeapon)->setChargeCount(0);
+ }
+ }
+
+ f291_drawSlot(champIndex, slotIndex);
+ if (isInventoryChampion)
+ setFlag(curChampion->_attributes, k0x4000_ChampionAttributeViewport);
+
+ if (slotIndex < k2_ChampionSlotHead) {
+ if (slotIndex == k1_ChampionSlotActionHand) {
+ setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand);
+ if (_g506_actingChampionOrdinal == _vm->M0_indexToOrdinal(champIndex))
+ _vm->_menuMan->f388_clearActingChampion();
+
+ if ((curIconIndex >= k30_IconIndiceScrollOpen) && (curIconIndex <= k31_IconIndiceScrollClosed)) {
+ ((Scroll *)curWeapon)->setClosed(true);
+ f296_drawChangedObjectIcons();
+ }
+ }
+
+ if ((curIconIndex >= k4_IconIndiceWeaponTorchUnlit) && (curIconIndex <= k7_IconIndiceWeaponTorchLit)) {
+ curWeapon->setLit(false);
+ _vm->_inventoryMan->f337_setDungeonViewPalette();
+ f296_drawChangedObjectIcons();
+ }
+
+ if (isInventoryChampion && (slotIndex == k1_ChampionSlotActionHand)) {
+ switch (curIconIndex) {
+ case k144_IconIndiceContainerChestClosed:
+ _vm->_inventoryMan->f334_closeChest();
+ // No break on purpose
+ case k30_IconIndiceScrollOpen:
+ case k31_IconIndiceScrollClosed:
+ setFlag(curChampion->_attributes, k0x0800_ChampionAttributePanel);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ curChampion->_load -= _vm->_dungeonMan->f140_getObjectWeight(curThing);
+ setFlag(curChampion->_attributes, k0x0200_ChampionAttributeLoad);
+ return curThing;
+}
+
+void ChampionMan::f325_decrementStamina(int16 championIndex, int16 decrement) {
+ if (championIndex == kM1_ChampionNone)
+ return;
+
+ Champion *curChampion = &_gK71_champions[championIndex];
+ curChampion->_currStamina -= decrement;
+
+ int16 stamina = curChampion->_currStamina;
+ if (stamina <= 0) {
+ curChampion->_currStamina = 0;
+ f321_addPendingDamageAndWounds_getDamage(championIndex, (-stamina) >> 1, k0x0000_ChampionWoundNone, k0_attackType_NORMAL);
+ } else if (stamina > curChampion->_maxStamina) {
+ curChampion->_currStamina = curChampion->_maxStamina;
+ }
+
+ setFlag(curChampion->_attributes, k0x0200_ChampionAttributeLoad | k0x0100_ChampionAttributeStatistics);
+}
+
+int16 ChampionMan::f321_addPendingDamageAndWounds_getDamage(int16 champIndex, int16 attack, int16 allowedWounds, uint16 attackType) {
+ if (attack <= 0)
+ return 0;
+
+ Champion *curChampion = &_gK71_champions[champIndex];
+ if (!curChampion->_currHealth)
+ return 0;
+
+ bool skipScaling = false;
+ if (attackType != k0_attackType_NORMAL) {
+ uint16 defense = 0;
+ uint16 woundCount = 0;
+ for (int16 woundIndex = k0_ChampionSlotReadyHand; woundIndex <= k5_ChampionSlotFeet; woundIndex++) {
+ if (allowedWounds & (1 << woundIndex)) {
+ woundCount++;
+ defense += f313_getWoundDefense(champIndex, woundIndex | ((attackType == k4_attackType_SHARP) ? k0x8000_maskUseSharpDefense : k0x0000_maskDoNotUseSharpDefense));
+ }
+ }
+ if (woundCount)
+ defense /= woundCount;
+
+ switch (attackType) {
+ case k6_attackType_PSYCHIC:
+ {
+ int16 wisdomFactor = 115 - curChampion->_statistics[k3_ChampionStatWisdom][k1_ChampionStatCurrent];
+ if (wisdomFactor <= 0) {
+ attack = 0;
+ } else {
+ attack = _vm->f30_getScaledProduct(attack, 6, wisdomFactor);
+ }
+
+ skipScaling = true;
+ }
+ break;
+ case k5_attackType_MAGIC:
+ attack = f307_getStatisticAdjustedAttack(curChampion, k5_ChampionStatAntimagic, attack);
+ attack -= _g407_party._spellShieldDefense;
+ skipScaling = true;
+ break;
+ case k1_attackType_FIRE:
+ attack = f307_getStatisticAdjustedAttack(curChampion, k6_ChampionStatAntifire, attack);
+ attack -= _g407_party._fireShieldDefense;
+ break;
+ case k2_attackType_SELF:
+ defense >>= 1;
+ break;
+ default:
+ break;
+ }
+
+ if (!skipScaling) {
+ if (attack <= 0)
+ return 0;
+
+ attack = _vm->f30_getScaledProduct(attack, 6, 130 - defense);
+ }
+ /* BUG0_44
+ A champion may take much more damage than expected after a Black Flame attack or an impact
+ with a Fireball projectile. If the party has a fire shield defense value higher than the fire
+ attack value then the resulting intermediary attack value is negative and damage should be 0.
+ However, the negative value is still used for further computations and the result may be a very
+ high positive attack value which may kill a champion. This can occur only for k1_attackType_FIRE
+ and if attack is negative before calling F0030_MAIN_GetScaledProduct
+ */
+
+ if (attack <= 0)
+ return 0;
+
+ int16 adjustedAttack = f307_getStatisticAdjustedAttack(curChampion, k4_ChampionStatVitality, _vm->getRandomNumber(128) + 10);
+ if (attack > adjustedAttack) {
+ /* BUG0_45
+ This bug is not perceptible because of BUG0_41 that ignores Vitality while determining the
+ probability of being wounded. However if it was fixed, the behavior would be the opposite
+ of what it should: the higher the vitality of a champion, the lower the result of
+ F0307_CHAMPION_GetStatisticAdjustedAttack and the more likely the champion could get
+ wounded (because of more iterations in the loop below)
+ */
+ do {
+ setFlag(*(uint16 *)&_g410_championPendingWounds[champIndex], (1 << _vm->getRandomNumber(8)) & allowedWounds);
+ } while ((attack > (adjustedAttack <<= 1)) && adjustedAttack);
+ }
+
+ if (_g300_partyIsSleeping)
+ f314_wakeUp();
+ }
+ _g409_championPendingDamage[champIndex] += attack;
+ return attack;
+}
+
+int16 ChampionMan::f313_getWoundDefense(int16 champIndex, uint16 woundIndex) {
+ static const byte woundDefenseFactor[6] = {5, 5, 4, 6, 3, 1}; // @ G0050_auc_Graphic562_WoundDefenseFactor
+
+ Champion *curChampion = &_gK71_champions[champIndex];
+ bool useSharpDefense = getFlag(woundIndex, k0x8000_maskUseSharpDefense);
+ if (useSharpDefense)
+ clearFlag(woundIndex, k0x8000_maskUseSharpDefense);
+
+ uint16 armorShieldDefense = 0;
+ for (int16 slotIndex = k0_ChampionSlotReadyHand; slotIndex <= k1_ChampionSlotActionHand; slotIndex++) {
+ Thing curThing = curChampion->_slots[slotIndex];
+ if (curThing.getType() == k6_ArmourThingType) {
+ ArmourInfo *armorInfo = (ArmourInfo *)_vm->_dungeonMan->f156_getThingData(curThing);
+ armorInfo = &g239_ArmourInfo[((Armour *)armorInfo)->getType()];
+ if (getFlag(armorInfo->_attributes, k0x0080_ArmourAttributeIsAShield))
+ armorShieldDefense += ((f312_getStrength(champIndex, slotIndex) + _vm->_dungeonMan->f143_getArmourDefense(armorInfo, useSharpDefense)) * woundDefenseFactor[woundIndex]) >> ((slotIndex == woundIndex) ? 4 : 5);
+ }
+ }
+
+ int16 woundDefense = _vm->getRandomNumber((curChampion->_statistics[k4_ChampionStatVitality][k1_ChampionStatCurrent] >> 3) + 1);
+ if (useSharpDefense)
+ woundDefense >>= 1;
+
+ woundDefense += curChampion->_actionDefense + curChampion->_shieldDefense + _g407_party._shieldDefense + armorShieldDefense;
+ if (woundIndex > k1_ChampionSlotActionHand) {
+ Thing curThing = curChampion->_slots[woundIndex];
+ if (curThing.getType() == k6_ArmourThingType) {
+ ArmourInfo *armourInfo = (ArmourInfo *)_vm->_dungeonMan->f156_getThingData(curThing);
+ woundDefense += _vm->_dungeonMan->f143_getArmourDefense(&g239_ArmourInfo[((Armour *)armourInfo)->getType()], useSharpDefense);
+ }
+ }
+
+ if (getFlag(curChampion->_wounds, 1 << woundIndex))
+ woundDefense -= 8 + _vm->getRandomNumber(4);
+
+ if (_g300_partyIsSleeping)
+ woundDefense >>= 1;
+
+ return f26_getBoundedValue(0, woundDefense >> 1, 100);
+}
+
+uint16 ChampionMan::f307_getStatisticAdjustedAttack(Champion *champ, uint16 statIndex, uint16 attack) {
+ int16 factor = 170 - champ->_statistics[statIndex][k1_ChampionStatCurrent];
+
+ /* BUG0_41
+ The Antifire and Antimagic statistics are completely ignored. The Vitality statistic is ignored
+ against poison and to determine the probability of being wounded. Vitality is still used normally
+ to compute the defense against wounds and the speed of health regeneration. A bug in the Megamax C
+ compiler produces wrong machine code for this statement. It always returns 0 for the current statistic
+ value so that factor = 170 in all cases
+ */
+ if (factor < 16)
+ return attack >> 3;
+
+ return _vm->f30_getScaledProduct(attack, 7, factor);
+}
+
+void ChampionMan::f314_wakeUp() {
+ _vm->_g321_stopWaitingForPlayerInput = true;
+ _g300_partyIsSleeping = false;
+ _vm->_g318_waitForInputMaxVerticalBlankCount = 10;
+ _vm->f22_delay(10);
+ _vm->_displayMan->f98_drawFloorAndCeiling();
+ _vm->_eventMan->_g441_primaryMouseInput = g447_PrimaryMouseInput_Interface;
+ _vm->_eventMan->_g442_secondaryMouseInput = g448_SecondaryMouseInput_Movement;
+ _vm->_eventMan->_g443_primaryKeyboardInput = g458_primaryKeyboardInput_interface;
+ _vm->_eventMan->_g444_secondaryKeyboardInput = g459_secondaryKeyboardInput_movement;
+ _vm->_eventMan->f357_discardAllInput();
+ _vm->_menuMan->f457_drawEnabledMenus();
+}
+
+int16 ChampionMan::f305_getThrowingStaminaCost(Thing thing) {
+ int16 weight = _vm->_dungeonMan->f140_getObjectWeight(thing) >> 1;
+ int16 staminaCost = f26_getBoundedValue<int16>(1, weight, 10);
+
+ while ((weight -= 10) > 0)
+ staminaCost += weight >> 1;
+
+ return staminaCost;
+}
+
+void ChampionMan::f330_disableAction(uint16 champIndex, uint16 ticks) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ int32 updatedEnableActionEventTime = _vm->_g313_gameTime + ticks;
+
+ TimelineEvent curEvent;
+ curEvent._type = k11_TMEventTypeEnableChampionAction;
+ curEvent._priority = champIndex;
+ curEvent._B._slotOrdinal = 0;
+
+ int16 eventIndex = curChampion->_enableActionEventIndex;
+ if (eventIndex >= 0) {
+ int32 currentEnableActionEventTime = M30_time(_vm->_timeline->_g370_events[eventIndex]._mapTime);
+ if (updatedEnableActionEventTime >= currentEnableActionEventTime) {
+ updatedEnableActionEventTime += (currentEnableActionEventTime - _vm->_g313_gameTime) >> 1;
+ } else {
+ updatedEnableActionEventTime = currentEnableActionEventTime + (ticks >> 1);
+ }
+ _vm->_timeline->f237_deleteEvent(eventIndex);
+ } else {
+ setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand | k0x0008_ChampionAttributeDisableAction);
+ f292_drawChampionState((ChampionIndex)champIndex);
+ }
+ M33_setMapAndTime(curEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, updatedEnableActionEventTime);
+ curChampion->_enableActionEventIndex = _vm->_timeline->f238_addEventGetEventIndex(&curEvent);
+}
+
+void ChampionMan::f304_addSkillExperience(uint16 champIndex, uint16 skillIndex, uint16 exp) {
+ if ((skillIndex >= k4_ChampionSkillSwing) && (skillIndex <= k11_ChampionSkillShoot) && (_vm->_projexpl->_g361_lastCreatureAttackTime < _vm->_g313_gameTime - 150))
+ exp >>= 1;
+
+ if (exp) {
+ if (_vm->_dungeonMan->_g269_currMap->_difficulty)
+ exp *= _vm->_dungeonMan->_g269_currMap->_difficulty;
+
+ Champion *curChampion = &_gK71_champions[champIndex];
+ uint16 baseSkillIndex;
+ if (skillIndex >= k4_ChampionSkillSwing)
+ baseSkillIndex = (skillIndex - k4_ChampionSkillSwing) >> 2;
+ else
+ baseSkillIndex = skillIndex;
+
+ uint16 skillLevelBefore = f303_getSkillLevel(champIndex, baseSkillIndex | (k0x4000_IgnoreObjectModifiers | k0x8000_IgnoreTemporaryExperience));
+
+ if ((skillIndex >= k4_ChampionSkillSwing) && (_vm->_projexpl->_g361_lastCreatureAttackTime > _vm->_g313_gameTime - 25))
+ exp <<= 1;
+
+ Skill *curSkill = &curChampion->_skills[skillIndex];
+ curSkill->_experience += exp;
+ if (curSkill->_temporaryExperience < 32000)
+ curSkill->_temporaryExperience += f26_getBoundedValue(1, exp >> 3, 100);
+
+ curSkill = &curChampion->_skills[baseSkillIndex];
+ if (skillIndex >= k4_ChampionSkillSwing)
+ curSkill->_experience += exp;
+
+ uint16 skillLevelAfter = f303_getSkillLevel(champIndex, baseSkillIndex | (k0x4000_IgnoreObjectModifiers | k0x8000_IgnoreTemporaryExperience));
+ if (skillLevelAfter > skillLevelBefore) {
+ int16 newBaseSkillLevel = skillLevelAfter;
+ int16 minorStatIncrease = _vm->getRandomNumber(2);
+ int16 majorStatIncrease = 1 + _vm->getRandomNumber(2);
+ uint16 vitalityAmount = _vm->getRandomNumber(2); /* For Priest skill, the amount is 0 or 1 for all skill levels */
+ if (baseSkillIndex != k2_ChampionSkillPriest) {
+ vitalityAmount &= skillLevelAfter; /* For non Priest skills the amount is 0 for even skill levels. The amount is 0 or 1 for odd skill levels */
+ }
+ curChampion->_statistics[k4_ChampionStatVitality][k0_ChampionStatMaximum] += vitalityAmount;
+ uint16 staminaAmount = curChampion->_maxStamina;
+ curChampion->_statistics[k6_ChampionStatAntifire][k0_ChampionStatMaximum] += _vm->getRandomNumber(2) & ~skillLevelAfter; /* The amount is 0 for odd skill levels. The amount is 0 or 1 for even skill levels */
+ bool increaseManaFl = false;
+ switch (baseSkillIndex) {
+ case k0_ChampionSkillFighter:
+ staminaAmount >>= 4;
+ skillLevelAfter *= 3;
+ curChampion->_statistics[k1_ChampionStatStrength][k0_ChampionStatMaximum] += majorStatIncrease;
+ curChampion->_statistics[k2_ChampionStatDexterity][k0_ChampionStatMaximum] += minorStatIncrease;
+ break;
+ case k1_ChampionSkillNinja:
+ staminaAmount /= 21;
+ skillLevelAfter <<= 1;
+ curChampion->_statistics[k1_ChampionStatStrength][k0_ChampionStatMaximum] += minorStatIncrease;
+ curChampion->_statistics[k2_ChampionStatDexterity][k0_ChampionStatMaximum] += majorStatIncrease;
+ break;
+ case k3_ChampionSkillWizard:
+ staminaAmount >>= 5;
+ curChampion->_maxMana += skillLevelAfter + (skillLevelAfter >> 1);
+ curChampion->_statistics[k3_ChampionStatWisdom][k0_ChampionStatMaximum] += majorStatIncrease;
+ increaseManaFl = true;
+ break;
+ case k2_ChampionSkillPriest:
+ staminaAmount /= 25;
+ curChampion->_maxMana += skillLevelAfter;
+ skillLevelAfter += (skillLevelAfter + 1) >> 1;
+ curChampion->_statistics[k3_ChampionStatWisdom][k0_ChampionStatMaximum] += minorStatIncrease;
+ increaseManaFl = true;
+ break;
+ default:
+ break;
+ }
+ if (increaseManaFl) {
+ if ((curChampion->_maxMana += MIN(_vm->getRandomNumber(4), (uint16)(newBaseSkillLevel - 1))) > 900)
+ curChampion->_maxMana = 900;
+ curChampion->_statistics[k5_ChampionStatAntimagic][k0_ChampionStatMaximum] += _vm->getRandomNumber(3);
+ }
+
+ if ((curChampion->_maxHealth += skillLevelAfter + _vm->getRandomNumber((skillLevelAfter >> 1) + 1)) > 999)
+ curChampion->_maxHealth = 999;
+
+ if ((curChampion->_maxStamina += staminaAmount + _vm->getRandomNumber((staminaAmount >> 1) + 1)) > 9999)
+ curChampion->_maxStamina = 9999;
+
+ setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
+ f292_drawChampionState((ChampionIndex)champIndex);
+ _vm->_textMan->f51_messageAreaPrintLineFeed();
+ Color curChampionColor = g46_ChampionColor[champIndex];
+ _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, curChampion->_name);
+ // TODO: localization
+ _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, " JUST GAINED A ");
+ _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, g417_baseSkillName[baseSkillIndex]);
+ _vm->_textMan->f47_messageAreaPrintMessage(curChampionColor, " LEVEL!");
+ }
+ }
+}
+
+int16 ChampionMan::f324_damageAll_getDamagedChampionCount(uint16 attack, int16 wounds, int16 attackType) {
+ int16 randomMax = (attack >> 3) + 1;
+ uint16 reducedAttack = attack - randomMax;
+ randomMax <<= 1;
+
+ int16 damagedChampionCount = 0;
+ for (int16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++) {
+ // Actual attack is attack +/- (attack / 8)
+ if (f321_addPendingDamageAndWounds_getDamage(championIndex, MAX(1, reducedAttack + _vm->getRandomNumber(randomMax)), wounds, attackType))
+ damagedChampionCount++;
+ }
+
+ return damagedChampionCount;
+}
+
+int16 ChampionMan::f286_getTargetChampionIndex(int16 mapX, int16 mapY, uint16 cell) {
+ if (_g305_partyChampionCount && (M38_distance(mapX, mapY, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY) <= 1)) {
+ signed char orderedCellsToAttack[4];
+ _vm->_groupMan->f229_setOrderedCellsToAttack(orderedCellsToAttack, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, mapX, mapY, cell);
+ for (uint16 i = 0; i < 4; i++) {
+ int16 championIndex = f285_getIndexInCell(orderedCellsToAttack[i]);
+ if (championIndex >= 0)
+ return championIndex;
+ }
+ }
+ return kM1_ChampionNone;
+}
+
+int16 ChampionMan::f311_getDexterity(Champion* champ) {
+ int16 dexterity = _vm->getRandomNumber(8) + champ->_statistics[k2_ChampionStatDexterity][k1_ChampionStatCurrent];
+ dexterity -= ((int32)(dexterity >> 1) * (int32)champ->_load) / f309_getMaximumLoad(champ);
+ if (_g300_partyIsSleeping)
+ dexterity >>= 1;
+
+ return f26_getBoundedValue(1 + _vm->getRandomNumber(8), dexterity >> 1, 100 - _vm->getRandomNumber(8));
+}
+
+bool ChampionMan::f308_isLucky(Champion* champ, uint16 percentage) {
+ if (_vm->getRandomNumber(2) && (_vm->getRandomNumber(100) > percentage))
+ return true;
+
+ unsigned char *curStat = champ->_statistics[k0_ChampionStatLuck];
+ bool isLucky = (_vm->getRandomNumber(curStat[k1_ChampionStatCurrent]) > percentage);
+ curStat[k1_ChampionStatCurrent] = f26_getBoundedValue<char>(curStat[k2_ChampionStatMinimum], curStat[k1_ChampionStatCurrent] + (isLucky ? -2 : 2), curStat[k0_ChampionStatMaximum]);
+ return isLucky;
+}
+
+void ChampionMan::f322_championPoison(int16 champIndex, uint16 attack) {
+ if ((champIndex == kM1_ChampionNone) || (_vm->M0_indexToOrdinal(champIndex) == _g299_candidateChampionOrdinal))
+ return;
+
+ Champion *curChampion = &_gK71_champions[champIndex];
+ f321_addPendingDamageAndWounds_getDamage(champIndex, MAX(1, attack >> 6), k0x0000_ChampionWoundNone, k0_attackType_NORMAL);
+ setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
+ if ((_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) && (_vm->_inventoryMan->_g424_panelContent == k0_PanelContentFoodWaterPoisoned)) {
+ setFlag(curChampion->_attributes, k0x0800_ChampionAttributePanel);
+ }
+
+ if (--attack) {
+ curChampion->_poisonEventCount++;
+ TimelineEvent newEvent;
+ newEvent._type = k75_TMEventTypePoisonChampion;
+ newEvent._priority = champIndex;
+ M33_setMapAndTime(newEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 36);
+ newEvent._B._attack = attack;
+ _vm->_timeline->f238_addEventGetEventIndex(&newEvent);
+ }
+
+ f292_drawChampionState((ChampionIndex)champIndex);
+}
+
+void ChampionMan::f284_setPartyDirection(int16 dir) {
+ if (dir == _vm->_dungeonMan->_g308_partyDir)
+ return;
+
+ int16 L0834_i_Delta = dir - _vm->_dungeonMan->_g308_partyDir;
+ if (L0834_i_Delta < 0)
+ L0834_i_Delta += 4;
+
+ Champion *curChampion = _gK71_champions;
+ for (int16 i = k0_ChampionFirst; i < _g305_partyChampionCount; i++) {
+ curChampion->_cell = (ViewCell)M21_normalizeModulo4(curChampion->_cell + L0834_i_Delta);
+ curChampion->_dir = (Direction)M21_normalizeModulo4(curChampion->_dir + L0834_i_Delta);
+ curChampion++;
+ }
+
+ _vm->_dungeonMan->_g308_partyDir = (Direction)dir;
+ f296_drawChangedObjectIcons();
+}
+
+void ChampionMan::f316_deleteScent(uint16 scentIndex) {
+ uint16 count = --_g407_party._scentCount - scentIndex;
+
+ if (count) {
+ for (uint16 i = 0; i < count; ++i) {
+ _g407_party._scents[scentIndex + i] = _g407_party._scents[scentIndex + i + 1];
+ _g407_party._scentStrengths[scentIndex + i] = _g407_party._scentStrengths[scentIndex + i + 1];
+ }
+ }
+
+ if (scentIndex < _g407_party._firstScentIndex)
+ _g407_party._firstScentIndex--;
+
+ if (scentIndex < _g407_party._lastScentIndex)
+ _g407_party._lastScentIndex--;
+}
+
+void ChampionMan::f317_addScentStrength(int16 mapX, int16 mapY, int32 cycleCount) {
+ int16 scentIndex = _g407_party._scentCount;
+ if (scentIndex) {
+ bool mergeFl = getFlag(cycleCount, k0x8000_mergeCycles);
+ if (mergeFl)
+ clearFlag(cycleCount, k0x8000_mergeCycles);
+
+ Scent newScent; /* BUG0_00 Useless code */
+ newScent.setMapX(mapX); /* BUG0_00 Useless code */
+ newScent.setMapY(mapY); /* BUG0_00 Useless code */
+ newScent.setMapIndex(_vm->_dungeonMan->_g272_currMapIndex); /* BUG0_00 Useless code */
+
+ Scent *curScent = _g407_party._scents; /* BUG0_00 Useless code */
+ bool cycleCountDefined = false;
+ while (scentIndex--) {
+ if (&*curScent++ == &newScent) {
+ if (!cycleCountDefined) {
+ cycleCountDefined = true;
+ if (mergeFl) {
+ cycleCount = MAX<int32>(_g407_party._scentStrengths[scentIndex], cycleCount);
+ } else {
+ cycleCount = MIN<int32>(80, _g407_party._scentStrengths[scentIndex] + cycleCount);
+ }
+ }
+ _g407_party._scentStrengths[scentIndex] = cycleCount;
+ }
+ }
+ }
+}
+
+void ChampionMan::f297_putObjectInLeaderHand(Thing thing, bool setMousePointer) {
+ if (thing == Thing::_none)
+ return;
+
+ _g415_leaderEmptyHanded = false;
+ _vm->_objectMan->f36_extractIconFromBitmap(_g413_leaderHandObjectIconIndex = _vm->_objectMan->f33_getIconIndex(_g414_leaderHandObject = thing), _vm->_objectMan->_g412_objectIconForMousePointer);
+ _vm->_eventMan->f78_showMouse();
+ _vm->_objectMan->f34_drawLeaderObjectName(thing);
+
+ if (setMousePointer)
+ _vm->_g325_setMousePointerToObjectInMainLoop = true;
+ else
+ _vm->_eventMan->f68_setPointerToObject(_vm->_objectMan->_g412_objectIconForMousePointer);
+
+ _vm->_eventMan->f77_hideMouse();
+ if (_g411_leaderIndex != kM1_ChampionNone) {
+ _gK71_champions[_g411_leaderIndex]._load += _vm->_dungeonMan->f140_getObjectWeight(thing);
+ setFlag(_gK71_champions[_g411_leaderIndex]._attributes, k0x0200_ChampionAttributeLoad);
+ f292_drawChampionState(_g411_leaderIndex);
+ }
+}
+
+int16 ChampionMan::f310_getMovementTicks(Champion *champ) {
+ uint16 maximumLoad = f309_getMaximumLoad(champ);
+ uint16 curLoad = champ->_load;
+ uint16 woundTicks;
+ int16 ticks;
+ /* BUG0_72 - Fixed
+ The party moves very slowly even though no champion 'Load' value is drawn in red.
+ When the Load of a champion has exactly the maximum value he can carry then the Load
+ is drawn in yellow but the speed is the same as when the champion is overloaded
+ (when the Load is drawn in red). The comparison operator should be >= instead of >
+ */
+ if (maximumLoad >= curLoad) {
+ ticks = 2;
+ if (((int32)curLoad << 3) > ((int32)maximumLoad * 5))
+ ticks++;
+
+ woundTicks = 1;
+ } else {
+ ticks = 4 + (((curLoad - maximumLoad) << 2) / maximumLoad);
+ woundTicks = 2;
+ }
+
+ if (getFlag(champ->_wounds, k0x0020_ChampionWoundFeet))
+ ticks += woundTicks;
+
+ if (_vm->_objectMan->f33_getIconIndex(champ->_slots[k5_ChampionSlotFeet]) == k194_IconIndiceArmourBootOfSpeed)
+ ticks--;
+
+ return ticks;
+}
+
+bool ChampionMan::f294_isAmmunitionCompatibleWithWeapon(uint16 champIndex, uint16 weaponSlotIndex, uint16 ammunitionSlotIndex) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ Thing curThing = curChampion->_slots[weaponSlotIndex];
+ if (curThing.getType() != k5_WeaponThingType)
+ return false;
+
+ WeaponInfo *weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
+ int16 weaponClass = kM1_WeaponClassNone;
+
+ if ((weaponInfo->_class >= k16_WeaponClassFirstBow) && (weaponInfo->_class <= k31_WeaponClassLastBow))
+ weaponClass = k10_WeaponClassBowAmmunition;
+ else if ((weaponInfo->_class >= k32_WeaponClassFirstSling) && (weaponInfo->_class <= k47_WeaponClassLastSling))
+ weaponClass = k11_WeaponClassSlingAmmunition;
+
+ if (weaponClass == kM1_WeaponClassNone)
+ return false;
+
+ curThing = curChampion->_slots[ammunitionSlotIndex];
+ weaponInfo = _vm->_dungeonMan->f158_getWeaponInfo(curThing);
+ return ((curThing.getType() == k5_WeaponThingType) && (weaponInfo->_class == weaponClass));
+}
+
+void ChampionMan::f293_drawAllChampionStates() {
+ for (int16 i = k0_ChampionFirst; i < _g305_partyChampionCount; i++)
+ f292_drawChampionState((ChampionIndex)i);
+}
+
+void ChampionMan::f283_viAltarRebirth(uint16 champIndex) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ if (f285_getIndexInCell(curChampion->_cell) != kM1_ChampionNone) {
+ uint16 numCell = k0_CellNorthWest;
+ while (f285_getIndexInCell(numCell) != kM1_ChampionNone)
+ numCell++;
+
+ curChampion->_cell = (ViewCell)numCell;
+ }
+
+ uint16 maximumHealth = curChampion->_maxHealth;
+ curChampion->_maxHealth = MAX(25, maximumHealth - (maximumHealth >> 6) - 1);
+ curChampion->_currHealth = curChampion->_maxHealth >> 1;
+ _vm->_menuMan->f393_drawSpellAreaControls(_g514_magicCasterChampionIndex);
+ curChampion->_dir = _vm->_dungeonMan->_g308_partyDir;
+ setFlag(curChampion->_attributes, k0x8000_ChampionAttributeActionHand | k0x1000_ChampionAttributeStatusBox | k0x0400_ChampionAttributeIcon);
+ f292_drawChampionState((ChampionIndex)champIndex);
+}
+
+void ChampionMan::f302_processCommands28to65_clickOnSlotBox(uint16 slotBoxIndex) {
+ uint16 champIndex;
+ uint16 slotIndex;
+
+ if (slotBoxIndex < k8_SlotBoxInventoryFirstSlot) {
+ if (_g299_candidateChampionOrdinal)
+ return;
+
+ champIndex = slotBoxIndex >> 1;
+ if ((champIndex >= _g305_partyChampionCount) || (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) || !_gK71_champions[champIndex]._currHealth)
+ return;
+
+ slotIndex = M70_handSlotIndex(slotBoxIndex);
+ } else {
+ champIndex = _vm->M1_ordinalToIndex(_vm->_inventoryMan->_g432_inventoryChampionOrdinal);
+ slotIndex = slotBoxIndex - k8_SlotBoxInventoryFirstSlot;
+ }
+
+ Thing leaderHandObject = _g414_leaderHandObject;
+ Thing slotThing;
+ if (slotIndex >= k30_ChampionSlotChest_1) {
+ slotThing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
+ } else {
+ slotThing = _gK71_champions[champIndex]._slots[slotIndex];
+ }
+
+ if ((slotThing == Thing::_none) && (leaderHandObject == Thing::_none))
+ return;
+
+ if ((leaderHandObject != Thing::_none) && (!(g237_ObjectInfo[_vm->_dungeonMan->f141_getObjectInfoIndex(leaderHandObject)]._allowedSlots & gSlotMasks[slotIndex])))
+ return;
+
+ _vm->_eventMan->f78_showMouse();
+ if (leaderHandObject != Thing::_none)
+ f298_getObjectRemovedFromLeaderHand();
+
+ if (slotThing != Thing::_none) {
+ f300_getObjectRemovedFromSlot(champIndex, slotIndex);
+ f297_putObjectInLeaderHand(slotThing, false);
+ }
+
+ if (leaderHandObject != Thing::_none)
+ f301_addObjectInSlot((ChampionIndex)champIndex, leaderHandObject, (ChampionSlot)slotIndex);
+
+ f292_drawChampionState((ChampionIndex)champIndex);
+ _vm->_eventMan->f77_hideMouse();
+}
+
+bool ChampionMan::f327_isProjectileSpellCast(uint16 champIndex, Thing thing, int16 kineticEnergy, uint16 requiredManaAmount) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ if (curChampion->_currMana < requiredManaAmount)
+ return false;
+
+ curChampion->_currMana -= requiredManaAmount;
+ setFlag(curChampion->_attributes, k0x0100_ChampionAttributeStatistics);
+ int16 stepEnergy = 10 - MIN(8, curChampion->_maxMana >> 3);
+ if (kineticEnergy < (stepEnergy << 2)) {
+ kineticEnergy += 3;
+ stepEnergy--;
+ }
+
+ f326_championShootProjectile(curChampion, thing, kineticEnergy, 90, stepEnergy);
+ return true; // fix BUG_01
+}
+
+void ChampionMan::f326_championShootProjectile(Champion* champ, Thing thing, int16 kineticEnergy, int16 attack, int16 stepEnergy) {
+ Direction newDirection = champ->_dir;
+ _vm->_projexpl->f212_projectileCreate(thing, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, M21_normalizeModulo4((((champ->_cell - newDirection + 1) & 0x0002) >> 1) + newDirection), newDirection, kineticEnergy, attack, stepEnergy);
+ _vm->_g311_projectileDisableMovementTicks = 4;
+ _vm->_g312_lastProjectileDisabledMovementDirection = newDirection;
+}
+
+void ChampionMan::f320_applyAndDrawPendingDamageAndWounds() {
+ Champion *championPtr = _gK71_champions;
+ for (uint16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++, championPtr++) {
+ int16 pendingWounds = _g410_championPendingWounds[championIndex];
+ setFlag(championPtr->_wounds, pendingWounds);
+ _g410_championPendingWounds[championIndex] = 0;
+ uint16 pendingDamage = _g409_championPendingDamage[championIndex];
+ if (!pendingDamage)
+ continue;
+
+ _g409_championPendingDamage[championIndex] = 0;
+ int16 curHealth = championPtr->_currHealth;
+ if (!curHealth)
+ continue;
+
+ // DEBUG CODE
+ if (_vm->_console->_debugGodmodeHP == false)
+ curHealth -= pendingDamage;
+
+ if (curHealth <= 0) {
+ f319_championKill(championIndex);
+ } else {
+ championPtr->_currHealth = curHealth;
+ setFlag(championPtr->_attributes, k0x0100_ChampionAttributeStatistics);
+ if (pendingWounds) {
+ setFlag(championPtr->_attributes, k0x2000_ChampionAttributeWounds);
+ }
+
+ int16 textPosX = championIndex * k69_ChampionStatusBoxSpacing;
+ int16 textPosY;
+
+ Box blitBox;
+ blitBox._y1 = 0;
+ _vm->_eventMan->f78_showMouse();
+
+ if (_vm->M0_indexToOrdinal(championIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
+ blitBox._y2 = 28;
+ blitBox._x1 = textPosX + 7;
+ blitBox._x2 = blitBox._x1 + 31; /* Box is over the champion portrait in the status box */
+ _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k16_damageToChampionBig), &blitBox, k16_byteWidth, k10_ColorFlesh, 29);
+ // Check the number of digits and sets the position accordingly.
+ if (pendingDamage < 10) // 1 digit
+ textPosX += 21;
+ else if (pendingDamage < 100) // 2 digits
+ textPosX += 18;
+ else // 3 digits
+ textPosX += 15;
+
+ textPosY = 16;
+ } else {
+ blitBox._y2 = 6;
+ blitBox._x1 = textPosX;
+ blitBox._x2 = blitBox._x1 + 47; /* Box is over the champion name in the status box */
+ _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k15_damageToChampionSmallIndice), &blitBox, k24_byteWidth, k10_ColorFlesh, 7);
+ // Check the number of digits and sets the position accordingly.
+ if (pendingDamage < 10) // 1 digit
+ textPosX += 19;
+ else if (pendingDamage < 100) // 2 digits
+ textPosX += 16;
+ else //3 digits
+ textPosX += 13;
+
+ textPosY = 5;
+ }
+ _vm->_textMan->f53_printToLogicalScreen(textPosX, textPosY, k15_ColorWhite, k8_ColorRed, f288_getStringFromInteger(pendingDamage, false, 3).c_str());
+
+ int16 eventIndex = championPtr->_hideDamageReceivedIndex;
+ if (eventIndex == -1) {
+ TimelineEvent newEvent;
+ newEvent._type = k12_TMEventTypeHideDamageReceived;
+ M33_setMapAndTime(newEvent._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
+ newEvent._priority = championIndex;
+ championPtr->_hideDamageReceivedIndex = _vm->_timeline->f238_addEventGetEventIndex(&newEvent);
+ } else {
+ TimelineEvent *curEvent = &_vm->_timeline->_g370_events[eventIndex];
+ M33_setMapAndTime(curEvent->_mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
+ _vm->_timeline->f236_fixChronology(_vm->_timeline->f235_getIndex(eventIndex));
+ }
+ f292_drawChampionState((ChampionIndex)championIndex);
+ _vm->_eventMan->f77_hideMouse();
+ }
+ }
+}
+
+void ChampionMan::f319_championKill(uint16 champIndex) {
+ Champion *curChampion = &_gK71_champions[champIndex];
+ curChampion->_currHealth = 0;
+ setFlag(curChampion->_attributes, k0x1000_ChampionAttributeStatusBox);
+ if (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
+ if (_vm->_g331_pressingEye) {
+ _vm->_g331_pressingEye = false;
+ _vm->_eventMan->_g597_ignoreMouseMovements = false;
+ if (!_g415_leaderEmptyHanded) {
+ _vm->_objectMan->f34_drawLeaderObjectName(_g414_leaderHandObject);
+ }
+ _vm->_eventMan->_g587_hideMousePointerRequestCount = 1;
+ _vm->_eventMan->f77_hideMouse();
+ } else if (_vm->_g333_pressingMouth) {
+ _vm->_g333_pressingMouth = false;
+ _vm->_eventMan->_g597_ignoreMouseMovements = false;
+ _vm->_eventMan->_g587_hideMousePointerRequestCount = 1;
+ _vm->_eventMan->f77_hideMouse();
+ }
+ _vm->_inventoryMan->f355_toggleInventory(k4_ChampionCloseInventory);
+ }
+ f318_dropAllObjects(champIndex);
+ Thing unusedThing = _vm->_dungeonMan->f166_getUnusedThing(k0x8000_championBones | k10_JunkThingType);
+ uint16 curCell = 0;
+ if (unusedThing != Thing::_none) {
+ Junk *L0966_ps_Junk = (Junk *)_vm->_dungeonMan->f156_getThingData(unusedThing);
+ L0966_ps_Junk->setType(k5_JunkTypeBones);
+ L0966_ps_Junk->setDoNotDiscard(true);
+ L0966_ps_Junk->setChargeCount(champIndex);
+ curCell = curChampion->_cell;
+ _vm->_moveSens->f267_getMoveResult(M15_thingWithNewCell(unusedThing, curCell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
+ }
+ curChampion->_symbolStep = 0;
+ curChampion->_symbols[0] = '\0';
+ curChampion->_dir = _vm->_dungeonMan->_g308_partyDir;
+ curChampion->_maximumDamageReceived = 0;
+ uint16 curChampionIconIndex = M26_championIconIndex(curCell, _vm->_dungeonMan->_g308_partyDir);
+ if (_vm->M0_indexToOrdinal(curChampionIconIndex) == _vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap) {
+ _vm->_eventMan->_g598_mousePointerBitmapUpdated = true;
+ _vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap = _vm->M0_indexToOrdinal(kM1_ChampionNone);
+ warning(false, "IGNORED CODE:G0592_B_BuildMousePointerScreenAreaRequested = true");
+ }
+
+ if (curChampion->_poisonEventCount)
+ f323_unpoison(champIndex);
+
+ _vm->_displayMan->_g578_useByteBoxCoordinates = false;
+ _vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[curChampionIconIndex << 2], k0_ColorBlack);
+ f292_drawChampionState((ChampionIndex)champIndex);
+
+ int16 aliveChampionIndex;
+ for (aliveChampionIndex = k0_ChampionFirst, curChampion = _gK71_champions; aliveChampionIndex < _g305_partyChampionCount; aliveChampionIndex++, curChampion++) {
+ if (curChampion->_currHealth)
+ break;
+ }
+
+ if (aliveChampionIndex == _g305_partyChampionCount) { /* BUG0_43 The game does not end if the last living champion in the party is killed while looking at a candidate champion in a portrait. The condition to end the game when the whole party is killed is not true because the code considers the candidate champion as alive (in the loop above) */
+ _g303_partyDead = true;
+ return;
+ }
+
+ if (champIndex == _g411_leaderIndex)
+ _vm->_eventMan->f368_commandSetLeader((ChampionIndex)aliveChampionIndex);
+
+ if (champIndex == _g514_magicCasterChampionIndex)
+ _vm->_menuMan->f394_setMagicCasterAndDrawSpellArea(aliveChampionIndex);
+ else
+ _vm->_menuMan->f393_drawSpellAreaControls(_g514_magicCasterChampionIndex);
+}
+
+void ChampionMan::f318_dropAllObjects(uint16 champIndex) {
+ static const int16 slotDropOrder[30] = {
+ k5_ChampionSlotFeet,
+ k4_ChampionSlotLegs,
+ k9_ChampionSlotQuiverLine_2_2,
+ k8_ChampionSlotQuiverLine_1_2,
+ k7_ChampionSlotQuiverLine_2_1,
+ k12_ChampionSlotQuiverLine_1_1,
+ k6_ChampionSlotPouch_2,
+ k11_ChampionSlotPouch_1,
+ k3_ChampionSlotTorso,
+ k13_ChampionSlotBackpackLine_1_1,
+ k14_ChampionSlotBackpackLine_2_2,
+ k15_ChampionSlotBackpackLine_2_3,
+ k16_ChampionSlotBackpackLine_2_4,
+ k17_ChampionSlotBackpackLine_2_5,
+ k18_ChampionSlotBackpackLine_2_6,
+ k19_ChampionSlotBackpackLine_2_7,
+ k20_ChampionSlotBackpackLine_2_8,
+ k21_ChampionSlotBackpackLine_2_9,
+ k22_ChampionSlotBackpackLine_1_2,
+ k23_ChampionSlotBackpackLine_1_3,
+ k24_ChampionSlotBackpackLine_1_4,
+ k25_ChampionSlotBackpackLine_1_5,
+ k26_ChampionSlotBackpackLine_1_6,
+ k27_ChampionSlotBackpackLine_1_7,
+ k28_ChampionSlotBackpackLine_1_8,
+ k29_ChampionSlotBackpackLine_1_9,
+ k10_ChampionSlotNeck,
+ k2_ChampionSlotHead,
+ k0_ChampionSlotReadyHand,
+ k1_ChampionSlotActionHand
+ };
+
+ uint16 curCell = _gK71_champions[champIndex]._cell;
+ for (uint16 slotIndex = k0_ChampionSlotReadyHand; slotIndex < k30_ChampionSlotChest_1; slotIndex++) {
+ Thing curThing = f300_getObjectRemovedFromSlot(champIndex, slotDropOrder[slotIndex]);
+ if (curThing != Thing::_none)
+ _vm->_moveSens->f267_getMoveResult(M15_thingWithNewCell(curThing, curCell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
+ }
+}
+
+void ChampionMan::f323_unpoison(int16 champIndex) {
+ if (champIndex == kM1_ChampionNone)
+ return;
+
+ TimelineEvent *eventPtr = _vm->_timeline->_g370_events;
+ for (uint16 eventIndex = 0; eventIndex < _vm->_timeline->_g369_eventMaxCount; eventPtr++, eventIndex++) {
+ if ((eventPtr->_type == k75_TMEventTypePoisonChampion) && (eventPtr->_priority == champIndex))
+ _vm->_timeline->f237_deleteEvent(eventIndex);
+ }
+ _gK71_champions[champIndex]._poisonEventCount = 0;
+}
+
+void ChampionMan::f331_applyTimeEffects() {
+ if (!_g305_partyChampionCount)
+ return;
+
+ Scent checkScent;
+ checkScent.setMapX(_vm->_dungeonMan->_g306_partyMapX);
+ checkScent.setMapY(_vm->_dungeonMan->_g307_partyMapY);
+ checkScent.setMapIndex(_vm->_dungeonMan->_g309_partyMapIndex);
+
+ for (byte loopScentIndex = 0; loopScentIndex + 1 < _g407_party._scentCount; loopScentIndex++) {
+ if (&_g407_party._scents[loopScentIndex] != &checkScent) {
+ _g407_party._scentStrengths[loopScentIndex] = MAX(0, _g407_party._scentStrengths[loopScentIndex] - 1);
+ if (!_g407_party._scentStrengths[loopScentIndex] && !loopScentIndex) {
+ f316_deleteScent(0);
+ continue;
+ }
+ }
+ }
+
+ uint16 gameTime = _vm->_g313_gameTime & 0xFFFF;
+ uint16 timeCriteria = (((gameTime & 0x0080) + ((gameTime & 0x0100) >> 2)) + ((gameTime & 0x0040) << 2)) >> 2;
+ Champion *championPtr = _gK71_champions;
+ for (uint16 championIndex = k0_ChampionFirst; championIndex < _g305_partyChampionCount; championIndex++, championPtr++) {
+ if (championPtr->_currHealth && (_vm->M0_indexToOrdinal(championIndex) != _g299_candidateChampionOrdinal)) {
+ uint16 wizardSkillLevel = f303_getSkillLevel(championIndex, k3_ChampionSkillWizard) + f303_getSkillLevel(championIndex, k2_ChampionSkillPriest);
+ if ((championPtr->_currMana < championPtr->_maxMana)
+ && (timeCriteria < championPtr->_statistics[k3_ChampionStatWisdom][k1_ChampionStatCurrent] + wizardSkillLevel)) {
+ int16 manaGain = championPtr->_maxMana / 40;
+ if (_g300_partyIsSleeping)
+ manaGain <<= 1;
+
+ manaGain++;
+ f325_decrementStamina(championIndex, manaGain * MAX(7, 16 - wizardSkillLevel));
+ championPtr->_currMana += MIN<int16>(manaGain, championPtr->_maxMana - championPtr->_currMana);
+ } else if (championPtr->_currMana > championPtr->_maxMana)
+ championPtr->_currMana--;
+
+ for (int16 idx = k19_ChampionSkillWater; idx >= k0_ChampionSkillFighter; idx--) {
+ if (championPtr->_skills[idx]._temporaryExperience > 0)
+ championPtr->_skills[idx]._temporaryExperience--;
+ }
+ uint16 staminaGainCycleCount = 4;
+ int16 staminaMagnitude = championPtr->_maxStamina;
+ while (championPtr->_currStamina < (staminaMagnitude >>= 1))
+ staminaGainCycleCount += 2;
+
+ int16 staminaLoss = 0;
+ int16 staminaAmount = f26_getBoundedValue(1, (championPtr->_maxStamina >> 8) - 1, 6);
+ if (_g300_partyIsSleeping)
+ staminaAmount <<= 1;
+
+ int32 compDelay = _vm->_g313_gameTime - _vm->_projexpl->_g362_lastPartyMovementTime;
+ if (compDelay > 80) {
+ staminaAmount++;
+ if (compDelay > 250)
+ staminaAmount++;
+ }
+ do {
+ bool staminaAboveHalf = (staminaGainCycleCount <= 4);
+ if (championPtr->_food < -512) {
+ if (staminaAboveHalf) {
+ staminaLoss += staminaAmount;
+ championPtr->_food -= 2;
+ }
+ } else {
+ if (championPtr->_food >= 0)
+ staminaLoss -= staminaAmount;
+
+ championPtr->_food -= staminaAboveHalf ? 2 : staminaGainCycleCount >> 1;
+ }
+ if (championPtr->_water < -512) {
+ if (staminaAboveHalf) {
+ staminaLoss += staminaAmount;
+ championPtr->_water -= 1;
+ }
+ } else {
+ if (championPtr->_water >= 0)
+ staminaLoss -= staminaAmount;
+
+ championPtr->_water -= staminaAboveHalf ? 1 : staminaGainCycleCount >> 2;
+ }
+ } while (--staminaGainCycleCount && ((championPtr->_currStamina - staminaLoss) < championPtr->_maxStamina));
+ f325_decrementStamina(championIndex, staminaLoss);
+ if (championPtr->_food < -1024)
+ championPtr->_food = -1024;
+
+ if (championPtr->_water < -1024)
+ championPtr->_water = -1024;
+
+ if ((championPtr->_currHealth < championPtr->_maxHealth) && (championPtr->_currStamina >= (championPtr->_maxStamina >> 2)) && (timeCriteria < (championPtr->_statistics[k4_ChampionStatVitality][k1_ChampionStatCurrent] + 12))) {
+ int16 healthGain = (championPtr->_maxHealth >> 7) + 1;
+ if (_g300_partyIsSleeping)
+ healthGain <<= 1;
+
+ if (_vm->_objectMan->f33_getIconIndex(championPtr->_slots[k10_ChampionSlotNeck]) == k121_IconIndiceJunkEkkhardCross)
+ healthGain += (healthGain >> 1) + 1;
+
+ championPtr->_currHealth += MIN(healthGain, (int16)(championPtr->_maxHealth - championPtr->_currHealth));
+ }
+ if (!((int)_vm->_g313_gameTime & (_g300_partyIsSleeping ? 63 : 255))) {
+ for (uint16 i = k0_ChampionStatLuck; i <= k6_ChampionStatAntifire; i++) {
+ byte *curStatistic = championPtr->_statistics[i];
+ uint16 statisticMaximum = curStatistic[k0_ChampionStatMaximum];
+ if (curStatistic[k1_ChampionStatCurrent] < statisticMaximum)
+ curStatistic[k1_ChampionStatCurrent]++;
+ else if (curStatistic[k1_ChampionStatCurrent] > statisticMaximum)
+ curStatistic[k1_ChampionStatCurrent] -= curStatistic[k1_ChampionStatCurrent] / statisticMaximum;
+ }
+ }
+ if (!_g300_partyIsSleeping && (championPtr->_dir != _vm->_dungeonMan->_g308_partyDir) && (_vm->_projexpl->_g361_lastCreatureAttackTime + 60 < _vm->_g313_gameTime)) {
+ championPtr->_dir = _vm->_dungeonMan->_g308_partyDir;
+ championPtr->_maximumDamageReceived = 0;
+ setFlag(championPtr->_attributes, k0x0400_ChampionAttributeIcon);
+ }
+ setFlag(championPtr->_attributes, k0x0100_ChampionAttributeStatistics);
+ if (_vm->M0_indexToOrdinal(championIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
+ if (_vm->_g333_pressingMouth || _vm->_g331_pressingEye || (_vm->_inventoryMan->_g424_panelContent == k0_PanelContentFoodWaterPoisoned)) {
+ setFlag(championPtr->_attributes, k0x0800_ChampionAttributePanel);
+ }
+ }
+ }
+ }
+ f293_drawAllChampionStates();
+}
+
+void ChampionMan::save2_PartyPart(Common::OutSaveFile* file) {
+ for (uint16 i = 0; i < 4; ++i) {
+ Champion *champ = &_gK71_champions[i];
+ file->writeUint16BE(champ->_attributes);
+ file->writeUint16BE(champ->_wounds);
+ for (uint16 y = 0; y < 7; ++y)
+ for (uint16 x = 0; x < 3; ++x)
+ file->writeByte(champ->_statistics[y][x]);
+ for (uint16 j = 0; j < 30; ++j)
+ file->writeUint16BE(champ->_slots[j].toUint16());
+ for (uint16 j = 0; j < 20; ++j) {
+ file->writeSint16BE(champ->_skills[j]._temporaryExperience);
+ file->writeSint32BE(champ->_skills[j]._experience);
+ }
+ for (uint16 j = 0; j < 8; ++j)
+ file->writeByte(champ->_name[j]);
+ for (uint16 j = 0; j < 20; ++j)
+ file->writeByte(champ->_title[j]);
+ file->writeUint16BE(champ->_dir);
+ file->writeUint16BE(champ->_cell);
+ file->writeUint16BE(champ->_actionIndex);
+ file->writeUint16BE(champ->_symbolStep);
+ for (uint16 j = 0; j < 5; ++j)
+ file->writeByte(champ->_symbols[j]);
+ file->writeUint16BE(champ->_directionMaximumDamageReceived);
+ file->writeUint16BE(champ->_maximumDamageReceived);
+ file->writeUint16BE(champ->_poisonEventCount);
+ file->writeSint16BE(champ->_enableActionEventIndex);
+ file->writeSint16BE(champ->_hideDamageReceivedIndex);
+ file->writeSint16BE(champ->_currHealth);
+ file->writeSint16BE(champ->_maxHealth);
+ file->writeSint16BE(champ->_currStamina);
+ file->writeSint16BE(champ->_maxStamina);
+ file->writeSint16BE(champ->_currMana);
+ file->writeSint16BE(champ->_maxMana);
+ file->writeSint16BE(champ->_actionDefense);
+ file->writeSint16BE(champ->_food);
+ file->writeSint16BE(champ->_water);
+ file->writeUint16BE(champ->_load);
+ file->writeSint16BE(champ->_shieldDefense);
+ for (uint16 j = 0; j < 928; ++j)
+ file->writeByte(champ->_portrait[j]);
+ }
+
+ Party &party = _g407_party;
+ file->writeSint16BE(party._magicalLightAmount);
+ file->writeByte(party._event73Count_ThievesEye);
+ file->writeByte(party._event79Count_Footprints);
+ file->writeSint16BE(party._shieldDefense);
+ file->writeSint16BE(party._fireShieldDefense);
+ file->writeSint16BE(party._spellShieldDefense);
+ file->writeByte(party._scentCount);
+ file->writeByte(party._freezeLifeTicks);
+ file->writeByte(party._firstScentIndex);
+ file->writeByte(party._lastScentIndex);
+ for (uint16 i = 0; i < 24; ++i)
+ file->writeUint16BE(party._scents[i].toUint16());
+ for (uint16 i = 0; i < 24; ++i)
+ file->writeByte(party._scentStrengths[i]);
+ file->writeByte(party._event71Count_Invisibility);
+}
+
+void ChampionMan::load2_PartyPart(Common::InSaveFile* file) {
+ for (uint16 i = 0; i < 4; ++i) {
+ Champion *champ = &_gK71_champions[i];
+ champ->_attributes = file->readUint16BE();
+ champ->_wounds = file->readUint16BE();
+ for (uint16 y = 0; y < 7; ++y)
+ for (uint16 x = 0; x < 3; ++x)
+ champ->_statistics[y][x] = file->readByte();
+ for (uint16 j = 0; j < 30; ++j)
+ champ->_slots[j] = Thing(file->readUint16BE());
+ for (uint16 j = 0; j < 20; ++j) {
+ champ->_skills[j]._temporaryExperience = file->readSint16BE();
+ champ->_skills[j]._experience = file->readSint32BE();
+ }
+ for (uint16 j = 0; j < 8; ++j)
+ champ->_name[j] = file->readByte();
+ for (uint16 j = 0; j < 20; ++j)
+ champ->_title[j] = file->readByte();
+ champ->_dir = (Direction)file->readUint16BE();
+ champ->_cell = (ViewCell)file->readUint16BE();
+ champ->_actionIndex = (ChampionAction)file->readUint16BE();
+ champ->_symbolStep = file->readUint16BE();
+ for (uint16 j = 0; j < 5; ++j)
+ champ->_symbols[j] = file->readByte();
+ champ->_directionMaximumDamageReceived = file->readUint16BE();
+ champ->_maximumDamageReceived = file->readUint16BE();
+ champ->_poisonEventCount = file->readUint16BE();
+ champ->_enableActionEventIndex = file->readSint16BE();
+ champ->_hideDamageReceivedIndex = file->readSint16BE();
+ champ->_currHealth = file->readSint16BE();
+ champ->_maxHealth = file->readSint16BE();
+ champ->_currStamina = file->readSint16BE();
+ champ->_maxStamina = file->readSint16BE();
+ champ->_currMana = file->readSint16BE();
+ champ->_maxMana = file->readSint16BE();
+ champ->_actionDefense = file->readSint16BE();
+ champ->_food = file->readSint16BE();
+ champ->_water = file->readSint16BE();
+ champ->_load = file->readUint16BE();
+ champ->_shieldDefense = file->readSint16BE();
+ for (uint16 j = 0; j < 928; ++j)
+ champ->_portrait[j] = file->readByte();
+ }
+
+ Party &party = _g407_party;
+ party._magicalLightAmount = file->readSint16BE();
+ party._event73Count_ThievesEye = file->readByte();
+ party._event79Count_Footprints = file->readByte();
+ party._shieldDefense = file->readSint16BE();
+ party._fireShieldDefense = file->readSint16BE();
+ party._spellShieldDefense = file->readSint16BE();
+ party._scentCount = file->readByte();
+ party._freezeLifeTicks = file->readByte();
+ party._firstScentIndex = file->readByte();
+ party._lastScentIndex = file->readByte();
+ for (uint16 i = 0; i < 24; ++i)
+ party._scents[i] = Scent(file->readUint16BE());
+ for (uint16 i = 0; i < 24; ++i)
+ party._scentStrengths[i] = file->readByte();
+ party._event71Count_Invisibility = file->readByte();
+}
+
+ChampionIndex ChampionMan::f285_getIndexInCell(int16 cell) {
+ for (uint16 i = 0; i < _g305_partyChampionCount; ++i) {
+ if ((_gK71_champions[i]._cell == cell) && _gK71_champions[i]._currHealth)
+ return (ChampionIndex)i;
+ }
+
+ return kM1_ChampionNone;
+}
+
+void ChampionMan::f278_resetDataToStartGame() {
+ if (!_vm->_g298_newGame) {
+ Thing L0787_T_Thing;
+ if ((L0787_T_Thing = _g414_leaderHandObject) == Thing::_none) {
+ _g415_leaderEmptyHanded = true;
+ _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
+ _vm->_eventMan->f69_setMousePointer();
+ } else {
+ f297_putObjectInLeaderHand(L0787_T_Thing, true); /* This call will add the weight of the leader hand object to the Load of the leader a first time */
+ }
+ Champion *L0788_ps_Champion = _gK71_champions;
+ int16 L0785_i_ChampionIndex;
+ for (L0785_i_ChampionIndex = k0_ChampionFirst; L0785_i_ChampionIndex < _g305_partyChampionCount; L0785_i_ChampionIndex++, L0788_ps_Champion++) {
+ clearFlag(L0788_ps_Champion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
+ setFlag(L0788_ps_Champion->_attributes, k0x8000_ChampionAttributeActionHand | k0x1000_ChampionAttributeStatusBox | k0x0400_ChampionAttributeIcon);
+ }
+ f293_drawAllChampionStates();
+ if ((L0785_i_ChampionIndex = _g411_leaderIndex) != kM1_ChampionNone) {
+ _g411_leaderIndex = kM1_ChampionNone;
+ _vm->_eventMan->f368_commandSetLeader((ChampionIndex)L0785_i_ChampionIndex);
+ }
+ if ((L0785_i_ChampionIndex = _g514_magicCasterChampionIndex) != kM1_ChampionNone) {
+ _g514_magicCasterChampionIndex = kM1_ChampionNone;
+ _vm->_menuMan->f394_setMagicCasterAndDrawSpellArea(L0785_i_ChampionIndex);
+ }
+ return;
+ }
+
+ _g414_leaderHandObject = Thing::_none;
+ _g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
+ _g415_leaderEmptyHanded = true;
+}
+
+void ChampionMan::f280_addCandidateChampionToParty(uint16 championPortraitIndex) {
+ if (!_g415_leaderEmptyHanded)
+ return;
+
+ if (_g305_partyChampionCount == 4)
+ return;
+
+ uint16 previousPartyChampionCount = _g305_partyChampionCount;
+ Champion *championPtr = &_gK71_champions[previousPartyChampionCount];
+ championPtr->resetToZero();
+ // Strangerke - TODO: Check if the new code is possible to run on the older version (example: the portraits could be missing in the data)
+ _vm->_displayMan->_g578_useByteBoxCoordinates = true;
+ _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k26_ChampionPortraitsIndice), championPtr->_portrait, gBoxChampionPortrait, M27_getChampionPortraitX(championPortraitIndex), M28_getChampionPortraitY(championPortraitIndex), k128_byteWidth, k16_byteWidth, kM1_ColorNoTransparency);
+ championPtr->_actionIndex = k255_ChampionActionNone;
+ championPtr->_enableActionEventIndex = -1;
+ championPtr->_hideDamageReceivedIndex = -1;
+ championPtr->_dir = _vm->_dungeonMan->_g308_partyDir;
+ uint16 viewCell = k0_ViewCellFronLeft;
+ while (f285_getIndexInCell(M21_normalizeModulo4(viewCell + _vm->_dungeonMan->_g308_partyDir)) != kM1_ChampionNone)
+ viewCell++;
+
+ championPtr->_cell = (ViewCell)M21_normalizeModulo4(viewCell + _vm->_dungeonMan->_g308_partyDir);
+ championPtr->_attributes = k0x0400_ChampionAttributeIcon;
+ championPtr->_directionMaximumDamageReceived = _vm->_dungeonMan->_g308_partyDir;
+ championPtr->_food = 1500 + _vm->getRandomNumber(256);
+ championPtr->_water = 1500 + _vm->getRandomNumber(256);
+ for (int16 slotIdx = k0_ChampionSlotReadyHand; slotIdx < k30_ChampionSlotChest_1; slotIdx++)
+ championPtr->_slots[slotIdx] = Thing::_none;
+
+ Thing curThing = _vm->_dungeonMan->f161_getSquareFirstThing(_vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
+ while (curThing.getType() != k2_TextstringType)
+ curThing = _vm->_dungeonMan->f159_getNextThing(curThing);
+
+ char L0807_ac_DecodedChampionText[77];
+ char *decodedStringPtr = L0807_ac_DecodedChampionText;
+ _vm->_dungeonMan->f168_decodeText(decodedStringPtr, curThing, (TextType)(k2_TextTypeScroll | k0x8000_DecodeEvenIfInvisible));
+
+ uint16 charIdx = 0;
+ char tmpChar;
+ while ((tmpChar = *decodedStringPtr++) != '\n')
+ championPtr->_name[charIdx++] = tmpChar;
+
+ championPtr->_name[charIdx] = '\0';
+ charIdx = 0;
+ bool championTitleCopiedFl = false;
+ for (;;) { /*_Infinite loop_*/
+ tmpChar = *decodedStringPtr++;
+ if (tmpChar == '\n') { /* New line */
+ if (championTitleCopiedFl)
+ break;
+ championTitleCopiedFl = true;
+ } else
+ championPtr->_title[charIdx++] = tmpChar;
+ }
+ championPtr->_title[charIdx] = '\0';
+ if (*decodedStringPtr++ == 'M')
+ setFlag(championPtr->_attributes, k0x0010_ChampionAttributeMale);
+
+ decodedStringPtr++;
+ championPtr->_currHealth = championPtr->_maxHealth = f279_getDecodedValue(decodedStringPtr, 4);
+ decodedStringPtr += 4;
+ championPtr->_currStamina = championPtr->_maxStamina = f279_getDecodedValue(decodedStringPtr, 4);
+ decodedStringPtr += 4;
+ championPtr->_currMana = championPtr->_maxMana = f279_getDecodedValue(decodedStringPtr, 4);
+ decodedStringPtr += 4;
+ decodedStringPtr++;
+ for (int16 statIdx = k0_ChampionStatLuck; statIdx <= k6_ChampionStatAntifire; statIdx++) {
+ championPtr->_statistics[statIdx][k2_ChampionStatMinimum] = 30;
+ championPtr->_statistics[statIdx][k1_ChampionStatCurrent] = championPtr->_statistics[statIdx][k0_ChampionStatMaximum] = f279_getDecodedValue(decodedStringPtr, 2);
+ decodedStringPtr += 2;
+ }
+ championPtr->_statistics[k0_ChampionStatLuck][k2_ChampionStatMinimum] = 10;
+ decodedStringPtr++;
+ for (uint16 skillIdx = k4_ChampionSkillSwing; skillIdx <= k19_ChampionSkillWater; skillIdx++) {
+ int skillValue = *decodedStringPtr++ - 'A';
+ if (skillValue > 0)
+ championPtr->_skills[skillIdx]._experience = 125L << skillValue;
+ }
+ for (uint16 skillIdx = k0_ChampionSkillFighter; skillIdx <= k3_ChampionSkillWizard; skillIdx++) {
+ int32 baseSkillExperience = 0;
+ int16 hiddenSkillIndex = (skillIdx + 1) << 2;
+ for (uint16 hiddenIdx = 0; hiddenIdx < 4; hiddenIdx++)
+ baseSkillExperience += championPtr->_skills[hiddenSkillIndex + hiddenIdx]._experience;
+
+ championPtr->_skills[skillIdx]._experience = baseSkillExperience;
+ }
+ _g299_candidateChampionOrdinal = previousPartyChampionCount + 1;
+ if (++_g305_partyChampionCount == 1) {
+ _vm->_eventMan->f368_commandSetLeader(k0_ChampionFirst);
+ _vm->_menuMan->_g508_refreshActionArea = true;
+ } else {
+ _vm->_menuMan->f388_clearActingChampion();
+ _vm->_menuMan->f386_drawActionIcon((ChampionIndex)(_g305_partyChampionCount - 1));
+ }
+
+ int16 curMapX = _vm->_dungeonMan->_g306_partyMapX;
+ int16 curMapY = _vm->_dungeonMan->_g307_partyMapY;
+ uint16 championObjectsCell = returnOppositeDir(_vm->_dungeonMan->_g308_partyDir);
+ curMapX += _vm->_dirIntoStepCountEast[_vm->_dungeonMan->_g308_partyDir], curMapY += _vm->_dirIntoStepCountNorth[_vm->_dungeonMan->_g308_partyDir];
+ curThing = _vm->_dungeonMan->f161_getSquareFirstThing(curMapX, curMapY);
+ int16 slotIdx = k13_ChampionSlotBackpackLine_1_1;
+ while (curThing != Thing::_endOfList) {
+ ThingType thingType = curThing.getType();
+ if ((thingType > k3_SensorThingType) && (curThing.getCell() == championObjectsCell)) {
+ int16 objectAllowedSlots = g237_ObjectInfo[_vm->_dungeonMan->f141_getObjectInfoIndex(curThing)]._allowedSlots;
+ uint16 curSlotIndex;
+ switch (thingType) {
+ case k6_ArmourThingType: {
+ bool skipCheck = false;
+ for (curSlotIndex = k2_ChampionSlotHead; curSlotIndex <= k5_ChampionSlotFeet; curSlotIndex++) {
+ if (objectAllowedSlots & gSlotMasks[curSlotIndex]) {
+ skipCheck = true;
+ break;
+ }
+ }
+
+ if (skipCheck)
+ break;
+
+ if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
+ curSlotIndex = k10_ChampionSlotNeck;
+ else
+ curSlotIndex = slotIdx++;
+
+ break;
+ }
+ case k5_WeaponThingType:
+ if (championPtr->_slots[k1_ChampionSlotActionHand] == Thing::_none)
+ curSlotIndex = k1_ChampionSlotActionHand;
+ else if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
+ curSlotIndex = k10_ChampionSlotNeck;
+ else
+ curSlotIndex = slotIdx++;
+ break;
+ case k7_ScrollThingType:
+ case k8_PotionThingType:
+ if (championPtr->_slots[k11_ChampionSlotPouch_1] == Thing::_none)
+ curSlotIndex = k11_ChampionSlotPouch_1;
+ else if (championPtr->_slots[k6_ChampionSlotPouch_2] == Thing::_none)
+ curSlotIndex = k6_ChampionSlotPouch_2;
+ else if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
+ curSlotIndex = k10_ChampionSlotNeck;
+ else
+ curSlotIndex = slotIdx++;
+ break;
+ case k9_ContainerThingType:
+ case k10_JunkThingType:
+ if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
+ curSlotIndex = k10_ChampionSlotNeck;
+ else
+ curSlotIndex = slotIdx++;
+
+ break;
+ default:
+ break;
+ }
+
+ while (championPtr->_slots[curSlotIndex] != Thing::_none) {
+ if ((objectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (championPtr->_slots[k10_ChampionSlotNeck] == Thing::_none))
+ curSlotIndex = k10_ChampionSlotNeck;
+ else
+ curSlotIndex = slotIdx++;
+ }
+ f301_addObjectInSlot((ChampionIndex)previousPartyChampionCount, curThing, (ChampionSlot)curSlotIndex);
+ }
+ curThing = _vm->_dungeonMan->f159_getNextThing(curThing);
+ }
+ _vm->_inventoryMan->f355_toggleInventory((ChampionIndex)previousPartyChampionCount);
+ _vm->_menuMan->f456_drawDisabledMenu();;
+}
+
+void ChampionMan::f287_drawChampionBarGraphs(ChampionIndex champIndex) {
+ int16 barGraphHeights[3];
+ Champion *champ = &_gK71_champions[champIndex];
+ int16 barGraphIdx = 0;
+ if (champ->_currHealth > 0) {
+ int32 barGraphHeight = (((int32)champ->_currHealth << 10) * 25) / champ->_maxHealth;
+ barGraphHeights[barGraphIdx++] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
+ } else
+ barGraphHeights[barGraphIdx++] = 0;
+
+ if (champ->_currStamina > 0) {
+ int32 barGraphHeight = (((int32)champ->_currStamina << 10) * 25) / champ->_maxStamina;
+ barGraphHeights[barGraphIdx++] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
+ } else
+ barGraphHeights[barGraphIdx++] = 0;
+
+ if (champ->_currMana > 0) {
+ if (champ->_currMana > champ->_maxMana)
+ barGraphHeights[barGraphIdx] = 25;
+ else {
+ int32 barGraphHeight = (((int32)champ->_currMana << 10) * 25) / champ->_maxMana;
+ barGraphHeights[barGraphIdx] = (barGraphHeight >> 10) + ((barGraphHeight & 0x000003FF) ? 1 : 0);
+ }
+ } else {
+ barGraphHeights[barGraphIdx] = 0;
+ }
+ _vm->_eventMan->f78_showMouse();
+
+ // Strangerke - TO CHECK: if portraits, maybe the old (assembly) code is required for older versions
+ Box box;
+ box._x1 = champIndex * k69_ChampionStatusBoxSpacing + 46;
+ box._x2 = box._x1 + 3;
+ box._y1 = 2;
+ box._y2 = 26;
+ for (int16 barGraphIndex = 0; barGraphIndex < 3; barGraphIndex++) {
+ int16 barGraphHeight = barGraphHeights[barGraphIndex];
+ if (barGraphHeight < 25) {
+ box._y1 = 2;
+ box._y2 = 27 - barGraphHeight;
+ _vm->_displayMan->D24_fillScreenBox(box, k12_ColorDarkestGray);
+ }
+ if (barGraphHeight) {
+ box._y1 = 27 - barGraphHeight;
+ box._y2 = 26;
+ _vm->_displayMan->D24_fillScreenBox(box, g46_ChampionColor[champIndex]);
+ }
+ box._x1 += 7;
+ box._x2 += 7;
+ }
+ _vm->_eventMan->f77_hideMouse();
+}
+
+
+uint16 ChampionMan::f306_getStaminaAdjustedValue(Champion *champ, int16 val) {
+ int16 currStamina = champ->_currStamina;
+ int16 halfMaxStamina = champ->_maxStamina / 2;
+ if (currStamina < halfMaxStamina) {
+ warning(false, "Possible undefined behavior in the original code");
+ val /= 2;
+ return val + ((uint32)val * (uint32)currStamina) / halfMaxStamina;
+ }
+ return val;
+}
+
+uint16 ChampionMan::f309_getMaximumLoad(Champion *champ) {
+ uint16 maximumLoad = champ->getStatistic(k1_ChampionStatStrength, k1_ChampionStatCurrent) * 8 + 100;
+ maximumLoad = f306_getStaminaAdjustedValue(champ, maximumLoad);
+ int16 wounds = champ->getWounds();
+ if (wounds)
+ maximumLoad -= maximumLoad >> (champ->getWoundsFlag(k0x0010_ChampionWoundLegs) ? 2 : 3);
+
+ if (_vm->_objectMan->f33_getIconIndex(champ->getSlot(k5_ChampionSlotFeet)) == k119_IconIndiceArmourElvenBoots)
+ maximumLoad += maximumLoad * 16;
+
+ maximumLoad += 9;
+ maximumLoad -= maximumLoad % 10;
+ return maximumLoad;
+}
+
+void ChampionMan::f292_drawChampionState(ChampionIndex champIndex) {
+ int16 championStatusBoxX = champIndex * k69_ChampionStatusBoxSpacing;
+ Champion *curChampion = &_gK71_champions[champIndex];
+ uint16 championAttributes = curChampion->_attributes;
+ if (!getFlag(championAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand))
+ return;
+
+ bool isInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal);
+ _vm->_displayMan->_g578_useByteBoxCoordinates = false;
+ _vm->_eventMan->f78_showMouse();
+ if (getFlag(championAttributes, k0x1000_ChampionAttributeStatusBox)) {
+ Box box;
+ box._y1 = 0;
+ box._y2 = 28;
+ box._x1 = championStatusBoxX;
+ box._x2 = box._x1 + 66;
+ if (curChampion->_currHealth) {
+ _vm->_displayMan->D24_fillScreenBox(box, k12_ColorDarkestGray);
+ int16 nativeBitmapIndices[3];
+ for (uint16 i = 0; i < 3; ++i)
+ nativeBitmapIndices[i] = 0;
+
+ uint16 borderCount = 0;
+ if (_g407_party._fireShieldDefense > 0)
+ nativeBitmapIndices[borderCount++] = k38_BorderPartyFireshieldIndice;
+
+ if (_g407_party._spellShieldDefense > 0)
+ nativeBitmapIndices[borderCount++] = k39_BorderPartySpellshieldIndice;
+
+ if ((_g407_party._shieldDefense > 0) || curChampion->_shieldDefense)
+ nativeBitmapIndices[borderCount++] = k37_BorderPartyShieldIndice;
+
+ while (borderCount--)
+ _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndices[borderCount]), &box, k40_byteWidth, k10_ColorFlesh, 29);
+
+ if (isInventoryChampion) {
+ _vm->_inventoryMan->f354_drawStatusBoxPortrait(champIndex);
+ setFlag(championAttributes, k0x0100_ChampionAttributeStatistics);
+ } else
+ setFlag(championAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x2000_ChampionAttributeWounds | k0x8000_ChampionAttributeActionHand);
+ } else {
+ _vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k8_StatusBoxDeadChampion), &box, k40_byteWidth, kM1_ColorNoTransparency, 29);
+ _vm->_textMan->f53_printToLogicalScreen(championStatusBoxX + 1, 5, k13_ColorLightestGray, k1_ColorDarkGary, curChampion->_name);
+ _vm->_menuMan->f386_drawActionIcon(champIndex);
+
+ clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
+ _vm->_eventMan->f77_hideMouse();
+ return;
+ }
+ }
+ if (!(curChampion->_currHealth)) {
+ clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
+ _vm->_eventMan->f77_hideMouse();
+ return;
+ }
+
+ if (getFlag(championAttributes, k0x0080_ChampionAttributeNameTitle)) {
+ Color nameColor = (champIndex == _g411_leaderIndex) ? k9_ColorGold : k13_ColorLightestGray;
+ if (isInventoryChampion) {
+ char *championName = curChampion->_name;
+ _vm->_textMan->f52_printToViewport(3, 7, nameColor, championName);
+ int16 championTitleX = 6 * strlen(championName) + 3;
+ char titleFirstCharacter = curChampion->_title[0];
+ if ((titleFirstCharacter != ',') && (titleFirstCharacter != ';') && (titleFirstCharacter != '-'))
+ championTitleX += 6;
+
+ _vm->_textMan->f52_printToViewport(championTitleX, 7, nameColor, curChampion->_title);
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ } else {
+ Box box;
+ box._y1 = 0;
+ box._y2 = 6;
+ box._x1 = championStatusBoxX;
+ box._x2 = box._x1 + 42;
+ _vm->_displayMan->D24_fillScreenBox(box, k1_ColorDarkGary);
+ _vm->_textMan->f53_printToLogicalScreen(championStatusBoxX + 1, 5, nameColor, k1_ColorDarkGary, curChampion->_name);
+ }
+ }
+ if (getFlag(championAttributes, k0x0100_ChampionAttributeStatistics)) {
+ f287_drawChampionBarGraphs(champIndex);
+ if (isInventoryChampion) {
+ f290_drawHealthStaminaManaValues(curChampion);
+ int16 nativeBitmapIndex;
+ if ((curChampion->_food < 0) || (curChampion->_water < 0) || (curChampion->_poisonEventCount))
+ nativeBitmapIndex = k34_SlotBoxWoundedIndice;
+ else
+ nativeBitmapIndex = k33_SlotBoxNormalIndice;
+
+ _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex), gBoxMouth, k16_byteWidth, k12_ColorDarkestGray, 18);
+ nativeBitmapIndex = k33_SlotBoxNormalIndice;
+ for (int i = k1_ChampionStatStrength; i <= k6_ChampionStatAntifire; i++) {
+ if ((curChampion->_statistics[i][k1_ChampionStatCurrent] < curChampion->_statistics[i][k0_ChampionStatMaximum])) {
+ nativeBitmapIndex = k34_SlotBoxWoundedIndice;
+ break;
+ }
+ }
+ _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex), gBoxEye, k16_byteWidth, k12_ColorDarkestGray, 18);
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ }
+ }
+ if (getFlag(championAttributes, k0x2000_ChampionAttributeWounds)) {
+ for (int i = isInventoryChampion ? k5_ChampionSlotFeet : k1_ChampionSlotActionHand; i >= k0_ChampionSlotReadyHand; i--)
+ f291_drawSlot(champIndex, i);
+
+ if (isInventoryChampion)
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ }
+ if (getFlag(championAttributes, k0x0200_ChampionAttributeLoad) && isInventoryChampion) {
+ uint16 maxLoad = f309_getMaximumLoad(curChampion);
+ Color loadColor;
+ if (curChampion->_load > maxLoad)
+ loadColor = k8_ColorRed;
+ else if (((long)curChampion->_load << 3) > ((long)maxLoad * 5))
+ loadColor = k11_ColorYellow;
+ else
+ loadColor = k13_ColorLightestGray;
+
+ _vm->_textMan->f52_printToViewport(104, 132, loadColor, "LOAD ");
+ maxLoad = curChampion->_load / 10;
+ strcpy(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, true, 3).c_str());
+ strcat(_vm->_g353_stringBuildBuffer, ".");
+ maxLoad = curChampion->_load - (maxLoad * 10);
+ strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, false, 1).c_str());
+ strcat(_vm->_g353_stringBuildBuffer, "/");
+ maxLoad = (f309_getMaximumLoad(curChampion) + 5) / 10;
+ strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(maxLoad, true, 3).c_str());
+ strcat(_vm->_g353_stringBuildBuffer, " KG");
+ _vm->_textMan->f52_printToViewport(148, 132, loadColor, _vm->_g353_stringBuildBuffer);
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ }
+ uint16 championIconIndex = M26_championIconIndex(curChampion->_cell, _vm->_dungeonMan->_g308_partyDir);
+ if (getFlag(championAttributes, k0x0400_ChampionAttributeIcon) && (_vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap != _vm->M0_indexToOrdinal(championIconIndex))) {
+ _vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[championIconIndex], g46_ChampionColor[champIndex]);
+ _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k28_ChampionIcons), _vm->_displayMan->_g348_bitmapScreen, g54_BoxChampionIcons[championIconIndex], M26_championIconIndex(curChampion->_dir, _vm->_dungeonMan->_g308_partyDir) * 19, 0, k40_byteWidth, k160_byteWidthScreen, k12_ColorDarkestGray, 14, k200_heightScreen);
+ }
+ if (getFlag(championAttributes, k0x0800_ChampionAttributePanel) && isInventoryChampion) {
+ if (_vm->_g333_pressingMouth)
+ _vm->_inventoryMan->f345_drawPanelFoodWaterPoisoned();
+ else if (_vm->_g331_pressingEye) {
+ if (_g415_leaderEmptyHanded)
+ _vm->_inventoryMan->f351_drawChampionSkillsAndStatistics();
+ } else
+ _vm->_inventoryMan->f347_drawPanel();
+
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ }
+ if (getFlag(championAttributes, k0x8000_ChampionAttributeActionHand)) {
+ f291_drawSlot(champIndex, k1_ChampionSlotActionHand);
+ _vm->_menuMan->f386_drawActionIcon(champIndex);
+ if (isInventoryChampion)
+ setFlag(championAttributes, k0x4000_ChampionAttributeViewport);
+ }
+ if (getFlag(championAttributes, k0x4000_ChampionAttributeViewport))
+ _vm->_displayMan->f97_drawViewport(k0_viewportNotDungeonView);
+
+ clearFlag(curChampion->_attributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand);
+ _vm->_eventMan->f77_hideMouse();
+}
+
+uint16 ChampionMan::M26_championIconIndex(int16 val, Direction dir) {
+ return ((val + 4 - dir) & 0x3);
+}
+
+void ChampionMan::f290_drawHealthStaminaManaValues(Champion* champ) {
+ f289_drawHealthOrStaminaOrManaValue(116, champ->_currHealth, champ->_maxHealth);
+ f289_drawHealthOrStaminaOrManaValue(124, champ->_currStamina, champ->_maxStamina);
+ f289_drawHealthOrStaminaOrManaValue(132, champ->_currMana, champ->_maxMana);
+}
+
+void ChampionMan::f291_drawSlot(uint16 champIndex, int16 slotIndex) {
+ int16 nativeBitmapIndex = -1;
+ Champion *champ = &_gK71_champions[champIndex];
+ bool isInventoryChamp = (_vm->_inventoryMan->_g432_inventoryChampionOrdinal == _vm->M0_indexToOrdinal(champIndex));
+
+ uint16 slotBoxIndex;
+ if (!isInventoryChamp) {
+ // If drawing a slot for a champion other than the champion whose inventory is open
+ if ((slotIndex > k1_ChampionSlotActionHand) || (_g299_candidateChampionOrdinal == _vm->M0_indexToOrdinal(champIndex)))
+ return;
+ slotBoxIndex = (champIndex << 1) + slotIndex;
+ } else
+ slotBoxIndex = k8_SlotBoxInventoryFirstSlot + slotIndex;
+
+ Thing thing;
+ if (slotIndex >= k30_ChampionSlotChest_1)
+ thing = _vm->_inventoryMan->_g425_chestSlots[slotIndex - k30_ChampionSlotChest_1];
+ else
+ thing = champ->getSlot((ChampionSlot)slotIndex);
+
+ SlotBox *slotBox = &_vm->_objectMan->_g30_slotBoxes[slotBoxIndex];
+ Box box;
+ box._x1 = slotBox->_x - 1;
+ box._y1 = slotBox->_y - 1;
+ box._x2 = box._x1 + 17;
+ box._y2 = box._y1 + 17;
+
+ if (!isInventoryChamp)
+ _vm->_eventMan->f77_hideMouse();
+
+ int16 iconIndex;
+ if (thing == Thing::_none) {
+ if (slotIndex <= k5_ChampionSlotFeet) {
+ iconIndex = k212_IconIndiceReadyHand + (slotIndex << 1);
+ if (champ->getWoundsFlag((ChampionWound)(1 << slotIndex))) {
+ iconIndex++;
+ nativeBitmapIndex = k34_SlotBoxWoundedIndice;
+ } else
+ nativeBitmapIndex = k33_SlotBoxNormalIndice;
+ } else {
+ if ((slotIndex >= k10_ChampionSlotNeck) && (slotIndex <= k13_ChampionSlotBackpackLine_1_1))
+ iconIndex = k208_IconIndiceNeck + (slotIndex - k10_ChampionSlotNeck);
+ else
+ iconIndex = k204_IconIndiceEmptyBox;
+ }
+ } else {
+ iconIndex = _vm->_objectMan->f33_getIconIndex(thing); // BUG0_35
+ if (isInventoryChamp && (slotIndex == k1_ChampionSlotActionHand) && ((iconIndex == k144_IconIndiceContainerChestClosed) || (iconIndex == k30_IconIndiceScrollOpen))) {
+ iconIndex++;
+ } // BUG2_00
+ if (slotIndex <= k5_ChampionSlotFeet) {
+ if (champ->getWoundsFlag((ChampionWound)(1 << slotIndex)))
+ nativeBitmapIndex = k34_SlotBoxWoundedIndice;
+ else
+ nativeBitmapIndex = k33_SlotBoxNormalIndice;
+ }
+ }
+
+ if ((slotIndex == k1_ChampionSlotActionHand) && (_vm->M0_indexToOrdinal(champIndex) == _g506_actingChampionOrdinal))
+ nativeBitmapIndex = k35_SlotBoxActingHandIndice;
+
+ if (nativeBitmapIndex != -1) {
+ _vm->_displayMan->_g578_useByteBoxCoordinates = false;
+ if (isInventoryChamp)
+ _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex),
+ _vm->_displayMan->_g296_bitmapViewport, box, 0, 0, 16, k112_byteWidthViewport, k12_ColorDarkestGray);
+ else
+ _vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(nativeBitmapIndex),
+ _vm->_displayMan->_g348_bitmapScreen, box, 0, 0, 16, k160_byteWidthScreen, k12_ColorDarkestGray);
+ }
+
+ _vm->_objectMan->f38_drawIconInSlotBox(slotBoxIndex, iconIndex);
+
+ if (!isInventoryChamp)
+ _vm->_eventMan->f78_showMouse();
+}
+
+void ChampionMan::f281_renameChampion(Champion* champ) {
+#define k1_RENAME_CHAMPION_NAME 1
+#define k2_RENAME_CHAMPION_TITLE 2
+ static const char underscoreCharacterString[2] = "_";
+ static char renameChampionInputCharacterString[2] = " ";
+ static const char reincarnateSpecialCharacters[6] = {',', '.', ';', ':', ' '};
+
+ Box displayBox;
+ displayBox._y1 = 3;
+ displayBox._y2 = 8;
+ displayBox._x1 = 3;
+ displayBox._x2 = displayBox._x1 + 167;
+
+ _vm->_displayMan->f135_fillBoxBitmap(_vm->_displayMan->_g296_bitmapViewport, displayBox, k12_ColorDarkestGray, k112_byteWidthViewport, k136_heightViewport);
+ _vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k27_PanelRenameChampionIndice), g32_BoxPanel, k72_byteWidth, k4_ColorCyan, 73);
+ _vm->_textMan->f52_printToViewport(177, 58, k13_ColorLightestGray, "_______");
+ _vm->_textMan->f52_printToViewport(105, 76, k13_ColorLightestGray, "___________________");
+ _vm->_eventMan->f78_showMouse();
+ _vm->_displayMan->f97_drawViewport(k0_viewportNotDungeonView);
+ _vm->_eventMan->f67_setMousePointerToNormal(k0_pointerArrow);
+ _vm->_eventMan->f77_hideMouse();
+ uint16 curCharacterIndex = 0;
+ champ->_name[curCharacterIndex] = '\0';
+ champ->_title[0] = '\0';
+ int16 renamedChampionStringMode = k1_RENAME_CHAMPION_NAME;
+ char *renamedChampionString = champ->_name;
+ int16 textPosX = 177;
+ int16 textPosY = 91;
+
+ for (;;) { /*_Infinite loop_*/
+ bool championTitleIsFull = ((renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE) && (curCharacterIndex == 19));
+ if (!championTitleIsFull) {
+ _vm->_eventMan->f78_showMouse();
+ _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k9_ColorGold, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
+ _vm->_eventMan->f77_hideMouse();
+ }
+
+ int16 curCharacter = 256;
+ while (curCharacter == 256) {
+ Common::Event event;
+ Common::EventType eventType = _vm->_eventMan->processInput(&event, &event);
+ _vm->_displayMan->updateScreen();
+ if (_vm->_engineShouldQuit)
+ return;
+ _vm->_displayMan->updateScreen();
+ //_vm->f22_delay(1);
+
+ if (eventType == Common::EVENT_LBUTTONDOWN) {
+ // If left mouse button status has changed
+
+ Common::Point mousePos = _vm->_eventMan->getMousePos();
+ if ((renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE || (curCharacterIndex > 0)) && (mousePos.x >= 197) && (mousePos.x <= 215) && (mousePos.y >= 147) && (mousePos.y <= 155)) { /* Coordinates of 'OK' button */
+ int16 characterIndexBackup = curCharacterIndex;
+ char L0821_ac_ChampionNameBackupString[8];
+ renamedChampionString = champ->_name;
+ strcpy(L0821_ac_ChampionNameBackupString, renamedChampionString);
+ curCharacterIndex = strlen(renamedChampionString);
+ // Replace space characters on the right of the champion name by '\0' characters
+ while (renamedChampionString[--curCharacterIndex] == ' ')
+ renamedChampionString[curCharacterIndex] = '\0';
+
+ bool found = false;
+ for (uint16 idx = k0_ChampionFirst; idx < _g305_partyChampionCount - 1; idx++) {
+ if (!strcmp(_gK71_champions[idx]._name, renamedChampionString)) {
+ // If an existing champion already has the specified name for the new champion
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ if (renamedChampionStringMode == k2_RENAME_CHAMPION_TITLE)
+ renamedChampionString = champ->_title;
+
+ strcpy(renamedChampionString = champ->_name, L0821_ac_ChampionNameBackupString);
+ curCharacterIndex = characterIndexBackup;
+ } else {
+ if ((mousePos.x >= 107) && (mousePos.x <= 175) && (mousePos.y >= 147) && (mousePos.y <= 155)) { /* Coordinates of 'BACKSPACE' button */
+ curCharacter = '\b';
+ break;
+ }
+#if 0
+ if ((mousePos.x < 107) || (mousePos.x > 215) || (mousePos.y < 116) || (mousePos.y > 144)) {/* Coordinates of table of all other characters */
+ //goto T0281023;
+ }
+ if (!((mousePos.x + 4) % 10) || (!((mousePos.y + 5) % 10) && ((mousePos.x < 207) || (mousePos.y != 135)))) {
+ //goto T0281023;
+ }
+#endif
+ curCharacter = 'A' + (11 * ((mousePos.y - 116) / 10)) + ((mousePos.x - 107) / 10);
+ if ((curCharacter == 86) || (curCharacter == 97)) {
+ // The 'Return' button occupies two cells in the table
+ curCharacter = '\r'; /* Carriage return */
+ break;
+ }
+
+ if (curCharacter >= 87)
+ // Compensate for the first cell occupied by 'Return' button
+ curCharacter--;
+
+ if (curCharacter > 'Z')
+ curCharacter = reincarnateSpecialCharacters[(curCharacter - 'Z') - 1];
+
+ break;
+ }
+ } else if (eventType == Common::EVENT_KEYDOWN)
+ curCharacter = event.kbd.ascii;
+ }
+
+ if ((curCharacter >= 'a') && (curCharacter <= 'z'))
+ curCharacter -= 32; // Convert to uppercase
+
+ if (((curCharacter >= 'A') && (curCharacter <= 'Z')) || (curCharacter == '.') || (curCharacter == ',') || (curCharacter == ';') || (curCharacter == ':') || (curCharacter == ' ')) {
+ if ((curCharacter != ' ') || curCharacterIndex != 0) {
+ if (!championTitleIsFull) {
+ renameChampionInputCharacterString[0] = curCharacter;
+ _vm->_eventMan->f78_showMouse();
+ _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, renameChampionInputCharacterString, k200_heightScreen);
+ _vm->_eventMan->f77_hideMouse();
+ renamedChampionString[curCharacterIndex++] = curCharacter;
+ renamedChampionString[curCharacterIndex] = '\0';
+ textPosX += 6;
+ if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex == 7)) {
+ renamedChampionStringMode = k2_RENAME_CHAMPION_TITLE;
+ renamedChampionString = champ->_title;
+ textPosX = 105;
+ textPosY = 109;
+ curCharacterIndex = 0;
+ }
+ }
+ }
+ } else if (curCharacter == '\r') { // Carriage return
+ if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex > 0)) {
+ _vm->_eventMan->f78_showMouse();
+ _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
+ _vm->_eventMan->f77_hideMouse();
+ renamedChampionStringMode = k2_RENAME_CHAMPION_TITLE;
+ renamedChampionString = champ->_title;
+ textPosX = 105;
+ textPosY = 109;
+ curCharacterIndex = 0;
+ }
+ } else if (curCharacter == '\b') { // Backspace
+ if ((renamedChampionStringMode == k1_RENAME_CHAMPION_NAME) && (curCharacterIndex == 0))
+ continue;
+
+ if (!championTitleIsFull) {
+ _vm->_eventMan->f78_showMouse();
+ _vm->_textMan->f40_printTextToBitmap(_vm->_displayMan->_g348_bitmapScreen, k160_byteWidthScreen, textPosX, textPosY, k13_ColorLightestGray, k12_ColorDarkestGray, underscoreCharacterString, k200_heightScreen);
+ _vm->_eventMan->f77_hideMouse();
+ }
+ if (curCharacterIndex == 0) {
+ renamedChampionString = champ->_name;
+ curCharacterIndex = strlen(renamedChampionString) - 1;
+ renamedChampionStringMode = k1_RENAME_CHAMPION_NAME;
+ textPosX = 177 + (curCharacterIndex * 6);
+ textPosY = 91;
+ } else {
+ curCharacterIndex--;
+ textPosX -= 6;
+ }
+ renamedChampionString[curCharacterIndex] = '\0';
+ }
+ }
+}
+
+uint16 ChampionMan::f303_getSkillLevel(int16 champIndex, uint16 skillIndex) {
+ if (_g300_partyIsSleeping)
+ return 1;
+
+ bool ignoreTmpExp = getFlag(skillIndex, k0x8000_IgnoreTemporaryExperience);
+ bool ignoreObjModifiers = getFlag(skillIndex, k0x4000_IgnoreObjectModifiers);
+ clearFlag(skillIndex, k0x8000_IgnoreTemporaryExperience | k0x4000_IgnoreObjectModifiers);
+ Champion *champ = &_gK71_champions[champIndex];
+ Skill *skill = &champ->_skills[skillIndex];
+ int32 exp = skill->_experience;
+ if (!ignoreTmpExp)
+ exp += skill->_temporaryExperience;
+
+ if (skillIndex > k3_ChampionSkillWizard) {
+ // Hidden skill
+ skill = &champ->_skills[(skillIndex - k4_ChampionSkillSwing) >> 2];
+ exp += skill->_experience; // Add experience in the base skill
+ if (!ignoreTmpExp)
+ exp += skill->_temporaryExperience;
+
+ exp >>= 1; // Halve experience to get average of base skill + hidden skill experience
+ }
+ int16 skillLevel = 1;
+ while (exp >= 500) {
+ exp >>= 1;
+ skillLevel++;
+ }
+ if (!ignoreObjModifiers) {
+ int16 actionHandIconIndex = _vm->_objectMan->f33_getIconIndex(champ->_slots[k1_ChampionSlotActionHand]);
+ if (actionHandIconIndex == k27_IconIndiceWeaponTheFirestaff)
+ skillLevel++;
+ else if (actionHandIconIndex == k28_IconIndiceWeaponTheFirestaffComplete)
+ skillLevel += 2;
+
+ int16 neckIconIndex = _vm->_objectMan->f33_getIconIndex(champ->_slots[k10_ChampionSlotNeck]);
+ switch (skillIndex) {
+ case k3_ChampionSkillWizard:
+ if (neckIconIndex == k124_IconIndiceJunkPendantFeral)
+ skillLevel += 1;
+ break;
+ case k13_ChampionSkillHeal:
+ // The skill modifiers of these two objects are not cumulative
+ if ((neckIconIndex == k120_IconIndiceJunkGemOfAges) || (actionHandIconIndex == k66_IconIndiceWeaponSceptreOfLyf))
+ skillLevel += 1;
+ break;
+ case k14_ChampionSkillInfluence:
+ if (neckIconIndex == k122_IconIndiceJunkMoonstone)
+ skillLevel += 1;
+ break;
+ case k15_ChampionSkillDefend:
+ if (neckIconIndex == k121_IconIndiceJunkEkkhardCross)
+ skillLevel += 1;
+ break;
+ default:
+ break;
+ }
+ }
+ return skillLevel;
+}
+
+}
diff --git a/engines/dm/champion.h b/engines/dm/champion.h
index 04ab76988f..a94bdcca8a 100644
--- a/engines/dm/champion.h
+++ b/engines/dm/champion.h
@@ -513,6 +513,7 @@ class ChampionMan {
int16 _g410_championPendingWounds[4]; // @ G0410_ai_ChampionPendingWounds
int16 _g409_championPendingDamage[4]; // @ G0409_ai_ChampionPendingDamage
public:
+
Champion _gK71_champions[4]; // @ K0071_as_Champions
uint16 _g305_partyChampionCount; // @ G0305_ui_PartyChampionCount
bool _g303_partyDead; // @ G0303_B_PartyDead
diff --git a/engines/dm/console.cpp b/engines/dm/console.cpp
index e2618507f9..a1600661bc 100644
--- a/engines/dm/console.cpp
+++ b/engines/dm/console.cpp
@@ -30,6 +30,44 @@
namespace DM {
-Console::Console(DM::DMEngine* vm) : _vm(vm) {}
+Console::Console(DM::DMEngine* vm) : _vm(vm) {
+ _debugGodmodeMana = false;
+ _debugGodmodeHP = false;
+ _debugGodmodeStamina = false;
-} \ No newline at end of file
+ registerCmd("godmode", WRAP_METHOD(Console, Cmd_godmode));
+}
+
+bool Console::Cmd_godmode(int argc, const char** argv) {
+ if (argc < 3)
+ goto argumentError;
+
+ bool setFlagTo;
+
+ if (strcmp("on", argv[2]) == 0) {
+ setFlagTo = true;
+ } else if (strcmp("off", argv[2]) == 0) {
+ setFlagTo = false;
+ } else
+ goto argumentError;
+
+ if (strcmp("all", argv[1]) == 0) {
+ _debugGodmodeHP = _debugGodmodeMana = _debugGodmodeStamina = setFlagTo;
+ } else if (strcmp("mana", argv[1]) == 0) {
+ _debugGodmodeMana = setFlagTo;
+ } else if (strcmp("hp", argv[1]) == 0) {
+ _debugGodmodeHP = setFlagTo;
+ } else if (strcmp("stamina", argv[1]) == 0) {
+ _debugGodmodeStamina = setFlagTo;
+ } else
+ goto argumentError;
+
+ debugPrintf("God mode set for %s to %s\n", argv[1], argv[2]);
+ return true;
+
+argumentError:
+ debugPrintf("Usage: %s <all/mana/hp/stamina> <on/off>\n", argv[0]);
+ return true;
+}
+
+}
diff --git a/engines/dm/console.h b/engines/dm/console.h
index eab2a32e68..0bfcfcef64 100644
--- a/engines/dm/console.h
+++ b/engines/dm/console.h
@@ -36,7 +36,12 @@ class DMEngine;
class Console : public GUI::Debugger {
DMEngine *_vm;
public:
+ bool _debugGodmodeMana;
+ bool _debugGodmodeHP;
+ bool _debugGodmodeStamina;
+
explicit Console(DM::DMEngine *vm);
virtual ~Console(void) {}
+ bool Cmd_godmode(int argc, const char **argv);
};
}
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 2f52b07ff6..8cd5771302 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -367,8 +367,21 @@ void DMEngine::f2_gameloop() {
while (true) {
if (_engineShouldQuit)
return;
+
+ // DEBUG CODE
+ for (int16 i = 0; i < _championMan->_g305_partyChampionCount; ++i) {
+ Champion &champ = _championMan->_gK71_champions[i];
+ if (_console->_debugGodmodeHP)
+ champ._currHealth = champ._maxHealth;
+ if (_console->_debugGodmodeMana)
+ champ._currMana = champ._maxMana;
+ if (_console->_debugGodmodeStamina)
+ champ._currStamina = champ._maxStamina;
+ }
for (;;) {
+
+
if (_g327_newPartyMapIndex != kM1_mapIndexNone) {
f3_processNewPartyMap(_g327_newPartyMapIndex);
_moveSens->f267_getMoveResult(Thing::_party, kM1_MapXNotOnASquare, 0, _dungeonMan->_g306_partyMapX, _dungeonMan->_g307_partyMapY);