mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-15 00:27:31 +00:00
2475 lines
108 KiB
C++
2475 lines
108 KiB
C++
/* 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 {
|
|
|
|
uint16 g38_slotMasks[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 */
|
|
|
|
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;
|
|
_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->_rnd->getRandomNumber(16) + (kineticEnergy >> 1) + skillLevel;
|
|
int16 attack = f26_getBoundedValue((uint16)40, (uint16)((skillLevel << 3) + _vm->_rnd->getRandomNumber(31)), (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->_rnd->getRandomNumber(15) + 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->_rnd->getRandomNumber(127) + 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->_rnd->getRandomNumber(7)) & 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 = _vm->_championMan->_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 = _vm->_championMan->_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 = _vm->_championMan->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 = &_vm->_championMan->_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() {
|
|
int16 L0873_i_ChampionIndex;
|
|
for (L0873_i_ChampionIndex = k0_ChampionFirst; L0873_i_ChampionIndex < _vm->_championMan->_g305_partyChampionCount; L0873_i_ChampionIndex++) {
|
|
_vm->_championMan->f292_drawChampionState((ChampionIndex)L0873_i_ChampionIndex);
|
|
}
|
|
}
|
|
|
|
void ChampionMan::f283_viAltarRebirth(uint16 champIndex) {
|
|
uint16 L0831_ui_Multiple;
|
|
#define AL0831_ui_Cell L0831_ui_Multiple
|
|
#define AL0831_ui_MaximumHealth L0831_ui_Multiple
|
|
Champion* L0832_ps_Champion;
|
|
|
|
L0832_ps_Champion = &_vm->_championMan->_gK71_champions[champIndex];
|
|
if (_vm->_championMan->f285_getIndexInCell(L0832_ps_Champion->_cell) != kM1_ChampionNone) {
|
|
AL0831_ui_Cell = k0_CellNorthWest;
|
|
while (_vm->_championMan->f285_getIndexInCell(AL0831_ui_Cell) != kM1_ChampionNone) {
|
|
AL0831_ui_Cell++;
|
|
}
|
|
L0832_ps_Champion->_cell = (ViewCell)AL0831_ui_Cell;
|
|
}
|
|
AL0831_ui_MaximumHealth = L0832_ps_Champion->_maxHealth;
|
|
L0832_ps_Champion->_currHealth = (L0832_ps_Champion->_maxHealth = MAX(25, AL0831_ui_MaximumHealth - (AL0831_ui_MaximumHealth >> 6) - 1)) >> 1;
|
|
_vm->_menuMan->f393_drawSpellAreaControls(_vm->_championMan->_g514_magicCasterChampionIndex);
|
|
L0832_ps_Champion->_dir = _vm->_dungeonMan->_g308_partyDir;
|
|
setFlag(L0832_ps_Champion->_attributes, k0x8000_ChampionAttributeActionHand | k0x1000_ChampionAttributeStatusBox | k0x0400_ChampionAttributeIcon);
|
|
_vm->_championMan->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 & g38_slotMasks[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) {
|
|
int16 L0991_i_StepEnergy;
|
|
Champion* L0992_ps_Champion;
|
|
|
|
L0992_ps_Champion = &_vm->_championMan->_gK71_champions[champIndex];
|
|
if (L0992_ps_Champion->_currMana < requiredManaAmount) {
|
|
return false;
|
|
}
|
|
L0992_ps_Champion->_currMana -= requiredManaAmount;
|
|
setFlag(L0992_ps_Champion->_attributes, k0x0100_ChampionAttributeStatistics);
|
|
L0991_i_StepEnergy = 10 - MIN(8, L0992_ps_Champion->_maxMana >> 3);
|
|
if (kineticEnergy < (L0991_i_StepEnergy << 2)) {
|
|
kineticEnergy += 3;
|
|
L0991_i_StepEnergy--;
|
|
}
|
|
f326_championShootProjectile(L0992_ps_Champion, thing, kineticEnergy, 90, L0991_i_StepEnergy);
|
|
return true; // fix BUG_01
|
|
}
|
|
|
|
void ChampionMan::f326_championShootProjectile(Champion* champ, Thing thing, int16 kineticEnergy, int16 attack, int16 stepEnergy) {
|
|
uint16 L0990_ui_Direction;
|
|
|
|
L0990_ui_Direction = champ->_dir;
|
|
_vm->_projexpl->f212_projectileCreate(thing, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY, M21_normalizeModulo4((((champ->_cell - L0990_ui_Direction + 1) & 0x0002) >> 1) + L0990_ui_Direction), (direction)L0990_ui_Direction, kineticEnergy, attack, stepEnergy);
|
|
_vm->_g311_projectileDisableMovementTicks = 4;
|
|
_vm->_g312_lastProjectileDisabledMovementDirection = L0990_ui_Direction;
|
|
}
|
|
|
|
void ChampionMan::f320_applyAndDrawPendingDamageAndWounds() {
|
|
uint16 L0967_ui_ChampionIndex;
|
|
uint16 L0968_ui_PendingDamage;
|
|
int16 L0969_i_Multiple;
|
|
#define AL0969_i_Health L0969_i_Multiple
|
|
#define AL0969_i_X L0969_i_Multiple
|
|
#define AL0969_i_EventIndex L0969_i_Multiple
|
|
int16 L0970_i_PendingWounds;
|
|
Champion* L0971_ps_Champion;
|
|
TimelineEvent* L0972_ps_Event;
|
|
int16 L0973_i_Y;
|
|
TimelineEvent L0974_s_Event;
|
|
Box L0975_s_Box;
|
|
|
|
|
|
L0971_ps_Champion = _vm->_championMan->_gK71_champions;
|
|
for (L0967_ui_ChampionIndex = k0_ChampionFirst; L0967_ui_ChampionIndex < _vm->_championMan->_g305_partyChampionCount; L0967_ui_ChampionIndex++, L0971_ps_Champion++) {
|
|
setFlag(L0971_ps_Champion->_wounds, L0970_i_PendingWounds = _g410_championPendingWounds[L0967_ui_ChampionIndex]);
|
|
_g410_championPendingWounds[L0967_ui_ChampionIndex] = 0;
|
|
if (!(L0968_ui_PendingDamage = _g409_championPendingDamage[L0967_ui_ChampionIndex]))
|
|
continue;
|
|
_g409_championPendingDamage[L0967_ui_ChampionIndex] = 0;
|
|
if (!(AL0969_i_Health = L0971_ps_Champion->_currHealth))
|
|
continue;
|
|
if ((AL0969_i_Health = AL0969_i_Health - L0968_ui_PendingDamage) <= 0) {
|
|
_vm->_championMan->f319_championKill(L0967_ui_ChampionIndex);
|
|
} else {
|
|
L0971_ps_Champion->_currHealth = AL0969_i_Health;
|
|
setFlag(L0971_ps_Champion->_attributes, k0x0100_ChampionAttributeStatistics);
|
|
if (L0970_i_PendingWounds) {
|
|
setFlag(L0971_ps_Champion->_attributes, k0x2000_ChampionAttributeWounds);
|
|
}
|
|
AL0969_i_X = L0967_ui_ChampionIndex * k69_ChampionStatusBoxSpacing;
|
|
L0975_s_Box._y1 = 0;
|
|
_vm->_eventMan->f78_showMouse();
|
|
if (_vm->M0_indexToOrdinal(L0967_ui_ChampionIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
|
|
L0975_s_Box._y2 = 28;
|
|
L0975_s_Box._x2 = (L0975_s_Box._x1 = AL0969_i_X + 7) + 31; /* Box is over the champion portrait in the status box */
|
|
_vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k16_damageToChampionBig), &L0975_s_Box, k16_byteWidth, k10_ColorFlesh, 29);
|
|
if (L0968_ui_PendingDamage < 10) { /* 1 digit */
|
|
AL0969_i_X += 21;
|
|
} else {
|
|
if (L0968_ui_PendingDamage < 100) { /* 2 digits */
|
|
AL0969_i_X += 18;
|
|
} else { /* 3 digits */
|
|
AL0969_i_X += 15;
|
|
}
|
|
}
|
|
L0973_i_Y = 16;
|
|
} else {
|
|
L0975_s_Box._y2 = 6;
|
|
L0975_s_Box._x2 = (L0975_s_Box._x1 = AL0969_i_X) + 47; /* Box is over the champion name in the status box */
|
|
_vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k15_damageToChampionSmallIndice), &L0975_s_Box, k24_byteWidth, k10_ColorFlesh, 7);
|
|
if (L0968_ui_PendingDamage < 10) { /* 1 digit */
|
|
AL0969_i_X += 19;
|
|
} else {
|
|
if (L0968_ui_PendingDamage < 100) { /* 2 digits */
|
|
AL0969_i_X += 16;
|
|
} else { /* 3 digits */
|
|
AL0969_i_X += 13;
|
|
}
|
|
}
|
|
L0973_i_Y = 5;
|
|
}
|
|
_vm->_textMan->f53_printToLogicalScreen(AL0969_i_X, L0973_i_Y, k15_ColorWhite, k8_ColorRed, _vm->_championMan->f288_getStringFromInteger(L0968_ui_PendingDamage, false, 3).c_str());
|
|
if ((AL0969_i_EventIndex = L0971_ps_Champion->_hideDamageReceivedIndex) == -1) {
|
|
L0974_s_Event._type = k12_TMEventTypeHideDamageReceived;
|
|
M33_setMapAndTime(L0974_s_Event._mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
|
|
L0974_s_Event._priority = L0967_ui_ChampionIndex;
|
|
L0971_ps_Champion->_hideDamageReceivedIndex = _vm->_timeline->f238_addEventGetEventIndex(&L0974_s_Event);
|
|
} else {
|
|
L0972_ps_Event = &_vm->_timeline->_g370_events[AL0969_i_EventIndex];
|
|
M33_setMapAndTime(L0972_ps_Event->_mapTime, _vm->_dungeonMan->_g309_partyMapIndex, _vm->_g313_gameTime + 5);
|
|
_vm->_timeline->f236_fixChronology(_vm->_timeline->f235_getIndex(AL0969_i_EventIndex));
|
|
}
|
|
_vm->_championMan->f292_drawChampionState((ChampionIndex)L0967_ui_ChampionIndex);
|
|
_vm->_eventMan->f77_hideMouse();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChampionMan::f319_championKill(uint16 champIndex) {
|
|
uint16 L0962_ui_Multiple = 0;
|
|
#define AL0962_ui_Cell L0962_ui_Multiple
|
|
#define AL0962_ui_ChampionIconIndex L0962_ui_Multiple
|
|
int16 L0963_i_AliveChampionIndex;
|
|
Thing L0964_T_Thing;
|
|
Champion* L0965_ps_Champion;
|
|
|
|
L0965_ps_Champion = &_vm->_championMan->_gK71_champions[champIndex];
|
|
L0965_ps_Champion->_currHealth = 0;
|
|
setFlag(L0965_ps_Champion->_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 (!_vm->_championMan->_g415_leaderEmptyHanded) {
|
|
_vm->_objectMan->f34_drawLeaderObjectName(_vm->_championMan->_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);
|
|
L0964_T_Thing = _vm->_dungeonMan->f166_getUnusedThing(k0x8000_championBones | k10_JunkThingType);
|
|
if (L0964_T_Thing == Thing::_none) {
|
|
} else {
|
|
Junk* L0966_ps_Junk = (Junk*)_vm->_dungeonMan->f156_getThingData(L0964_T_Thing);
|
|
L0966_ps_Junk->setType(k5_JunkTypeBones);
|
|
L0966_ps_Junk->setDoNotDiscard(true);
|
|
L0966_ps_Junk->setChargeCount(champIndex);
|
|
AL0962_ui_Cell = L0965_ps_Champion->_cell;
|
|
_vm->_movsens->f267_getMoveResult(M15_thingWithNewCell(L0964_T_Thing, AL0962_ui_Cell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
|
|
}
|
|
L0965_ps_Champion->_symbolStep = 0;
|
|
L0965_ps_Champion->_symbols[0] = '\0';
|
|
L0965_ps_Champion->_dir = _vm->_dungeonMan->_g308_partyDir;
|
|
L0965_ps_Champion->_maximumDamageReceived = 0;
|
|
AL0962_ui_ChampionIconIndex = _vm->_championMan->M26_championIconIndex(AL0962_ui_Cell, _vm->_dungeonMan->_g308_partyDir);
|
|
if (_vm->M0_indexToOrdinal(AL0962_ui_ChampionIconIndex) == _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 (L0965_ps_Champion->_poisonEventCount) {
|
|
f323_unpoison(champIndex);
|
|
}
|
|
_vm->_displayMan->_g578_useByteBoxCoordinates = false;
|
|
_vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[AL0962_ui_ChampionIconIndex << 2], k0_ColorBlack);
|
|
_vm->_championMan->f292_drawChampionState((ChampionIndex)champIndex);
|
|
for (L0963_i_AliveChampionIndex = k0_ChampionFirst, L0965_ps_Champion = _vm->_championMan->_gK71_champions; L0963_i_AliveChampionIndex < _vm->_championMan->_g305_partyChampionCount; L0963_i_AliveChampionIndex++, L0965_ps_Champion++) {
|
|
if (L0965_ps_Champion->_currHealth)
|
|
break;
|
|
}
|
|
if (L0963_i_AliveChampionIndex == _vm->_championMan->_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) */
|
|
_vm->_championMan->_g303_partyDead = true;
|
|
return;
|
|
}
|
|
if (champIndex == _vm->_championMan->_g411_leaderIndex) {
|
|
_vm->_eventMan->f368_commandSetLeader((ChampionIndex)L0963_i_AliveChampionIndex);
|
|
}
|
|
if (champIndex == _vm->_championMan->_g514_magicCasterChampionIndex) {
|
|
_vm->_menuMan->f394_setMagicCasterAndDrawSpellArea(L0963_i_AliveChampionIndex);
|
|
} else {
|
|
_vm->_menuMan->f393_drawSpellAreaControls(_vm->_championMan->_g514_magicCasterChampionIndex);
|
|
}
|
|
}
|
|
|
|
void ChampionMan::f318_dropAllObjects(uint16 champIndex) {
|
|
static int16 G0057_ai_Graphic562_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 L0959_ui_Cell;
|
|
Thing L0960_T_Thing;
|
|
uint16 L0961_ui_SlotIndex;
|
|
|
|
L0959_ui_Cell = _vm->_championMan->_gK71_champions[champIndex]._cell;
|
|
for (L0961_ui_SlotIndex = k0_ChampionSlotReadyHand; L0961_ui_SlotIndex < k30_ChampionSlotChest_1; L0961_ui_SlotIndex++) {
|
|
if ((L0960_T_Thing = f300_getObjectRemovedFromSlot(champIndex, G0057_ai_Graphic562_SlotDropOrder[L0961_ui_SlotIndex])) != Thing::_none) {
|
|
_vm->_movsens->f267_getMoveResult(M15_thingWithNewCell(L0960_T_Thing, L0959_ui_Cell), kM1_MapXNotOnASquare, 0, _vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChampionMan::f323_unpoison(int16 champIndex) {
|
|
int16 L0982_i_EventIndex;
|
|
TimelineEvent* L0983_ps_Event;
|
|
|
|
if (champIndex == kM1_ChampionNone) {
|
|
return;
|
|
}
|
|
for (L0982_i_EventIndex = 0, L0983_ps_Event = _vm->_timeline->_g370_events; L0982_i_EventIndex < _vm->_timeline->_g369_eventMaxCount; L0983_ps_Event++, L0982_i_EventIndex++) {
|
|
if ((L0983_ps_Event->_type == k75_TMEventTypePoisonChampion) && (L0983_ps_Event->_priority == champIndex)) {
|
|
_vm->_timeline->f237_deleteEvent(L0982_i_EventIndex);
|
|
}
|
|
}
|
|
_vm->_championMan->_gK71_champions[champIndex]._poisonEventCount = 0;
|
|
}
|
|
|
|
void ChampionMan::f331_applyTimeEffects() {
|
|
uint16 L1006_ui_Multiple;
|
|
#define AL1006_ui_GameTime L1006_ui_Multiple
|
|
#define AL1006_ui_ChampionIndex L1006_ui_Multiple
|
|
uint16 L1007_ui_Multiple;
|
|
#define AL1007_ui_ScentIndex L1007_ui_Multiple
|
|
#define AL1007_ui_ManaGain L1007_ui_Multiple
|
|
#define AL1007_ui_StaminaGainCycleCount L1007_ui_Multiple
|
|
#define AL1007_ui_StatisticIndex L1007_ui_Multiple
|
|
uint16 L1008_ui_Multiple;
|
|
#define AL1008_ui_WizardSkillLevel L1008_ui_Multiple
|
|
#define AL1008_ui_Delay L1008_ui_Multiple
|
|
#define AL1008_ui_StaminaAboveHalf L1008_ui_Multiple
|
|
#define AL1008_ui_StatisticMaximum L1008_ui_Multiple
|
|
int16 L1009_i_Multiple;
|
|
#define AL1009_i_SkillIndex L1009_i_Multiple
|
|
#define AL1009_i_StaminaMagnitude L1009_i_Multiple
|
|
#define AL1009_i_StaminaLoss L1009_i_Multiple
|
|
Champion* L1010_ps_Champion;
|
|
unsigned char* L1011_puc_Statistic;
|
|
uint16 L1012_ui_TimeCriteria;
|
|
int16 L1013_i_Multiple;
|
|
#define AL1013_i_StaminaAmount L1013_i_Multiple
|
|
#define AL1013_i_HealthGain L1013_i_Multiple
|
|
Scent L1014_s_Scent;
|
|
|
|
|
|
if (!_vm->_championMan->_g305_partyChampionCount) {
|
|
return;
|
|
}
|
|
L1014_s_Scent.setMapX(_vm->_dungeonMan->_g306_partyMapX);
|
|
L1014_s_Scent.setMapY(_vm->_dungeonMan->_g307_partyMapY);
|
|
L1014_s_Scent.setMapIndex(_vm->_dungeonMan->_g309_partyMapIndex);
|
|
AL1007_ui_ScentIndex = 0;
|
|
while ((int16)AL1007_ui_ScentIndex < (int16)(_vm->_championMan->_g407_party._scentCount - 1)) {
|
|
if (&_vm->_championMan->_g407_party._scents[AL1007_ui_ScentIndex] != &L1014_s_Scent) {
|
|
if (!(_vm->_championMan->_g407_party._scentStrengths[AL1007_ui_ScentIndex] = MAX(0, _vm->_championMan->_g407_party._scentStrengths[AL1007_ui_ScentIndex] - 1)) && !AL1007_ui_ScentIndex) {
|
|
f316_deleteScent(0);
|
|
continue;
|
|
}
|
|
}
|
|
AL1007_ui_ScentIndex++;
|
|
}
|
|
AL1006_ui_GameTime = _vm->_g313_gameTime;
|
|
L1012_ui_TimeCriteria = (((AL1006_ui_GameTime & 0x0080) + ((AL1006_ui_GameTime & 0x0100) >> 2)) + ((AL1006_ui_GameTime & 0x0040) << 2)) >> 2;
|
|
for (AL1006_ui_ChampionIndex = k0_ChampionFirst, L1010_ps_Champion = _vm->_championMan->_gK71_champions; AL1006_ui_ChampionIndex < _vm->_championMan->_g305_partyChampionCount; AL1006_ui_ChampionIndex++, L1010_ps_Champion++) {
|
|
if (L1010_ps_Champion->_currHealth && (_vm->M0_indexToOrdinal(AL1006_ui_ChampionIndex) != _vm->_championMan->_g299_candidateChampionOrdinal)) {
|
|
if ((L1010_ps_Champion->_currMana < L1010_ps_Champion->_maxMana) && (L1012_ui_TimeCriteria < (L1010_ps_Champion->_statistics[k3_ChampionStatWisdom][k1_ChampionStatCurrent] + (AL1008_ui_WizardSkillLevel = _vm->_championMan->f303_getSkillLevel(AL1006_ui_ChampionIndex, k3_ChampionSkillWizard) + _vm->_championMan->f303_getSkillLevel(AL1006_ui_ChampionIndex, k2_ChampionSkillPriest))))) {
|
|
AL1007_ui_ManaGain = L1010_ps_Champion->_maxMana / 40;
|
|
if (_vm->_championMan->_g300_partyIsSleeping) {
|
|
AL1007_ui_ManaGain = AL1007_ui_ManaGain << 1;
|
|
}
|
|
AL1007_ui_ManaGain++;
|
|
f325_decrementStamina(AL1006_ui_ChampionIndex, AL1007_ui_ManaGain * MAX(7, 16 - AL1008_ui_WizardSkillLevel));
|
|
L1010_ps_Champion->_currMana += MIN(AL1007_ui_ManaGain, (uint16)(L1010_ps_Champion->_maxMana - L1010_ps_Champion->_currMana));
|
|
} else {
|
|
if (L1010_ps_Champion->_currMana > L1010_ps_Champion->_maxMana) {
|
|
L1010_ps_Champion->_currMana--;
|
|
}
|
|
}
|
|
for (AL1009_i_SkillIndex = k19_ChampionSkillWater; AL1009_i_SkillIndex >= k0_ChampionSkillFighter; AL1009_i_SkillIndex--) {
|
|
if (L1010_ps_Champion->_skills[AL1009_i_SkillIndex]._temporaryExperience > 0) {
|
|
L1010_ps_Champion->_skills[AL1009_i_SkillIndex]._temporaryExperience--;
|
|
}
|
|
}
|
|
AL1007_ui_StaminaGainCycleCount = 4;
|
|
AL1009_i_StaminaMagnitude = L1010_ps_Champion->_maxStamina;
|
|
while (L1010_ps_Champion->_currStamina < (AL1009_i_StaminaMagnitude >>= 1)) {
|
|
AL1007_ui_StaminaGainCycleCount += 2;
|
|
}
|
|
AL1009_i_StaminaLoss = 0;
|
|
AL1013_i_StaminaAmount = f26_getBoundedValue(1, (L1010_ps_Champion->_maxStamina >> 8) - 1, 6);
|
|
if (_vm->_championMan->_g300_partyIsSleeping) {
|
|
AL1013_i_StaminaAmount <<= 1;
|
|
}
|
|
if ((AL1008_ui_Delay = (_vm->_g313_gameTime - _vm->_projexpl->_g362_lastPartyMovementTime)) > 80) {
|
|
AL1013_i_StaminaAmount++;
|
|
if (AL1008_ui_Delay > 250) {
|
|
AL1013_i_StaminaAmount++;
|
|
}
|
|
}
|
|
do {
|
|
AL1008_ui_StaminaAboveHalf = (AL1007_ui_StaminaGainCycleCount <= 4);
|
|
if (L1010_ps_Champion->_food < -512) {
|
|
if (AL1008_ui_StaminaAboveHalf) {
|
|
AL1009_i_StaminaLoss += AL1013_i_StaminaAmount;
|
|
L1010_ps_Champion->_food -= 2;
|
|
}
|
|
} else {
|
|
if (L1010_ps_Champion->_food >= 0) {
|
|
AL1009_i_StaminaLoss -= AL1013_i_StaminaAmount;
|
|
}
|
|
L1010_ps_Champion->_food -= AL1008_ui_StaminaAboveHalf ? 2 : AL1007_ui_StaminaGainCycleCount >> 1;
|
|
}
|
|
if (L1010_ps_Champion->_water < -512) {
|
|
if (AL1008_ui_StaminaAboveHalf) {
|
|
AL1009_i_StaminaLoss += AL1013_i_StaminaAmount;
|
|
L1010_ps_Champion->_water -= 1;
|
|
}
|
|
} else {
|
|
if (L1010_ps_Champion->_water >= 0) {
|
|
AL1009_i_StaminaLoss -= AL1013_i_StaminaAmount;
|
|
}
|
|
L1010_ps_Champion->_water -= AL1008_ui_StaminaAboveHalf ? 1 : AL1007_ui_StaminaGainCycleCount >> 2;
|
|
}
|
|
} while (--AL1007_ui_StaminaGainCycleCount && ((L1010_ps_Champion->_currStamina - AL1009_i_StaminaLoss) < L1010_ps_Champion->_maxStamina));
|
|
f325_decrementStamina(AL1006_ui_ChampionIndex, AL1009_i_StaminaLoss);
|
|
if (L1010_ps_Champion->_food < -1024) {
|
|
L1010_ps_Champion->_food = -1024;
|
|
}
|
|
if (L1010_ps_Champion->_water < -1024) {
|
|
L1010_ps_Champion->_water = -1024;
|
|
}
|
|
if ((L1010_ps_Champion->_currHealth < L1010_ps_Champion->_maxHealth) && (L1010_ps_Champion->_currStamina >= (L1010_ps_Champion->_maxStamina >> 2)) && (L1012_ui_TimeCriteria < (L1010_ps_Champion->_statistics[k4_ChampionStatVitality][k1_ChampionStatCurrent] + 12))) {
|
|
AL1013_i_HealthGain = (L1010_ps_Champion->_maxHealth >> 7) + 1;
|
|
if (_vm->_championMan->_g300_partyIsSleeping) {
|
|
AL1013_i_HealthGain <<= 1;
|
|
}
|
|
if (_vm->_objectMan->f33_getIconIndex(L1010_ps_Champion->_slots[k10_ChampionSlotNeck]) == k121_IconIndiceJunkEkkhardCross) {
|
|
AL1013_i_HealthGain += (AL1013_i_HealthGain >> 1) + 1;
|
|
}
|
|
L1010_ps_Champion->_currHealth += MIN(AL1013_i_HealthGain, (int16)(L1010_ps_Champion->_maxHealth - L1010_ps_Champion->_currHealth));
|
|
}
|
|
if (!((int)_vm->_g313_gameTime & (_vm->_championMan->_g300_partyIsSleeping ? 63 : 255))) {
|
|
for (AL1007_ui_StatisticIndex = k0_ChampionStatLuck; AL1007_ui_StatisticIndex <= k6_ChampionStatAntifire; AL1007_ui_StatisticIndex++) {
|
|
L1011_puc_Statistic = L1010_ps_Champion->_statistics[AL1007_ui_StatisticIndex];
|
|
AL1008_ui_StatisticMaximum = L1011_puc_Statistic[k0_ChampionStatMaximum];
|
|
if (L1011_puc_Statistic[k1_ChampionStatCurrent] < AL1008_ui_StatisticMaximum) {
|
|
L1011_puc_Statistic[k1_ChampionStatCurrent]++;
|
|
} else {
|
|
if (L1011_puc_Statistic[k1_ChampionStatCurrent] > AL1008_ui_StatisticMaximum) {
|
|
L1011_puc_Statistic[k1_ChampionStatCurrent] -= L1011_puc_Statistic[k1_ChampionStatCurrent] / AL1008_ui_StatisticMaximum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!_vm->_championMan->_g300_partyIsSleeping && (L1010_ps_Champion->_dir != _vm->_dungeonMan->_g308_partyDir) && (_vm->_projexpl->_g361_lastCreatureAttackTime + 60 < _vm->_g313_gameTime)) {
|
|
L1010_ps_Champion->_dir = _vm->_dungeonMan->_g308_partyDir;
|
|
L1010_ps_Champion->_maximumDamageReceived = 0;
|
|
setFlag(L1010_ps_Champion->_attributes, k0x0400_ChampionAttributeIcon);
|
|
}
|
|
setFlag(L1010_ps_Champion->_attributes, k0x0100_ChampionAttributeStatistics);
|
|
if (_vm->M0_indexToOrdinal(AL1006_ui_ChampionIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal) {
|
|
if (_vm->_g333_pressingMouth || _vm->_g331_pressingEye || (_vm->_inventoryMan->_g424_panelContent == k0_PanelContentFoodWaterPoisoned)) {
|
|
setFlag(L1010_ps_Champion->_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) {
|
|
warning(false, "MISSING CODE: stuff for resetting for loaded games");
|
|
assert(false);
|
|
}
|
|
|
|
_g414_leaderHandObject = Thing::_none;
|
|
_g413_leaderHandObjectIconIndex = kM1_IconIndiceNone;
|
|
_g415_leaderEmptyHanded = true;
|
|
}
|
|
|
|
|
|
void ChampionMan::f280_addCandidateChampionToParty(uint16 championPortraitIndex) {
|
|
Thing L0793_T_Thing;
|
|
uint16 L0794_ui_Multiple;
|
|
#define AL0794_ui_ViewCell L0794_ui_Multiple
|
|
#define AL0794_ui_SlotIndex L0794_ui_Multiple
|
|
#define AL0794_ui_CharacterIndex L0794_ui_Multiple
|
|
#define AL0794_ui_StatisticIndex L0794_ui_Multiple
|
|
#define AL0794_ui_SkillIndex L0794_ui_Multiple
|
|
int16 L0795_i_HiddenSkillIndex;
|
|
uint16 L0796_ui_Multiple;
|
|
#define AL0796_ui_Character L0796_ui_Multiple
|
|
#define AL0796_ui_SkillValue L0796_ui_Multiple
|
|
#define AL0796_ui_ThingType L0796_ui_Multiple
|
|
Champion* L0797_ps_Champion;
|
|
char* L0798_pc_Character;
|
|
uint16 L0799_ui_PreviousPartyChampionCount;
|
|
uint16 L0800_ui_Multiple;
|
|
#define AL0800_B_ChampionTitleCopied L0800_ui_Multiple
|
|
#define AL0800_ui_HiddenSkillCounter L0800_ui_Multiple
|
|
uint16 L0801_ui_SlotIndex;
|
|
int16 L0802_i_MapX;
|
|
int16 L0803_i_MapY;
|
|
uint16 L0804_ui_ChampionObjectsCell;
|
|
int16 L0805_i_ObjectAllowedSlots;
|
|
int32 L0806_l_BaseSkillExperience;
|
|
char L0807_ac_DecodedChampionText[77];
|
|
|
|
if (!_vm->_championMan->_g415_leaderEmptyHanded) {
|
|
return;
|
|
}
|
|
if (_vm->_championMan->_g305_partyChampionCount == 4) {
|
|
return;
|
|
}
|
|
L0797_ps_Champion = &_vm->_championMan->_gK71_champions[L0799_ui_PreviousPartyChampionCount = _vm->_championMan->_g305_partyChampionCount];
|
|
L0797_ps_Champion->resetToZero();
|
|
// Strangerke - TODO: Check if the new code is possible to run on the older version (example: the portaits could be missing in the data)
|
|
_vm->_displayMan->_g578_useByteBoxCoordinates = true;
|
|
_vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k26_ChampionPortraitsIndice), L0797_ps_Champion->_portrait, gBoxChampionPortrait, _vm->_championMan->M27_getChampionPortraitX(championPortraitIndex), _vm->_championMan->M28_getChampionPortraitY(championPortraitIndex), k128_byteWidth, k16_byteWidth, kM1_ColorNoTransparency);
|
|
L0797_ps_Champion->_actionIndex = k255_ChampionActionNone;
|
|
L0797_ps_Champion->_enableActionEventIndex = -1;
|
|
L0797_ps_Champion->_hideDamageReceivedIndex = -1;
|
|
L0797_ps_Champion->_dir = _vm->_dungeonMan->_g308_partyDir;
|
|
AL0794_ui_ViewCell = k0_ViewCellFronLeft;
|
|
while (_vm->_championMan->f285_getIndexInCell(M21_normalizeModulo4(AL0794_ui_ViewCell + _vm->_dungeonMan->_g308_partyDir)) != kM1_ChampionNone) {
|
|
AL0794_ui_ViewCell++;
|
|
}
|
|
L0797_ps_Champion->_cell = (ViewCell)M21_normalizeModulo4(AL0794_ui_ViewCell + _vm->_dungeonMan->_g308_partyDir);
|
|
L0797_ps_Champion->_attributes = k0x0400_ChampionAttributeIcon;
|
|
L0797_ps_Champion->_directionMaximumDamageReceived = _vm->_dungeonMan->_g308_partyDir;
|
|
L0797_ps_Champion->_food = 1500 + _vm->getRandomNumber(256);
|
|
L0797_ps_Champion->_water = 1500 + _vm->getRandomNumber(256);
|
|
for (AL0794_ui_SlotIndex = k0_ChampionSlotReadyHand; AL0794_ui_SlotIndex < k30_ChampionSlotChest_1; AL0794_ui_SlotIndex++) {
|
|
L0797_ps_Champion->_slots[AL0794_ui_SlotIndex] = Thing::_none;
|
|
}
|
|
L0793_T_Thing = _vm->_dungeonMan->f161_getSquareFirstThing(_vm->_dungeonMan->_g306_partyMapX, _vm->_dungeonMan->_g307_partyMapY);
|
|
while ((L0793_T_Thing.getType()) != k2_TextstringType) {
|
|
L0793_T_Thing = _vm->_dungeonMan->f159_getNextThing(L0793_T_Thing);
|
|
}
|
|
_vm->_dungeonMan->f168_decodeText(L0798_pc_Character = L0807_ac_DecodedChampionText, L0793_T_Thing, (TextType)(k2_TextTypeScroll | k0x8000_DecodeEvenIfInvisible));
|
|
AL0794_ui_CharacterIndex = 0;
|
|
while ((AL0796_ui_Character = *L0798_pc_Character++) != '\n') { /* New line */
|
|
L0797_ps_Champion->_name[AL0794_ui_CharacterIndex++] = AL0796_ui_Character;
|
|
}
|
|
L0797_ps_Champion->_name[AL0794_ui_CharacterIndex] = '\0';
|
|
AL0794_ui_CharacterIndex = 0;
|
|
AL0800_B_ChampionTitleCopied = false;
|
|
for (;;) { /*_Infinite loop_*/
|
|
AL0796_ui_Character = *L0798_pc_Character++;
|
|
if (AL0796_ui_Character == '\n') { /* New line */
|
|
if (AL0800_B_ChampionTitleCopied)
|
|
break;
|
|
AL0800_B_ChampionTitleCopied = true;
|
|
} else {
|
|
L0797_ps_Champion->_title[AL0794_ui_CharacterIndex++] = AL0796_ui_Character;
|
|
}
|
|
}
|
|
L0797_ps_Champion->_title[AL0794_ui_CharacterIndex] = '\0';
|
|
if (*L0798_pc_Character++ == 'M') {
|
|
setFlag(L0797_ps_Champion->_attributes, k0x0010_ChampionAttributeMale);
|
|
}
|
|
L0798_pc_Character++;
|
|
L0797_ps_Champion->_currHealth = L0797_ps_Champion->_maxHealth = _vm->_championMan->f279_getDecodedValue(L0798_pc_Character, 4);
|
|
L0798_pc_Character += 4;
|
|
L0797_ps_Champion->_currStamina = L0797_ps_Champion->_maxStamina = _vm->_championMan->f279_getDecodedValue(L0798_pc_Character, 4);
|
|
L0798_pc_Character += 4;
|
|
L0797_ps_Champion->_currMana = L0797_ps_Champion->_maxMana = _vm->_championMan->f279_getDecodedValue(L0798_pc_Character, 4);
|
|
L0798_pc_Character += 4;
|
|
L0798_pc_Character++;
|
|
for (AL0794_ui_StatisticIndex = k0_ChampionStatLuck; AL0794_ui_StatisticIndex <= k6_ChampionStatAntifire; AL0794_ui_StatisticIndex++) {
|
|
L0797_ps_Champion->_statistics[AL0794_ui_StatisticIndex][k2_ChampionStatMinimum] = 30;
|
|
L0797_ps_Champion->_statistics[AL0794_ui_StatisticIndex][k1_ChampionStatCurrent] = L0797_ps_Champion->_statistics[AL0794_ui_StatisticIndex][k0_ChampionStatMaximum] = _vm->_championMan->f279_getDecodedValue(L0798_pc_Character, 2);
|
|
L0798_pc_Character += 2;
|
|
}
|
|
L0797_ps_Champion->_statistics[k0_ChampionStatLuck][k2_ChampionStatMinimum] = 10;
|
|
L0798_pc_Character++;
|
|
for (AL0794_ui_SkillIndex = k4_ChampionSkillSwing; AL0794_ui_SkillIndex <= k19_ChampionSkillWater; AL0794_ui_SkillIndex++) {
|
|
if ((AL0796_ui_SkillValue = *L0798_pc_Character++ - 'A') > 0) {
|
|
L0797_ps_Champion->_skills[AL0794_ui_SkillIndex]._experience = 125L << AL0796_ui_SkillValue;
|
|
}
|
|
}
|
|
for (AL0794_ui_SkillIndex = k0_ChampionSkillFighter; AL0794_ui_SkillIndex <= k3_ChampionSkillWizard; AL0794_ui_SkillIndex++) {
|
|
L0806_l_BaseSkillExperience = 0;
|
|
L0795_i_HiddenSkillIndex = (AL0794_ui_SkillIndex + 1) << 2;
|
|
for (AL0800_ui_HiddenSkillCounter = 0; AL0800_ui_HiddenSkillCounter < 4; AL0800_ui_HiddenSkillCounter++) {
|
|
L0806_l_BaseSkillExperience += L0797_ps_Champion->_skills[L0795_i_HiddenSkillIndex + AL0800_ui_HiddenSkillCounter]._experience;
|
|
}
|
|
L0797_ps_Champion->_skills[AL0794_ui_SkillIndex]._experience = L0806_l_BaseSkillExperience;
|
|
}
|
|
_vm->_championMan->_g299_candidateChampionOrdinal = L0799_ui_PreviousPartyChampionCount + 1;
|
|
if (++_vm->_championMan->_g305_partyChampionCount == 1) {
|
|
_vm->_eventMan->f368_commandSetLeader(k0_ChampionFirst);
|
|
_vm->_menuMan->_g508_refreshActionArea = true;
|
|
} else {
|
|
_vm->_menuMan->f388_clearActingChampion();
|
|
_vm->_menuMan->f386_drawActionIcon((ChampionIndex)(_vm->_championMan->_g305_partyChampionCount - 1));
|
|
}
|
|
L0802_i_MapX = _vm->_dungeonMan->_g306_partyMapX;
|
|
L0803_i_MapY = _vm->_dungeonMan->_g307_partyMapY;
|
|
L0804_ui_ChampionObjectsCell = returnOppositeDir(_vm->_dungeonMan->_g308_partyDir);
|
|
L0802_i_MapX += _vm->_dirIntoStepCountEast[_vm->_dungeonMan->_g308_partyDir], L0803_i_MapY += _vm->_dirIntoStepCountNorth[_vm->_dungeonMan->_g308_partyDir];
|
|
L0793_T_Thing = _vm->_dungeonMan->f161_getSquareFirstThing(L0802_i_MapX, L0803_i_MapY);
|
|
AL0794_ui_SlotIndex = k13_ChampionSlotBackpackLine_1_1;
|
|
while (L0793_T_Thing != Thing::_endOfList) {
|
|
if (((AL0796_ui_ThingType = (L0793_T_Thing.getType())) > k3_SensorThingType) && ((L0793_T_Thing.getCell()) == L0804_ui_ChampionObjectsCell)) {
|
|
L0805_i_ObjectAllowedSlots = g237_ObjectInfo[_vm->_dungeonMan->f141_getObjectInfoIndex(L0793_T_Thing)]._allowedSlots;
|
|
switch (AL0796_ui_ThingType) {
|
|
case k6_ArmourThingType:
|
|
for (L0801_ui_SlotIndex = k2_ChampionSlotHead; L0801_ui_SlotIndex <= k5_ChampionSlotFeet; L0801_ui_SlotIndex++) {
|
|
if (L0805_i_ObjectAllowedSlots & gSlotMasks[L0801_ui_SlotIndex])
|
|
goto T0280048;
|
|
}
|
|
if ((L0805_i_ObjectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (L0797_ps_Champion->_slots[k10_ChampionSlotNeck] == Thing::_none)) {
|
|
L0801_ui_SlotIndex = k10_ChampionSlotNeck;
|
|
} else {
|
|
goto T0280046;
|
|
}
|
|
break;
|
|
case k5_WeaponThingType:
|
|
if (L0797_ps_Champion->_slots[k1_ChampionSlotActionHand] == Thing::_none) {
|
|
L0801_ui_SlotIndex = k1_ChampionSlotActionHand;
|
|
} else {
|
|
goto T0280046;
|
|
}
|
|
break;
|
|
case k7_ScrollThingType:
|
|
case k8_PotionThingType:
|
|
if (L0797_ps_Champion->_slots[k11_ChampionSlotPouch_1] == Thing::_none) {
|
|
L0801_ui_SlotIndex = k11_ChampionSlotPouch_1;
|
|
} else {
|
|
if (L0797_ps_Champion->_slots[k6_ChampionSlotPouch_2] == Thing::_none) {
|
|
L0801_ui_SlotIndex = k6_ChampionSlotPouch_2;
|
|
} else {
|
|
goto T0280046;
|
|
}
|
|
}
|
|
break;
|
|
case k9_ContainerThingType:
|
|
case k10_JunkThingType:
|
|
T0280046:
|
|
if ((L0805_i_ObjectAllowedSlots & gSlotMasks[k10_ChampionSlotNeck]) && (L0797_ps_Champion->_slots[k10_ChampionSlotNeck] == Thing::_none)) {
|
|
L0801_ui_SlotIndex = k10_ChampionSlotNeck;
|
|
} else {
|
|
L0801_ui_SlotIndex = AL0794_ui_SlotIndex++;
|
|
}
|
|
}
|
|
T0280048:
|
|
if (L0797_ps_Champion->_slots[L0801_ui_SlotIndex] != Thing::_none) {
|
|
goto T0280046;
|
|
}
|
|
_vm->_championMan->f301_addObjectInSlot((ChampionIndex)L0799_ui_PreviousPartyChampionCount, L0793_T_Thing, (ChampionSlot)L0801_ui_SlotIndex);
|
|
}
|
|
L0793_T_Thing = _vm->_dungeonMan->f159_getNextThing(L0793_T_Thing);
|
|
}
|
|
_vm->_inventoryMan->f355_toggleInventory((ChampionIndex)L0799_ui_PreviousPartyChampionCount);
|
|
_vm->_menuMan->f456_drawDisabledMenu();;
|
|
}
|
|
|
|
void ChampionMan::f287_drawChampionBarGraphs(ChampionIndex champIndex) {
|
|
int16 barGraphHeights[3];
|
|
Champion *champ = &_vm->_championMan->_gK71_champions[champIndex];
|
|
int16 AL0842_i_BarGraphIndex = 0;
|
|
if (champ->_currHealth > 0) {
|
|
int32 barGraphHeight = (((int32)champ->_currHealth << 10) * 25) / champ->_maxHealth;
|
|
if (barGraphHeight & 0x000003FF) {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = (barGraphHeight >> 10) + 1;
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = (barGraphHeight >> 10);
|
|
}
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = 0;
|
|
}
|
|
if (champ->_currStamina > 0) {
|
|
int32 barGraphHeight = (((int32)champ->_currStamina << 10) * 25) / champ->_maxStamina;
|
|
if (barGraphHeight & 0x000003FF) {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = (barGraphHeight >> 10) + 1;
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = (barGraphHeight >> 10);
|
|
}
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex++] = 0;
|
|
}
|
|
if (champ->_currMana > 0) {
|
|
if (champ->_currMana > champ->_maxMana) {
|
|
barGraphHeights[AL0842_i_BarGraphIndex] = 25;
|
|
} else {
|
|
int32 barGraphHeight = (((int32)champ->_currMana << 10) * 25) / champ->_maxMana;
|
|
if (barGraphHeight & 0x000003FF) {
|
|
barGraphHeights[AL0842_i_BarGraphIndex] = (barGraphHeight >> 10) + 1;
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex] = (barGraphHeight >> 10);
|
|
}
|
|
}
|
|
} else {
|
|
barGraphHeights[AL0842_i_BarGraphIndex] = 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) {
|
|
uint16 L0862_ui_ChampionAttributes;
|
|
bool L0863_B_IsInventoryChampion;
|
|
int16 L0864_i_Multiple;
|
|
#define AL0864_i_BorderCount L0864_i_Multiple
|
|
#define AL0864_i_ColorIndex L0864_i_Multiple
|
|
#define AL0864_i_Load L0864_i_Multiple
|
|
#define AL0864_i_ChampionIconIndex L0864_i_Multiple
|
|
#define AL0864_i_StatisticIndex L0864_i_Multiple
|
|
#define AL0864_i_SlotIndex L0864_i_Multiple
|
|
Champion* L0865_ps_Champion;
|
|
char* L0866_pc_ChampionName;
|
|
char L0867_c_ChampionTitleFirstCharacter;
|
|
int16 L0868_i_ChampionStatusBoxX;
|
|
int16 L0869_i_ChampionTitleX;
|
|
int16 L0870_i_Multiple;
|
|
#define AL0870_i_NativeBitmapIndex L0870_i_Multiple
|
|
#define AL0870_i_Color L0870_i_Multiple
|
|
Box L0871_s_Box;
|
|
int16 L0872_ai_NativeBitmapIndices[3];
|
|
|
|
|
|
L0868_i_ChampionStatusBoxX = champIndex * k69_ChampionStatusBoxSpacing;
|
|
L0865_ps_Champion = &_gK71_champions[champIndex];
|
|
L0862_ui_ChampionAttributes = L0865_ps_Champion->_attributes;
|
|
if (!getFlag(L0862_ui_ChampionAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x0200_ChampionAttributeLoad | k0x0400_ChampionAttributeIcon | k0x0800_ChampionAttributePanel | k0x1000_ChampionAttributeStatusBox | k0x2000_ChampionAttributeWounds | k0x4000_ChampionAttributeViewport | k0x8000_ChampionAttributeActionHand)) {
|
|
return;
|
|
}
|
|
L0863_B_IsInventoryChampion = (_vm->M0_indexToOrdinal(champIndex) == _vm->_inventoryMan->_g432_inventoryChampionOrdinal);
|
|
_vm->_displayMan->_g578_useByteBoxCoordinates = false;
|
|
_vm->_eventMan->f78_showMouse();
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x1000_ChampionAttributeStatusBox)) {
|
|
L0871_s_Box._y1 = 0;
|
|
L0871_s_Box._y2 = 28;
|
|
L0871_s_Box._x2 = (L0871_s_Box._x1 = L0868_i_ChampionStatusBoxX) + 66;
|
|
if (L0865_ps_Champion->_currHealth) {
|
|
_vm->_displayMan->D24_fillScreenBox(L0871_s_Box, k12_ColorDarkestGray);
|
|
for (uint16 i = 0; i < 3; ++i)
|
|
L0872_ai_NativeBitmapIndices[i] = 0;
|
|
AL0864_i_BorderCount = 0;
|
|
if (_g407_party._fireShieldDefense > 0) {
|
|
L0872_ai_NativeBitmapIndices[AL0864_i_BorderCount++] = k38_BorderPartyFireshieldIndice;
|
|
}
|
|
if (_g407_party._spellShieldDefense > 0) {
|
|
L0872_ai_NativeBitmapIndices[AL0864_i_BorderCount++] = k39_BorderPartySpellshieldIndice;
|
|
}
|
|
if ((_g407_party._shieldDefense > 0) || L0865_ps_Champion->_shieldDefense) {
|
|
L0872_ai_NativeBitmapIndices[AL0864_i_BorderCount++] = k37_BorderPartyShieldIndice;
|
|
}
|
|
while (AL0864_i_BorderCount--) {
|
|
_vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(L0872_ai_NativeBitmapIndices[AL0864_i_BorderCount]), &L0871_s_Box, k40_byteWidth, k10_ColorFlesh, 29);
|
|
}
|
|
if (L0863_B_IsInventoryChampion) {
|
|
_vm->_inventoryMan->f354_drawStatusBoxPortrait(champIndex);
|
|
setFlag(L0862_ui_ChampionAttributes, k0x0100_ChampionAttributeStatistics);
|
|
} else {
|
|
setFlag(L0862_ui_ChampionAttributes, k0x0080_ChampionAttributeNameTitle | k0x0100_ChampionAttributeStatistics | k0x2000_ChampionAttributeWounds | k0x8000_ChampionAttributeActionHand);
|
|
}
|
|
} else {
|
|
_vm->_displayMan->f21_blitToScreen(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k8_StatusBoxDeadChampion), &L0871_s_Box, k40_byteWidth, kM1_ColorNoTransparency, 29);
|
|
_vm->_textMan->f53_printToLogicalScreen(L0868_i_ChampionStatusBoxX + 1, 5, k13_ColorLightestGray, k1_ColorDarkGary, L0865_ps_Champion->_name);
|
|
_vm->_menuMan->f386_drawActionIcon(champIndex);
|
|
goto T0292042;
|
|
}
|
|
}
|
|
if (!(L0865_ps_Champion->_currHealth))
|
|
goto T0292042;
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x0080_ChampionAttributeNameTitle)) {
|
|
AL0864_i_ColorIndex = (champIndex == _g411_leaderIndex) ? k9_ColorGold : k13_ColorLightestGray;
|
|
if (L0863_B_IsInventoryChampion) {
|
|
_vm->_textMan->f52_printToViewport(3, 7, (Color)AL0864_i_ColorIndex, L0866_pc_ChampionName = L0865_ps_Champion->_name);
|
|
L0869_i_ChampionTitleX = 6 * strlen(L0866_pc_ChampionName) + 3;
|
|
L0867_c_ChampionTitleFirstCharacter = L0865_ps_Champion->_title[0];
|
|
if ((L0867_c_ChampionTitleFirstCharacter != ',') && (L0867_c_ChampionTitleFirstCharacter != ';') && (L0867_c_ChampionTitleFirstCharacter != '-')) {
|
|
L0869_i_ChampionTitleX += 6;
|
|
}
|
|
_vm->_textMan->f52_printToViewport(L0869_i_ChampionTitleX, 7, (Color)AL0864_i_ColorIndex, L0865_ps_Champion->_title);
|
|
setFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
} else {
|
|
L0871_s_Box._y1 = 0;
|
|
L0871_s_Box._y2 = 6;
|
|
L0871_s_Box._x2 = (L0871_s_Box._x1 = L0868_i_ChampionStatusBoxX) + 42;
|
|
_vm->_displayMan->D24_fillScreenBox(L0871_s_Box, k1_ColorDarkGary);
|
|
_vm->_textMan->f53_printToLogicalScreen(L0868_i_ChampionStatusBoxX + 1, 5, (Color)AL0864_i_ColorIndex, k1_ColorDarkGary, L0865_ps_Champion->_name);
|
|
}
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x0100_ChampionAttributeStatistics)) {
|
|
f287_drawChampionBarGraphs(champIndex);
|
|
if (L0863_B_IsInventoryChampion) {
|
|
f290_drawHealthStaminaManaValues(L0865_ps_Champion);
|
|
if ((L0865_ps_Champion->_food < 0) || (L0865_ps_Champion->_water < 0) || (L0865_ps_Champion->_poisonEventCount)) {
|
|
AL0870_i_NativeBitmapIndex = k34_SlotBoxWoundedIndice;
|
|
} else {
|
|
AL0870_i_NativeBitmapIndex = k33_SlotBoxNormalIndice;
|
|
}
|
|
_vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(AL0870_i_NativeBitmapIndex), gBoxMouth, k16_byteWidth, k12_ColorDarkestGray, 18);
|
|
AL0870_i_NativeBitmapIndex = k33_SlotBoxNormalIndice;
|
|
for (AL0864_i_StatisticIndex = k1_ChampionStatStrength; AL0864_i_StatisticIndex <= k6_ChampionStatAntifire; AL0864_i_StatisticIndex++) {
|
|
if ((L0865_ps_Champion->_statistics[AL0864_i_StatisticIndex][k1_ChampionStatCurrent] < L0865_ps_Champion->_statistics[AL0864_i_StatisticIndex][k0_ChampionStatMaximum])) {
|
|
AL0870_i_NativeBitmapIndex = k34_SlotBoxWoundedIndice;
|
|
break;
|
|
}
|
|
}
|
|
_vm->_displayMan->f20_blitToViewport(_vm->_displayMan->f489_getNativeBitmapOrGraphic(AL0870_i_NativeBitmapIndex), gBoxEye, k16_byteWidth, k12_ColorDarkestGray, 18);
|
|
setFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
}
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x2000_ChampionAttributeWounds)) {
|
|
for (AL0864_i_SlotIndex = L0863_B_IsInventoryChampion ? k5_ChampionSlotFeet : k1_ChampionSlotActionHand; AL0864_i_SlotIndex >= k0_ChampionSlotReadyHand; AL0864_i_SlotIndex--) {
|
|
f291_drawSlot(champIndex, AL0864_i_SlotIndex);
|
|
}
|
|
if (L0863_B_IsInventoryChampion) {
|
|
setFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
}
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x0200_ChampionAttributeLoad) && L0863_B_IsInventoryChampion) {
|
|
if (L0865_ps_Champion->_load > (AL0864_i_Load = f309_getMaximumLoad(L0865_ps_Champion))) {
|
|
AL0870_i_Color = k8_ColorRed;
|
|
} else {
|
|
if (((long)L0865_ps_Champion->_load << 3) > ((long)AL0864_i_Load * 5)) {
|
|
AL0870_i_Color = k11_ColorYellow;
|
|
} else {
|
|
AL0870_i_Color = k13_ColorLightestGray;
|
|
}
|
|
}
|
|
_vm->_textMan->f52_printToViewport(104, 132, (Color)AL0870_i_Color, "LOAD ");
|
|
AL0864_i_Load = L0865_ps_Champion->_load / 10;
|
|
strcpy(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(AL0864_i_Load, true, 3).c_str());
|
|
strcat(_vm->_g353_stringBuildBuffer, ".");
|
|
AL0864_i_Load = L0865_ps_Champion->_load - (AL0864_i_Load * 10);
|
|
strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(AL0864_i_Load, false, 1).c_str());
|
|
strcat(_vm->_g353_stringBuildBuffer, "/");
|
|
AL0864_i_Load = (f309_getMaximumLoad(L0865_ps_Champion) + 5) / 10;
|
|
strcat(_vm->_g353_stringBuildBuffer, f288_getStringFromInteger(AL0864_i_Load, true, 3).c_str());
|
|
strcat(_vm->_g353_stringBuildBuffer, " KG");
|
|
_vm->_textMan->f52_printToViewport(148, 132, (Color)AL0870_i_Color, _vm->_g353_stringBuildBuffer);
|
|
setFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
}
|
|
AL0864_i_ChampionIconIndex = M26_championIconIndex(L0865_ps_Champion->_cell, _vm->_dungeonMan->_g308_partyDir);
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x0400_ChampionAttributeIcon) && (_vm->_eventMan->_g599_useChampionIconOrdinalAsMousePointerBitmap != _vm->M0_indexToOrdinal(AL0864_i_ChampionIconIndex))) {
|
|
_vm->_displayMan->D24_fillScreenBox(g54_BoxChampionIcons[AL0864_i_ChampionIconIndex], g46_ChampionColor[champIndex]);
|
|
_vm->_displayMan->f132_blitToBitmap(_vm->_displayMan->f489_getNativeBitmapOrGraphic(k28_ChampionIcons), _vm->_displayMan->_g348_bitmapScreen, g54_BoxChampionIcons[AL0864_i_ChampionIconIndex], _vm->_championMan->M26_championIconIndex(L0865_ps_Champion->_dir, _vm->_dungeonMan->_g308_partyDir) * 19, 0, k40_byteWidth, k160_byteWidthScreen, k12_ColorDarkestGray, 14, k200_heightScreen);
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x0800_ChampionAttributePanel) && L0863_B_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(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x8000_ChampionAttributeActionHand)) {
|
|
f291_drawSlot(champIndex, k1_ChampionSlotActionHand);
|
|
_vm->_menuMan->f386_drawActionIcon(champIndex);
|
|
if (L0863_B_IsInventoryChampion) {
|
|
setFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport);
|
|
}
|
|
}
|
|
if (getFlag(L0862_ui_ChampionAttributes, k0x4000_ChampionAttributeViewport)) {
|
|
_vm->_displayMan->f97_drawViewport(k0_viewportNotDungeonView);
|
|
}
|
|
T0292042:
|
|
clearFlag(L0865_ps_Champion->_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) {
|
|
warning(false, "STUB METHOD: Champion::renameChampion, F0281_CHAMPION_Rename");
|
|
|
|
DisplayMan &dispMan = *_vm->_displayMan;
|
|
TextMan &textMan = *_vm->_textMan;
|
|
|
|
Box box;
|
|
box._y1 = 3;
|
|
box._y2 = 8;
|
|
box._x1 = 3;
|
|
box._x2 = box._x1 + 167;
|
|
|
|
dispMan.f135_fillBoxBitmap(dispMan._g296_bitmapViewport, box, k12_ColorDarkestGray, k112_byteWidthViewport, k136_heightViewport);
|
|
dispMan.f132_blitToBitmap(dispMan.f489_getNativeBitmapOrGraphic(k27_PanelRenameChampionIndice), dispMan._g296_bitmapViewport, g32_BoxPanel,
|
|
0, 0, 72, k112_byteWidthViewport, k4_ColorCyan);
|
|
textMan.f52_printToViewport(177, 58, k13_ColorLightestGray, "_______");
|
|
textMan.f52_printToViewport(105, 76, k13_ColorLightestGray, "___________________");
|
|
Common::Point clickPos;
|
|
static Box okButtonBox(197, 215, 147, 155);
|
|
for (;;) {
|
|
_vm->_eventMan->processInput();
|
|
if (_vm->_eventMan->f360_hasPendingClick(clickPos, k1_LeftMouseButton) && okButtonBox.isPointInside(clickPos)) {
|
|
return;
|
|
}
|
|
dispMan.f97_drawViewport(k0_viewportNotDungeonView);
|
|
dispMan.updateScreen();
|
|
}
|
|
}
|
|
|
|
uint16 ChampionMan::f303_getSkillLevel(int16 champIndex, uint16 skillIndex) {
|
|
if (_vm->_championMan->_g300_partyIsSleeping) {
|
|
return 1;
|
|
}
|
|
bool ignoreTmpExp = getFlag(skillIndex, k0x8000_IgnoreTemporaryExperience);
|
|
bool ignoreObjModifiers = getFlag(skillIndex, k0x4000_IgnoreObjectModifiers);
|
|
clearFlag(skillIndex, k0x8000_IgnoreTemporaryExperience | k0x4000_IgnoreObjectModifiers);
|
|
Champion *champ = &_vm->_championMan->_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;
|
|
if ((actionHandIconIndex = _vm->_objectMan->f33_getIconIndex(champ->_slots[k1_ChampionSlotActionHand])) == 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 k15_ChampionSkillDefend:
|
|
if (neckIconIndex == k121_IconIndiceJunkEkkhardCross) {
|
|
skillLevel += 1;
|
|
}
|
|
break;
|
|
case k13_ChampionSkillHeal:
|
|
if ((neckIconIndex == k120_IconIndiceJunkGemOfAges) || (actionHandIconIndex == k66_IconIndiceWeaponSceptreOfLyf)) { /* The skill modifiers of these two objects are not cumulative */
|
|
skillLevel += 1;
|
|
}
|
|
break;
|
|
case k14_ChampionSkillInfluence:
|
|
if (neckIconIndex == k122_IconIndiceJunkMoonstone) {
|
|
skillLevel += 1;
|
|
}
|
|
}
|
|
}
|
|
return skillLevel;
|
|
}
|
|
|
|
}
|
|
|
|
|