Mercurial > mm7
changeset 2498:92eeeb5200f2
.
author | Ritor1 |
---|---|
date | Fri, 19 Sep 2014 00:03:04 +0600 |
parents | 82d5d92a097c |
children | 68cdef6879a0 |
files | Actor.cpp Actor.h Chest.cpp Chest.h Engine/Objects/NPC.cpp Engine/Objects/NPC.h Engine/Objects/ObjectList.cpp Engine/Objects/ObjectList.h Engine/Objects/Player.cpp Engine/Objects/Player.h Engine/Objects/Player.swig Engine/Objects/SpriteObject.cpp Engine/Objects/SpriteObject.h Items.cpp Items.h Monsters.cpp Monsters.h NPC.cpp NPC.h ObjectList.cpp ObjectList.h Player.cpp Player.h Player.swig SpriteObject.cpp SpriteObject.h |
diffstat | 26 files changed, 24707 insertions(+), 13444 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Actor.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,5717 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS + +#include "Engine/Graphics/PaletteManager.h" +#include "ErrorHandling.h" + +#include "Engine/Graphics/DecalBuilder.h" + +#include "Engine/Graphics/Sprites.h" +#include "stru6.h" + + +#include "Actor.h" +#include "OurMath.h" +#include "Engine/Graphics/Outdoor.h" +#include "AudioPlayer.h" +#include "Game.h" +#include "ObjectList.h" +#include "Engine/Graphics/Overlays.h" +#include "FactionTable.h" +#include "TurnEngine.h" +#include "CastSpellInfo.h" +#include "Timer.h" +#include "LOD.h" +#include "Party.h" +#include "GUIWindow.h" + +#include "MM7.h" +#include "SpriteObject.h" +#include "stru298.h" +#include "Log.h" +#include "Texts.h" +#include "Engine/Graphics/Level/Decoration.h" +#include "Engine/Graphics/Viewport.h" +#include "Engine/Graphics/Vis.h" + + + + + +std::array<Actor, 500> pActors; +size_t uNumActors; + +stru319 stru_50C198; // idb + + +std::array<uint, 5> _4DF380_hostilityRanges = {0, 1024, 2560, 5120, 10240}; + + + + +//----- (0042FB5C) -------------------------------------------------------- +// True if monster should play attack animation when casting this spell. +bool ShouldMonsterPlayAttackAnim(signed int spell_id) +{ + switch (spell_id) + { + case SPELL_FIRE_HASTE: + case SPELL_AIR_SHIELD: + case SPELL_EARTH_STONESKIN: + case SPELL_SPIRIT_BLESS: + case SPELL_SPIRIT_FATE: + case SPELL_SPIRIT_HEROISM: + case SPELL_BODY_HAMMERHANDS: + case SPELL_BODY_POWER_CURE: + case SPELL_LIGHT_DISPEL_MAGIC: + case SPELL_LIGHT_DAY_OF_PROTECTION: + case SPELL_LIGHT_HOUR_OF_POWER: + case SPELL_DARK_PAIN_REFLECTION: + return false; + } + + return true; +} + + +//----- (0041AF52) -------------------------------------------------------- +void Actor::DrawHealthBar(Actor *actor, GUIWindow *window) +{ + unsigned int bar_length; // esi@1 + unsigned int uX; // ebx@10 + unsigned int v9; // [sp+14h] [bp-Ch]@4 + unsigned int v10; // [sp+1Ch] [bp-4h]@4 + + if (actor->pMonsterInfo.uHP <= 25) + bar_length = 25; + else if ( actor->pMonsterInfo.uHP < 200 ) + bar_length = actor->pMonsterInfo.uHP; + else + bar_length = 200; + + v10 = bar_length; + if ( actor->sCurrentHP <= (0.34 * actor->pMonsterInfo.uHP) ) + v9 = uTextureID_mhp_red; + else if ( actor->sCurrentHP <= ( 0.67 * actor->pMonsterInfo.uHP) ) + v9 = uTextureID_mhp_yel; + else + v9 = uTextureID_mhp_grn; + + if ( actor->sCurrentHP < (int)actor->pMonsterInfo.uHP ) + v10 = bar_length / actor->pMonsterInfo.uHP * actor->sCurrentHP; + + uX = window->uFrameX + (signed int)(window->uFrameWidth - bar_length) / 2; + + pRenderer->SetTextureClipRect(uX, window->uFrameY + 32, uX + bar_length, window->uFrameY + 52); + pRenderer->DrawTextureIndexed(uX, window->uFrameY + 32, pIcons_LOD->GetTexture(uTextureID_mhp_bd)); + pRenderer->SetTextureClipRect(uX, window->uFrameY + 32, uX + v10, window->uFrameY + 52); + pRenderer->DrawTextureIndexed(uX, window->uFrameY + 34, pIcons_LOD->GetTexture(v9)); + + pRenderer->ResetTextureClipRect(); + pRenderer->DrawTextureIndexed(uX - 5, window->uFrameY + 32, pIcons_LOD->GetTexture(uTextureID_mhp_capl)); + pRenderer->DrawTextureIndexed(uX + bar_length, window->uFrameY + 32, pIcons_LOD->GetTexture(uTextureID_mhp_capr)); +} + +//----- (00448A40) -------------------------------------------------------- +void Actor::ToggleFlag(signed int uActorID, unsigned int uFlag, int bToggle) +{ + if ( uActorID >= 0 && uActorID <= (signed int)(uNumActors - 1) ) + { + if ( bToggle ) + pActors[uActorID].uAttributes |= uFlag; + else + { + if ( uFlag == 0x10000 ) + { + if (pActors[uActorID].uAIState == Disabled ) + pActors[uActorID].uAIState = Standing; + } + pActors[uActorID].uAttributes &= ~uFlag; + } + } +} + +//----- (00448518) -------------------------------------------------------- +void __fastcall sub_448518_npc_set_item(int npc, unsigned int item, int a3) +{ + for (uint i = 0; i < uNumActors; i++) + { + if (pActors[uNumActors].sNPC_ID == npc) + Actor::GiveItem(i, item, a3); + } +} + +//----- (004485A7) -------------------------------------------------------- +void Actor::GiveItem(signed int uActorID, unsigned int uItemID, unsigned int bGive) +{ + if ( (uActorID >= 0) && (signed int)uActorID <= (signed int)(uNumActors - 1) ) + { + if ( bGive ) + { + if ( pActors[uActorID].uCarriedItemID == 0) + pActors[uActorID].uCarriedItemID = uItemID; + else if ( pActors[uActorID].ActorHasItems[0].uItemID == 0) + pActors[uActorID].ActorHasItems[0].uItemID = uItemID; + else if ( pActors[uActorID].ActorHasItems[1].uItemID == 0) + pActors[uActorID].ActorHasItems[1].uItemID = uItemID; + } + else + { + if ( pActors[uActorID].uCarriedItemID == uItemID ) + pActors[uActorID].uCarriedItemID = 0; + else if ( pActors[uActorID].ActorHasItems[0].uItemID == uItemID ) + pActors[uActorID].ActorHasItems[0].Reset(); + else if ( pActors[uActorID].ActorHasItems[1].uItemID == uItemID ) + pActors[uActorID].ActorHasItems[1].Reset(); + } + } +} + +//----- (0040894B) -------------------------------------------------------- +bool Actor::CanAct() +{ + bool isparalyzed; // esi@1 + bool isstoned; // edi@2 + + isstoned = (signed __int64)this->pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0;// stoned + isparalyzed = (signed __int64)this->pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime > 0;// paralyzed + return !(isstoned || isparalyzed || this->uAIState == Dying || this->uAIState == Dead + || this->uAIState == Removed || this->uAIState == Summoned || this->uAIState == Disabled); +} + +//----- (004089C7) -------------------------------------------------------- +bool Actor::IsNotAlive() +{ + bool isstoned; // esi@1 + + isstoned = (signed __int64)this->pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0;// stoned + return (isstoned || (uAIState == Dying) || (uAIState == Dead) || (uAIState == Removed) || (uAIState == Summoned) || (uAIState == Disabled)); +} + +//----- (004086E9) -------------------------------------------------------- +void Actor::SetRandomGoldIfTheresNoItem() +{ + int v2; // edi@1 + + v2 = 0; + if ( !this->ActorHasItems[3].uItemID ) + { + if ( this->pMonsterInfo.uTreasureDiceRolls ) + { + for (int i = 0; i < this->pMonsterInfo.uTreasureDiceRolls; i++) + v2 += rand() % this->pMonsterInfo.uTreasureDiceSides + 1; + if ( v2 ) + { + this->ActorHasItems[3].uItemID = 197; + this->ActorHasItems[3].uSpecEnchantmentType = v2; //actual gold amount + } + } + } + if ( rand() % 100 < this->pMonsterInfo.uTreasureDropChance ) + { + if ( this->pMonsterInfo.uTreasureLevel ) + pItemsTable->GenerateItem(this->pMonsterInfo.uTreasureLevel, this->pMonsterInfo.uTreasureType, &this->ActorHasItems[2]); + } + this->uAttributes |= ACTOR_HAS_ITEM; +} + +//----- (00404AC7) -------------------------------------------------------- +void Actor::AI_SpellAttack(unsigned int uActorID, AIDirection *pDir, int uSpellID, int a4, unsigned int uSkillLevel) +{ + Actor *actorPtr; // esi@1 + unsigned int realPoints; // edi@1 + unsigned int masteryLevel; // eax@1 + int v8; // edi@16 + signed int v10; // ecx@22 + int v19; // edi@34 + int v20; // eax@35 + signed int v23; // eax@41 + int v28; // st6@50 + int v30; // esi@50 + int v31; // ST3C_4@51 + unsigned int v32; // edi@51 + signed int v36; // eax@67 + int v39; // ecx@75 + int v42; // ecx@91 + int v44; // ecx@100 + int v48; // ecx@110 + int v51; // ecx@130 + int v54; // ecx@138 + int v59; // edi@146 + int v61; // edi@146 + signed int v63; // edi@146 + int v68; // edi@168 + signed int v70; // ecx@172 + int v79; // edx@185 + int v80; // eax@185 + signed int v91; // eax@200 + int v94; // ecx@208 + int v96; // ecx@217 + int pitch; // [sp+2Ch] [bp-A4h]@51 + int v114; // [sp+48h] [bp-88h]@41 + SpriteObject a1; // [sp+4Ch] [bp-84h]@1 + int v116; // [sp+BCh] [bp-14h]@49 + int v118; // [sp+C4h] [bp-Ch]@29 + int v119; // [sp+C8h] [bp-8h]@48 + int v120; // [sp+CCh] [bp-4h]@1 + int spellnuma; // [sp+D8h] [bp+8h]@29 + int spellnumb; // [sp+D8h] [bp+8h]@48 + int spellnumc; // [sp+D8h] [bp+8h]@50 + int spellnume; // [sp+D8h] [bp+8h]@179 + int a1a; // [sp+E0h] [bp+10h]@34 + int a1c; // [sp+E0h] [bp+10h]@184 + + + actorPtr = &pActors[uActorID]; + realPoints = uSkillLevel & 0x3F; + masteryLevel = SkillToMastery(uSkillLevel); + + switch (uSpellID) + { + case SPELL_FIRE_FIRE_BOLT: + case SPELL_FIRE_FIREBALL: + case SPELL_FIRE_INCINERATE: + case SPELL_AIR_LIGHNING_BOLT: + case SPELL_WATER_ICE_BOLT: + case SPELL_WATER_ACID_BURST: + case SPELL_EARTH_BLADES: + case SPELL_EARTH_ROCK_BLAST: + case SPELL_MIND_MIND_BLAST: + case SPELL_MIND_PSYCHIC_SHOCK: + case SPELL_BODY_HARM: + case SPELL_LIGHT_LIGHT_BOLT: + case SPELL_DARK_TOXIC_CLOUD: + case SPELL_DARK_DRAGON_BREATH: + a1.uType = stru_4E3ACC[uSpellID].uType; + a1.uObjectDescID = GetObjDescId(uSpellID); + a1.stru_24.Reset(); + a1.spell_id = uSpellID; + a1.spell_level = uSkillLevel; + a1.vPosition.x = actorPtr->vPosition.x; + a1.spell_skill = 0; + a1.vPosition.y = actorPtr->vPosition.y; + a1.vPosition.z = actorPtr->vPosition.z + ((signed int)actorPtr->uActorHeight >> 1); + a1.uFacing = LOWORD(pDir->uYawAngle); + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z); + a1.uSpriteFrameID = 0; + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.spell_target_pid = 0; + if ((double)pDir->uDistance < 307.2 ) + a1.field_60_distance_related_prolly_lod = 0; + else if ( pDir->uDistance < 1024 ) + a1.field_60_distance_related_prolly_lod = 1; + else if ( pDir->uDistance < 2560 ) + a1.field_60_distance_related_prolly_lod = 2; + else + a1.field_60_distance_related_prolly_lod = 3; + + a1.field_61 = 2; + v91 = a1.Create(pDir->uYawAngle, pDir->uPitchAngle, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + if ( v91 != -1 ) + { + pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], PID(OBJECT_Item, v91), 0, -1, 0, 0, 0, 0); + return; + } + return; + break; + + case SPELL_FIRE_HASTE: + if (masteryLevel == 1 || masteryLevel == 2) + v39 = 60 * (realPoints + 60); + else if (masteryLevel == 3 ) + v39 = 180 * (realPoints + 20); + else if (masteryLevel == 4 ) + v39 = 240 * (realPoints + 15); + else + v39 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_HASTE].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(v39 << 7) * 0.033333335), + masteryLevel, 0, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr, 0xFF3C1Eu); + pAudioPlayer->PlaySound((SoundID)10040, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_FIRE_METEOR_SHOWER: + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + return; + v114 = pParty->vPosition.z + 2500; + v23 = 8; + if (masteryLevel == 2) + v23 = 10; + else if (masteryLevel == 3) + v23 = 12; + else if (masteryLevel == 4) + v23 = 14; + spellnumb = 0; + v28 = 0; + for ( int i = 0; i < v23; i++) + { + v30 = rand() % 1000; + spellnumc = v30 - 2500; + v120 = v28 * v28; + v119 = spellnumb * spellnumb; + if ( sqrt((float)(spellnumc * spellnumc + v119 + v120)) <= 1.0 ) + { + v32 = 0; + pitch = 0; + } + else + { + v31 = (signed __int64)sqrt((float)(v119 + v120)); + v32 = stru_5C6E00->Atan2(spellnumb, (int)v28); + pitch = stru_5C6E00->Atan2(v31, (int)spellnumc); + } + a1.stru_24.Reset(); + a1.uType = stru_4E3ACC[uSpellID].uType; + a1.uObjectDescID = GetObjDescId(uSpellID); + a1.spell_level = uSkillLevel; + a1.vPosition.x = pParty->vPosition.x; + a1.vPosition.y = pParty->vPosition.y; + a1.vPosition.z = v30 + v114; + a1.spell_id = SPELL_FIRE_METEOR_SHOWER; + a1.spell_skill = 0; + a1.uAttributes = 0; + a1.uSectorID = 0; + a1.uSpriteFrameID = 0; + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.spell_target_pid = 0; + a1.field_60_distance_related_prolly_lod = stru_50C198._427546(v30 + 2500); + a1.uFacing = v32; + a1.uSoundID = 0; + if (pDir->uDistance < 307.2 ) + a1.field_60_distance_related_prolly_lod = 0; + else if ( pDir->uDistance < 1024 ) + a1.field_60_distance_related_prolly_lod = 1; + else if ( pDir->uDistance < 2560 ) + a1.field_60_distance_related_prolly_lod = 2; + else + a1.field_60_distance_related_prolly_lod = 3; + a1.field_61 = 2; + v36 = a1.Create(v32, pitch, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + if ( v36 != -1 ) + pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[9], PID(OBJECT_Item, v36), 0, -1, 0, 0, 0, 0); + spellnumb = rand() % 1024 - 512; + v28 = rand() % 1024 - 512; + } + return; + break; + + case SPELL_AIR_SPARKS: + if (masteryLevel == 2 ) + v10 = 5; + else if (masteryLevel == 3 ) + v10 = 7; + else if (masteryLevel == 4 ) + v10 = 9; + else + v10 = 3; + spellnuma = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360; + a1.uType = stru_4E3ACC[uSpellID].uType; + v118 = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360 / (v10 - 1); + a1.uObjectDescID = GetObjDescId(uSpellID); + + a1.stru_24.Reset(); + a1.spell_id = SPELL_AIR_SPARKS; + a1.spell_level = uSkillLevel; + a1.vPosition.x = actorPtr->vPosition.x; + a1.spell_skill = 0; + a1.vPosition.y = actorPtr->vPosition.y; + a1.vPosition.z = actorPtr->vPosition.z + ((signed int)actorPtr->uActorHeight >> 1); + a1.uFacing = pDir->uYawAngle; + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z); + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.uSpriteFrameID = 0; + a1.spell_target_pid = 0; + a1.field_60_distance_related_prolly_lod = 3; + v19 = spellnuma / -2; + a1a = spellnuma / 2; + if ( spellnuma / -2 > spellnuma / 2 ) + v20 = spellnuma / 2; + else + { + do + { + a1.uFacing = v19 + LOWORD(pDir->uYawAngle); + v20 = a1.Create((signed __int16)a1.uFacing, pDir->uPitchAngle, + pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + v19 += v118; + } + while ( v19 <= a1a ); + } + if ( v20 != -1 ) + { + pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[15], PID(OBJECT_Item, v20), 0, -1, 0, 0, 0, 0); + return; + } + return; + break; + + case SPELL_AIR_SHIELD: + if (masteryLevel == 1 || masteryLevel == 2) + v8 = 300 * realPoints + 3840; + else if (masteryLevel == 3 ) + v8 = 900 * realPoints + 3840; + else if (masteryLevel == 4 ) + v8 = 3600 * (realPoints + 64); + else + v8 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_SHIELD].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v8 << 7) * 0.033333335), + masteryLevel, 0, 0, 0); + return; + + case SPELL_EARTH_STONESKIN: + if (masteryLevel == 1 || masteryLevel == 2) + v44 = 300 * realPoints + 3840; + else if (masteryLevel == 3 ) + v44 = 900 * realPoints + 3840; + else if (masteryLevel == 4 ) + v44 = 3600 * (realPoints + 64); + else + v44 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_STONESKIN].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v44 << 7) * 0.033333335), + masteryLevel, realPoints + 5, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr,0x5C310Eu); + pAudioPlayer->PlaySound((SoundID)13040, PID(OBJECT_Actor,uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_SPIRIT_BLESS: + if (masteryLevel == 1 || masteryLevel == 2) + v42 = 300 * realPoints + 3840; + else if (masteryLevel == 3 ) + v42 = 900 * realPoints + 3840; + else if (masteryLevel == 4 ) + v42 = 1200 * realPoints + 3840; + else + v42 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_BLESS].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v42 << 7) * 0.033333335), + masteryLevel, realPoints + 5, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr,0xC8C805u); + pAudioPlayer->PlaySound((SoundID)14010, PID(OBJECT_Actor,uActorID), 0, -1, 0, 0, 0, 0); + return; + break; + + case SPELL_SPIRIT_FATE: + if (masteryLevel == 1 || masteryLevel == 2) + v48 = 2 * realPoints + 40; + else if (masteryLevel == 3 ) + v48 = 3 * realPoints + 60; + else if (masteryLevel == 4 ) + v48 = 2 * (3 * realPoints + 60); + else + v48 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_FATE].Apply(pParty->uTimePlayed + 1280, masteryLevel, v48, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr,0xC8C805u); + pAudioPlayer->PlaySound((SoundID)14020, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_SPIRIT_HEROISM: + if (masteryLevel == 1 || masteryLevel == 2) + v54 = 300 * realPoints + 3840; + else if (masteryLevel == 3 ) + v54 = 900 * realPoints + 3840; + else if (masteryLevel == 4 ) + v54 = 1200 * realPoints + 3840; + else + v54 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_HEROISM].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v54 << 7) * 0.033333335), + masteryLevel, realPoints + 5, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr,0xC8C805u); + pAudioPlayer->PlaySound((SoundID)14060, PID(OBJECT_Actor,uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_BODY_HAMMERHANDS: + if ( (signed int)masteryLevel <= 0 || (signed int)masteryLevel > 4 ) + v51 = 0; + else + v51 = 3600 * realPoints; + actorPtr->pActorBuffs[ACTOR_BUFF_PAIN_HAMMERHANDS].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v51 << 7) * 0.033333335), + masteryLevel, + realPoints, + 0, + 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr, 0xA81376u); + pAudioPlayer->PlaySound((SoundID)16060, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_BODY_POWER_CURE: + actorPtr->sCurrentHP += 5 * realPoints + 10; + if ( actorPtr->sCurrentHP >= (signed int)actorPtr->pMonsterInfo.uHP ) + actorPtr->sCurrentHP = LOWORD(actorPtr->pMonsterInfo.uHP); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr, 0xA81376u); + pAudioPlayer->PlaySound((SoundID)14020, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_LIGHT_DISPEL_MAGIC: + for (int i = 0; i < 20; i++ ) + pParty->pPartyBuffs[i].Reset(); + for (int i = 1; i <= 4; i++) + { + v59 = pPlayers[i]->GetParameterBonus(pPlayers[i]->GetActualWillpower()); + v61 = (pPlayers[i]->GetParameterBonus(pPlayers[i]->GetActualIntelligence()) + v59) / 2; + v63 = v61 + pPlayers[i]->GetParameterBonus(pPlayers[i]->GetActualLuck()) + 30; + if ( rand() % v63 < 30 ) + { + for (uint k = 0; k < pPlayers[i]->pPlayerBuffs.size(); k++) + pPlayers[i]->pPlayerBuffs[k].Reset(); + pOtherOverlayList->_4418B1(11210, i + 99, 0, 65536); + } + } + pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[80], PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_LIGHT_DAY_OF_PROTECTION: + if (masteryLevel == 1 || masteryLevel == 2) + v96 = 300 * realPoints + 3840; + else if (masteryLevel == 3 ) + { + LOWORD(realPoints) = 3 * realPoints; + v96 = 900 * (uSkillLevel & 0x3F) + 3840; + } + else if (masteryLevel == 4 ) + { + v96 = 1200 * realPoints + 3840; + LOWORD(realPoints) = 4 * realPoints; + } + else + { + LOWORD(realPoints) = uSkillLevel; + v96 = 0; + } + actorPtr->pActorBuffs[ACTOR_BUFF_DAY_OF_PROTECTION].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v96 << 7) * 0.033333335), + masteryLevel, realPoints, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr, 0xFFFFFFu); + pAudioPlayer->PlaySound((SoundID)17070, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_LIGHT_HOUR_OF_POWER: + if (masteryLevel == 1 || masteryLevel == 2) + v94 = 300 * realPoints + 3840; + else if (masteryLevel == 3) + v94 = 900 * realPoints + 3840; + else if (masteryLevel == 4) + v94 = 1200 * realPoints + 3840; + else + v94 = 0; + actorPtr->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v94 << 7) * 0.033333335), + masteryLevel, realPoints + 5, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr, 0xFFFFFFu); + pAudioPlayer->PlaySound((SoundID)17080, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + + case SPELL_DARK_SHARPMETAL: + if (masteryLevel == 2) + v70 = 5; + else if (masteryLevel == 3) + v70 = 7; + else if (masteryLevel == 4) + v70 = 9; + else + v70 = 3; + + spellnume = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360; + a1.uType = stru_4E3ACC[uSpellID].uType; + v116 = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360 / (v70 - 1); + a1.uObjectDescID = GetObjDescId(uSpellID); + a1.stru_24.Reset(); + a1.spell_id = uSpellID; + a1.spell_level = uSkillLevel; + a1.vPosition.x = actorPtr->vPosition.x; + a1.spell_skill = 0; + a1.vPosition.y = actorPtr->vPosition.y; + a1.vPosition.z = actorPtr->vPosition.z + ((signed int)actorPtr->uActorHeight >> 1); + a1.uFacing = pDir->uYawAngle; + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z); + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.uSpriteFrameID = 0; + a1.spell_target_pid = 0; + a1.field_60_distance_related_prolly_lod = 3; + a1c = spellnume / -2; + if ( spellnume / -2 > spellnume / 2 ) + v80 = spellnume / -2; + else + { + do + { + v79 = pDir->uYawAngle; + a1.uFacing = a1c + LOWORD(pDir->uYawAngle); + v80 = a1.Create(v79, pDir->uPitchAngle, + pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + a1c += v116; + } + while ( a1c <= spellnume / 2 ); + } + if ( v80 != -1 ) + { + pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[93], PID(OBJECT_Item, v80), 0, -1, 0, 0, 0, 0); + return; + } + return; + break; + + case SPELL_DARK_PAIN_REFLECTION: + if (masteryLevel == 0) + v68 = 0; + else if (masteryLevel == 1 || (masteryLevel == 2) || (masteryLevel == 3)) + v68 = 300 * realPoints + 3840; + else + v68 = 900 * realPoints + 3840; + actorPtr->pActorBuffs[ACTOR_BUFF_PAIN_REFLECTION].Apply( + pParty->uTimePlayed + (signed int)(signed __int64)((double)(v68 << 7) * 0.033333335), + masteryLevel, 0, 0, 0); + pGame->pStru6Instance->_4A7E89_sparkles_on_actor_after_it_casts_buff(actorPtr,0x7E7E7Eu); + pAudioPlayer->PlaySound((SoundID)18060, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + return; + } +} + +//----- (new func) -------------------------------------------------------- +unsigned short Actor::GetObjDescId( int spellId ) +{ + for (unsigned int i = 0; i < pObjectList->uNumObjects; i++) + { + if (stru_4E3ACC[spellId].uType == pObjectList->pObjects[i].uObjectID) + { + return i; + break; + } + } + return 0; +} + + +//----- (0043ABB0) -------------------------------------------------------- +bool Actor::ArePeasantsOfSameFaction(Actor *a1, Actor *a2) +{ + unsigned int v2; // esi@1 + unsigned int v3; // edi@1 + + v2 = a1->uAlly; + if ( !a1->uAlly ) + v2 = (a1->pMonsterInfo.uID - 1) / 3 + 1; + + v3 = a2->uAlly; + if ( !a2->uAlly ) + v3 = (a2->pMonsterInfo.uID - 1) / 3 + 1; + + if ( v2 >= 39 && v2 <= 44 && v3 >= 39 && v3 <= 44 + || v2 >= 45 && v2 <= 50 && v3 >= 45 && v3 <= 50 + || v2 >= 51 && v2 <= 62 && v3 >= 51 && v3 <= 62 + || v2 >= 78 && v2 <= 83 && v3 >= 78 && v3 <= 83 + || v2 == v3 + ) + return true; + else + return false; +} + +//----- (0043AC45) -------------------------------------------------------- +void Actor::AggroSurroundingPeasants(unsigned int uActorID, int a2) +{ + int v4; // ebx@8 + int v5; // ST1C_4@8 + int v6; // eax@8 + + int x = 0; x |= 0x80000; + int y = 0; y |= 0x80000; + Actor* victim = &pActors[uActorID]; + if ( a2 == 1 ) + victim->uAttributes |= ACTOR_AGGRESSOR; + + for (uint i = 0; i < uNumActors; ++i) + { + Actor* actor = &pActors[i]; + if (!actor->CanAct() || i == uActorID) + continue; + + if (Actor::ArePeasantsOfSameFaction(victim, actor)) + { + v4 = abs(actor->vPosition.x - victim->vPosition.x); + v5 = abs(actor->vPosition.y - victim->vPosition.y); + v6 = abs(actor->vPosition.z - victim->vPosition.z); + if (int_get_vector_length(v4, v5, v6) < 4096) + { + actor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Long; + if ( a2 == 1 ) + actor->uAttributes |= ACTOR_AGGRESSOR; + + } + } + } +} + +//----- (00404874) -------------------------------------------------------- +void Actor::AI_RangedAttack( unsigned int uActorID, struct AIDirection *pDir, int type, char a4 ) +{ + char specAb; // al@1 + int v13; // edx@28 + + SpriteObject a1; // [sp+Ch] [bp-74h]@1 + + switch ( type ) + { + case 1: + a1.uType = 545; + break; + case 2: + a1.uType = 550; + break; + case 3: + a1.uType = 510; + break; + case 4: + a1.uType = 500; + break; + case 5: + a1.uType = 515; + break; + case 6: + a1.uType = 505; + break; + case 7: + a1.uType = 530; + break; + case 8: + a1.uType = 525; + break; + case 9: + a1.uType = 520; + break; + case 10: + a1.uType = 535; + break; + case 11: + a1.uType = 540; + break; + case 13: + a1.uType = 555; + break; + default: + return; + } + bool found = false; + for ( uint i = 0; i < pObjectList->uNumObjects; i++) + { + if (pObjectList->pObjects[i].uObjectID == a1.uType) + { + a1.uObjectDescID = i; + found = true; + break; + } + } + if (!found) + { + Error("Item not found"); + return; + } + a1.stru_24.Reset(); + a1.spell_id = 0; + a1.vPosition.x = pActors[uActorID].vPosition.x; + a1.vPosition.y = pActors[uActorID].vPosition.y; + a1.vPosition.z = pActors[uActorID].vPosition.z - (unsigned int)(pActors[uActorID].uActorHeight * -0.75); + a1.spell_level = 0; + a1.spell_skill = 0; + a1.uFacing = pDir->uYawAngle; + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z); + a1.uSpriteFrameID = 0; + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.spell_target_pid = 0; + if (pDir->uDistance < 307.2 ) + a1.field_60_distance_related_prolly_lod = 0; + else if ( pDir->uDistance < 1024 ) + a1.field_60_distance_related_prolly_lod = 1; + else if ( pDir->uDistance < 2560 ) + a1.field_60_distance_related_prolly_lod = 2; + else + a1.field_60_distance_related_prolly_lod = 3; + + a1.field_61 = a4; + a1.Create(pDir->uYawAngle, pDir->uPitchAngle, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + if ( pActors[uActorID].pMonsterInfo.uSpecialAbilityType == 1 ) + { + specAb = pActors[uActorID].pMonsterInfo.uSpecialAbilityDamageDiceBonus; + if ( specAb == 2 ) + { + a1.vPosition.z += 40; + v13 = pDir->uYawAngle; + } + else + { + if ( specAb != 3 ) + return; + a1.Create(pDir->uYawAngle + 30, //TODO find out why the YawAngle change + pDir->uPitchAngle, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + v13 = pDir->uYawAngle - 30; + } + a1.Create(v13, pDir->uPitchAngle, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0); + } + return; +} + +//----- (00404736) -------------------------------------------------------- +void Actor::Explode( unsigned int uActorID ) +{ + SpriteObject a1; // [sp+Ch] [bp-78h]@1 + + a1.uType = 600; + a1.uObjectDescID = GetObjDescId(a1.uType); + a1.stru_24.Reset(); + a1.spell_id = 0; + a1.spell_level = 0; + a1.spell_skill = 0; + a1.vPosition.x = pActors[uActorID].vPosition.x; + a1.vPosition.y = pActors[uActorID].vPosition.y; + a1.vPosition.z = pActors[uActorID].vPosition.z - (unsigned int)(pActors[uActorID].uActorHeight * -0.75); + a1.uFacing = 0; + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z); + a1.uSpriteFrameID = 0; + a1.spell_caster_pid = PID(OBJECT_Actor, uActorID); + a1.spell_target_pid = 0; + a1.field_60_distance_related_prolly_lod = 3; + a1.field_61 = 4; + a1.Create(0, 0, 0, 0); + return; +} + +//----- (004040E9) -------------------------------------------------------- +// // Get direction vector from object1 to object2, +// // distance from object1 to object2 and Euler angles of the direction vector +// // +// // +// // object1 & object2 format : objectType | (objectID << 3) +// // objectType == 2 - SpriteObject +// // objectType == 3 - Actor +// // objectType == 4 - Party +// // objectType == 5 - Decoration +// // +// // originally this function had following prototype: +// // struct DirectionInfo GetDirectionInfo(signed int object1, signed int object2, signed int a4) +// // but compiler converts functions returning structures by value in the such way +void Actor::GetDirectionInfo( unsigned int uObj1ID, unsigned int uObj2ID, struct AIDirection *pOut, int a4 ) +{ + signed int v4; // eax@1 + signed int v5; // ecx@1 + int v18; // edx@15 + float v31; // st7@45 + float v32; // st6@45 + float v33; // st7@45 + Vec3_int_ v37; // [sp-10h] [bp-5Ch]@15 + AIDirection v41; // [sp+14h] [bp-38h]@46 + float outy2; // [sp+38h] [bp-14h]@33 + float outx2; // [sp+3Ch] [bp-10h]@33 + int outz; // [sp+40h] [bp-Ch]@6 + int outy; // [sp+44h] [bp-8h]@6 + int outx; // [sp+48h] [bp-4h]@6 + float a4a; // [sp+58h] [bp+Ch]@45 + + v4 = PID_ID(uObj1ID); + //v6 = uObj2ID; + v5 = PID_ID(uObj2ID); + switch( PID_TYPE(uObj1ID) ) + { + case OBJECT_Item: + { + outx = pSpriteObjects[v4].vPosition.x; + outy = pSpriteObjects[v4].vPosition.y; + outz = pSpriteObjects[v4].vPosition.z; + break; + } + case OBJECT_Actor: + { + outx = pActors[v4].vPosition.x; + outy = pActors[v4].vPosition.y; + outz = pActors[v4].vPosition.z - (unsigned int)(signed __int64)((double)pActors[v4].uActorHeight * -0.75); + break; + } + case OBJECT_Player: + { + if ( !v4 ) + { + outx = pParty->vPosition.x; + outy = pParty->vPosition.y; + outz = pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3; + break; + } + if ( v4 == 4 ) + { + v18 = pParty->sRotationY - stru_5C6E00->uIntegerHalfPi; + v37.z = pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3; + v37.x = pParty->vPosition.x; + v37.y = pParty->vPosition.y; + Vec3_int_::Rotate(24, v18, 0, v37, &outx, &outy, &outz); + break; + } + if ( v4 == 3 ) + { + v18 = pParty->sRotationY - stru_5C6E00->uIntegerHalfPi; + v37.z = pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3; + v37.x = pParty->vPosition.x; + v37.y = pParty->vPosition.y; + Vec3_int_::Rotate(8, v18, 0, v37, &outx, &outy, &outz); + break; + } + if ( v4 == 2 ) + { + v37.z = pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3; + v18 = stru_5C6E00->uIntegerHalfPi + pParty->sRotationY; + v37.x = pParty->vPosition.x; + v37.y = pParty->vPosition.y; + Vec3_int_::Rotate(8, v18, 0, v37, &outx, &outy, &outz); + break; + } + if ( v4 == 1 ) + { + v37.z = pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3; + v18 = stru_5C6E00->uIntegerHalfPi + pParty->sRotationY; + v37.x = pParty->vPosition.x; + v37.y = pParty->vPosition.y; + Vec3_int_::Rotate(24, v18, 0, v37, &outx, &outy, &outz); + break; + } + } + case OBJECT_Decoration: + { + outx = pLevelDecorations[v4].vPosition.x; + outy = pLevelDecorations[v4].vPosition.y; + outz = pLevelDecorations[v4].vPosition.z; + break; + } + default: + { + outz = 0; + outy = 0; + outx = 0; + break; + } + case OBJECT_BModel: + { + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + { + outx = (pIndoor->pFaces[v4].pBounding.x1 + pIndoor->pFaces[v4].pBounding.x2) >> 1; + outy = (pIndoor->pFaces[v4].pBounding.y1 + pIndoor->pFaces[v4].pBounding.y2) >> 1; + outz = (pIndoor->pFaces[v4].pBounding.z1 + pIndoor->pFaces[v4].pBounding.z2) >> 1; + } + break; + } + } + + switch( PID_TYPE(uObj2ID) ) + { + case OBJECT_Item: + { + outx2 = (float)pSpriteObjects[v5].vPosition.x; + outy2 =(float) pSpriteObjects[v5].vPosition.y; + a4 = pSpriteObjects[v5].vPosition.z; + break; + } + case OBJECT_Actor: + { + outx2 = (float)pActors[v5].vPosition.x; + outy2 = (float)pActors[v5].vPosition.y; + a4 = pActors[v5].vPosition.z - (unsigned int)(signed __int64)((double)pActors[v5].uActorHeight * -0.75); + break; + } + case OBJECT_Player: + { + outx2 = (float)pParty->vPosition.x; + outy2 = (float)pParty->vPosition.y; + if ( !a4 ) + a4 = pParty->sEyelevel; + a4 = pParty->vPosition.z + a4; + break; + } + case OBJECT_Decoration: + { + outx2 = (float)pLevelDecorations[v5].vPosition.x; + outy2 = (float)pLevelDecorations[v5].vPosition.y; + a4 = pLevelDecorations[v5].vPosition.z; + break; + } + default: + { + outx2 = 0.0; + outy2 = 0.0; + a4 = 0; + break; + } + case OBJECT_BModel: + { + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + { + outx2 = (float)((pIndoor->pFaces[v5].pBounding.x1 + pIndoor->pFaces[v5].pBounding.x2) >> 1); + outy2 = (float)((pIndoor->pFaces[v5].pBounding.y1 + pIndoor->pFaces[v5].pBounding.y2) >> 1); + a4 = (pIndoor->pFaces[v5].pBounding.z1 + pIndoor->pFaces[v5].pBounding.z2) >> 1; + } + break; + } + } + + v31 = (float)outx2 - (float)outx; + v32 = (float)outy2 - (float)outy; + a4a = (float)a4 - (float)outz; + outx2 = v32 * v32; + outy2 = v31 * v31; + v33 = sqrt(a4a * a4a + outy2 + outx2); + if ( v33 <= 1.0 ) + { + pOut->vDirection.x = 65536; + pOut->vDirection.y = 0; + pOut->vDirection.z = 0; + pOut->uDistance = 1; + pOut->uDistanceXZ = 1; + pOut->uYawAngle = 0; + pOut->uPitchAngle = 0; + } + else + { + pOut->vDirection.x = (int32_t)(1.0 / v33 * v31 * 65536.0); + pOut->vDirection.y = (int32_t)(1.0 / v33 * v32 * 65536.0); + pOut->vDirection.z = (int32_t)(1.0 / v33 * a4a * 65536.0); + pOut->uDistance = (uint)v33; + pOut->uDistanceXZ = (uint)sqrt(outy2 + outx2); + pOut->uYawAngle = stru_5C6E00->Atan2((signed __int64)v31, (signed __int64)v32); + pOut->uPitchAngle = stru_5C6E00->Atan2(pOut->uDistanceXZ, (signed __int64)a4a); + } +} + +//----- (00404030) -------------------------------------------------------- +void Actor::AI_FaceObject(unsigned int uActorID, unsigned int uObjID, int _48, AIDirection *a4) +{ + AIDirection *v7; // eax@3 + AIDirection v1; // eax@3 + AIDirection a3; // [sp+8h] [bp-38h]@4 + + if ( rand() % 100 >= 5 ) + { + //v9 = &pActors[uActorID]; + if ( !a4 ) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), uObjID, &v1, 0); + v7 = &v1; + } + else + v7 = a4; + pActors[uActorID].uYawAngle = v7->uYawAngle; + pActors[uActorID].uCurrentActionTime = 0; + pActors[uActorID].vVelocity.z = 0; + pActors[uActorID].vVelocity.y = 0; + pActors[uActorID].vVelocity.x = 0; + pActors[uActorID].uPitchAngle = v7->uPitchAngle; + pActors[uActorID].uCurrentActionLength = 256; + pActors[uActorID].uAIState = Interacting; + pActors[uActorID].UpdateAnimation(); + } + else + Actor::AI_Bored(uActorID, uObjID, a4); +} + +//----- (00403F58) -------------------------------------------------------- +void Actor::AI_StandOrBored(unsigned int uActorID, signed int uObjID, int uActionLength, AIDirection *a4) +{ + if (rand() % 2)//0 or 1 + AI_Bored(uActorID, uObjID, a4); + else + AI_Stand(uActorID, uObjID, uActionLength, a4); +} + +//----- (00403EB6) -------------------------------------------------------- +void Actor::AI_Stand(unsigned int uActorID, unsigned int object_to_face_pid, unsigned int uActionLength, AIDirection *a4) +{ + assert(uActorID < uNumActors); + // Actor* actor = &pActors[uActorID]; + + AIDirection a3; + if (!a4) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), object_to_face_pid, &a3, 0); + a4 = &a3; + } + + pActors[uActorID].uAIState = Standing; + if (!uActionLength) + pActors[uActorID].uCurrentActionLength = rand() % 256 + 256;// îò 256 äî 256 + 256 + else + pActors[uActorID].uCurrentActionLength = uActionLength; + pActors[uActorID].uCurrentActionTime = 0; + pActors[uActorID].uYawAngle = a4->uYawAngle; + pActors[uActorID].uPitchAngle = a4->uPitchAngle; + pActors[uActorID].vVelocity.z = 0; + pActors[uActorID].vVelocity.y = 0; + pActors[uActorID].vVelocity.x = 0; + pActors[uActorID].UpdateAnimation(); +} + +//----- (00403E61) -------------------------------------------------------- +void __fastcall Actor::StandAwhile(unsigned int uActorID) +{ + pActors[uActorID].uCurrentActionLength = rand() % 128 + 128; + pActors[uActorID].uCurrentActionTime = 0; + pActors[uActorID].uAIState = Standing; + pActors[uActorID].vVelocity.z = 0; + pActors[uActorID].vVelocity.y = 0; + pActors[uActorID].vVelocity.x = 0; + pActors[uActorID].UpdateAnimation(); +} + +//----- (00403C6C) -------------------------------------------------------- +void Actor::AI_MeleeAttack(unsigned int uActorID, signed int sTargetPid, struct AIDirection *arg0) +{ + int16_t v6; // esi@6 + int16_t v7; // edi@6 + signed int v8; // eax@7 + Vec3_int_ v10; // ST04_12@9 + AIDirection *v12; // eax@11 + AIDirection a3; // [sp+Ch] [bp-48h]@12 + AIDirection v20; // [sp+28h] [bp-2Ch]@12 + int v23; // [sp+4Ch] [bp-8h]@6 + unsigned int v25; // [sp+5Ch] [bp+8h]@13 + + assert(uActorID < uNumActors); + + if ( pActors[uActorID].pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY && pActors[uActorID].pMonsterInfo.uAIType == 1 ) + { + Actor::AI_Stand(uActorID, sTargetPid, 0, arg0); + return; + } + + if ( PID_TYPE(sTargetPid) == OBJECT_Actor) + { + v8 = PID_ID(sTargetPid); + v6 = pActors[v8].vPosition.x; + v7 = pActors[v8].vPosition.y; + v23 = (int)(pActors[v8].uActorHeight * 0.75 + pActors[v8].vPosition.z); + } + else if ( PID_TYPE(sTargetPid) == OBJECT_Player) + { + v6 = pParty->vPosition.x; + v7 = pParty->vPosition.y; + v23 = pParty->vPosition.z + pParty->sEyelevel; + } + else + { + Error("Should not get here"); + return; + } + + v10.x = pActors[uActorID].vPosition.x; + v10.y = pActors[uActorID].vPosition.y; + v10.z = (int32_t)(pActors[uActorID].uActorHeight * 0.75 + pActors[uActorID].vPosition.z); + + if ( sub_407A1C((int)v6, (int)v7, v23, v10) ) + { + if (arg0 != nullptr) + v12 = arg0; + else + { + Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), sTargetPid, &a3, 0); + v12 = &a3; + } + pActors[uActorID].uYawAngle = LOWORD(v12->uYawAngle); + pActors[uActorID].uCurrentActionLength = pSpriteFrameTable->pSpriteSFrames[pActors[uActorID].pSpriteIDs[ANIM_AtkMelee]].uAnimLength * 8; + pActors[uActorID].uCurrentActionTime = 0; + pActors[uActorID].uAIState = AttackingMelee; + Actor::PlaySound(uActorID, 0); + v25 = pMonsterStats->pInfos[pActors[uActorID].pMonsterInfo.uID].uRecoveryTime; + if ( pActors[uActorID].pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0 ) + v25 *= 2; + if ( pParty->bTurnBasedModeOn != 1 ) + pActors[uActorID].pMonsterInfo.uRecoveryTime = (int)(flt_6BE3A8_debug_recmod2 * v25 * 2.133333333333333); + else + pActors[uActorID].pMonsterInfo.uRecoveryTime = v25; + pActors[uActorID].vVelocity.z = 0; + pActors[uActorID].vVelocity.y = 0; + pActors[uActorID].vVelocity.x = 0; + pActors[uActorID].UpdateAnimation(); + } + else + Actor::AI_Pursue1(uActorID, sTargetPid, rand() % 2, 64, arg0); +} + +//----- (00438CF3) -------------------------------------------------------- +void Actor::ApplyFineForKillingPeasant(unsigned int uActorID) +{ + if ( uLevelMapStatsID == 0 || !pActors[uActorID].IsPeasant()) + return; + + if ( (uLevelMapStatsID == 6 || uLevelMapStatsID == 7) && pParty->IsPartyEvil()) //celeste and bracada + return; + + if ( (uLevelMapStatsID == 5 || uLevelMapStatsID == 8) && pParty->IsPartyGood()) // the pit and deyja + return; + + pParty->uFine += 100 * (pMapStats->pInfos[uLevelMapStatsID]._steal_perm + pActors[uActorID].pMonsterInfo.uLevel + pParty->GetPartyReputation()); + if ( pParty->uFine < 0 ) + pParty->uFine = 0; + if ( pParty->uFine > 4000000 ) + pParty->uFine = 4000000; + + if (uCurrentlyLoadedLevelType == LEVEL_Outdoor) + { + if (pOutdoor->ddm.uReputation < 10000) + pOutdoor->ddm.uReputation++; + } + else if (uCurrentlyLoadedLevelType == LEVEL_Indoor) + { + if (pIndoor->dlv.uReputation < 10000) + pIndoor->dlv.uReputation++; + } + else assert(false); + + if ( pParty->uFine ) + { + for ( int i = 1; i <= 4; i++) + { + if ( !_449B57_test_bit(pPlayers[i]->_achieved_awards_bits, 1) ) + _449B7E_toggle_bit(pPlayers[i]->_achieved_awards_bits, 1, 1u); + } + } +} + +//----- (0043AE80) -------------------------------------------------------- +void Actor::AddBloodsplatOnDamageOverlay(unsigned int uActorID, int a2, signed int a3) +{ + unsigned int v4; // esi@1 + + v4 = PID(OBJECT_Actor,uActorID); + switch ( a2 ) + { + case 1: + if ( a3 ) + pOtherOverlayList->_4418B6(904, v4, 0, (int)(sub_43AE12(a3) * 65536.0), 0); + return; + case 2: + if ( a3 ) + pOtherOverlayList->_4418B6(905, v4, 0, (int)(sub_43AE12(a3) * 65536.0), 0); + return; + case 3: + if ( a3 ) + pOtherOverlayList->_4418B6(906, v4, 0, (int)(sub_43AE12(a3) * 65536.0), 0); + return; + case 4: + if ( a3 ) + pOtherOverlayList->_4418B6(907, v4, 0, (int)(sub_43AE12(a3) * 65536.0), 0); + return; + case 5: + pOtherOverlayList->_4418B6(901, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + case 6: + pOtherOverlayList->_4418B6(902, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + case 7: + pOtherOverlayList->_4418B6(903, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + case 8: + pOtherOverlayList->_4418B6(900, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + case 9: + pOtherOverlayList->_4418B6(909, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + case 10: + pOtherOverlayList->_4418B6(908, v4, 0, PID(OBJECT_Actor,uActorID), 0); + return; + default: + return; + } + return; +} + +//----- (0043B3E0) -------------------------------------------------------- +int Actor::_43B3E0_CalcDamage( signed int dmgSource ) +{ + signed int v2; // ebp@1 + int v3; // eax@9 + signed int v4; // edi@9 + int v5; // esi@9 + unsigned __int16 v8; // si@21 + int v9; // edi@21 + signed int v10; // eax@23 + int v11; // [sp+10h] [bp-4h]@1 + + v2 = 0; + v11 = 0; + + switch( dmgSource ) + { + case 0: + if ( this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + v2 = this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_HEROISM].uExpireTime > 0 && this->pActorBuffs[ACTOR_BUFF_HEROISM].uPower > v2 ) + v2 = this->pActorBuffs[ACTOR_BUFF_HEROISM].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_PAIN_HAMMERHANDS].uExpireTime > 0 ) + v2 += this->pActorBuffs[ACTOR_BUFF_PAIN_HAMMERHANDS].uPower; + v3 = this->pMonsterInfo.uAttack1DamageDiceRolls; + v4 = this->pMonsterInfo.uAttack1DamageDiceSides; + v5 = this->pMonsterInfo.uAttack1DamageBonus; + break; + case 1: + v3 = this->pMonsterInfo.uAttack2DamageDiceRolls; + v4 = this->pMonsterInfo.uAttack2DamageDiceSides; + v5 = this->pMonsterInfo.uAttack2DamageBonus; + break; + case 2: + v8 = this->pMonsterInfo.uSpellSkillAndMastery1; + v9 = this->pMonsterInfo.uSpell1ID; + v10 = SkillToMastery(v8); + return _43AFE3_calc_spell_damage(v9, v8 & 0x3F, v10, 0); + break; + case 3: + v8 = this->pMonsterInfo.uSpellSkillAndMastery2; + v9 = this->pMonsterInfo.uSpell2ID; + v10 = SkillToMastery(v8); + return _43AFE3_calc_spell_damage(v9, v8 & 0x3F, v10, 0); + break; + case 4: + v3 = this->pMonsterInfo.uSpecialAbilityDamageDiceRolls; + v4 = this->pMonsterInfo.uSpecialAbilityDamageDiceSides; + v5 = this->pMonsterInfo.uSpecialAbilityDamageDiceBonus; + default: + return 0; + } + for ( int i = 0; i < v3; i++) + v11 += rand() % v4 + 1; + return v11 + v5 + v2; +} + +//----- (00438B9B) -------------------------------------------------------- +bool Actor::IsPeasant() +{ + unsigned int InHostile_Id; // eax@1 + + InHostile_Id = this->uAlly; + if ( !this->uAlly ) + InHostile_Id = (this->pMonsterInfo.uID - 1) / 3 + 1; + return (signed int)InHostile_Id >= 39 && (signed int)InHostile_Id <= 44//Dwarfs peasants + || (signed int)InHostile_Id >= 45 && (signed int)InHostile_Id <= 50//Elves peasants + || (signed int)InHostile_Id >= 51 && (signed int)InHostile_Id <= 62//Humans peasants + || (signed int)InHostile_Id >= 78 && (signed int)InHostile_Id <= 83;//Goblins peasants +} + +//----- (0042EBEE) -------------------------------------------------------- +void Actor::StealFrom( unsigned int uActorID ) +{ + Player *pPlayer; // edi@1 + int v4; // ebx@2 + unsigned int v5; // eax@2 + DDM_DLV_Header *v6; // esi@4 + int v8; // [sp+8h] [bp-4h]@6 + + pPlayer = &pParty->pPlayers[uActiveCharacter-1]; + if ( pPlayer->CanAct() ) + { + CastSpellInfoHelpers::_427D48(); + v4 = 0; + v5 = pMapStats->GetMapInfo(pCurrentMapName); + if ( v5 ) + v4 = pMapStats->pInfos[v5]._steal_perm; + v6 = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor) + v6 = &pIndoor->dlv; + pPlayer->StealFromActor(uActorID, v4, v6->uReputation++); + v8 = pPlayer->GetAttackRecoveryTime(0); + if ( v8 < 30 ) + v8 = 30; + if ( !pParty->bTurnBasedModeOn ) + pPlayer->SetRecoveryTime((int)(flt_6BE3A4_debug_recmod1 * v8 * 2.133333333333333)); + pTurnEngine->ApplyPlayerAction(); + } + return; +} + +//----- (00403A60) -------------------------------------------------------- +void Actor::AI_SpellAttack2(unsigned int uActorID, signed int edx0, AIDirection *pDir) +{ + Actor *v3; // ebx@1 + int16_t v4; // esi@3 + int16_t v5; // edi@3 + signed int v6; // eax@4 + Vec3_int_ v7; // ST04_12@6 + AIDirection *v9; // eax@8 + __int16 v13; // ax@10 + AIDirection a3; // [sp+Ch] [bp-48h]@9 + AIDirection v18; // [sp+28h] [bp-2Ch]@9 + int v19; // [sp+44h] [bp-10h]@6 + signed int a2; // [sp+48h] [bp-Ch]@1 + int v21; // [sp+4Ch] [bp-8h]@3 + unsigned int pDira; // [sp+5Ch] [bp+8h]@10 + + v3 = &pActors[uActorID]; + a2 = edx0; + if ( PID_TYPE(edx0) == OBJECT_Actor) + { + v6 = PID_ID(edx0); + v4 = pActors[v6].vPosition.x; + v5 = pActors[v6].vPosition.y; + v21 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z); + } + else if ( PID_TYPE(edx0) == OBJECT_Player) + { + v4 = pParty->vPosition.x; + v5 = pParty->vPosition.y; + v21 = pParty->vPosition.z + pParty->sEyelevel; + } + else + { + Error("Should not get here"); + return; + } + v19 = v3->uActorHeight; + v7.z = v3->vPosition.z - (int)(v19 * -0.75); + v7.y = v3->vPosition.y; + v7.x = v3->vPosition.x; + if ( sub_407A1C(v4, v5, v21, v7) ) + { + if ( pDir == nullptr) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), a2, &a3, 0); + v9 = &a3; + } + else + v9 = pDir; + v3->uYawAngle = LOWORD(v9->uYawAngle); + v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]].uAnimLength; + v3->uCurrentActionLength = 8 * v13; + v3->uCurrentActionTime = 0; + v3->uAIState = AttackingRanged4; + Actor::PlaySound(uActorID, 0); + pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime; + if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0) + pDira *= 2; + if ( pParty->bTurnBasedModeOn == 1 ) + v3->pMonsterInfo.uRecoveryTime = pDira; + else + v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength + (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333); + v3->vVelocity.z = 0; + v3->vVelocity.y = 0; + v3->vVelocity.x = 0; + if ( ShouldMonsterPlayAttackAnim(v3->pMonsterInfo.uSpell2ID) ) + { + v3->uCurrentActionLength = 64; + v3->uCurrentActionTime = 0; + v3->uAIState = Fidgeting; + v3->UpdateAnimation(); + v3->uAIState = AttackingRanged4; + } + else + v3->UpdateAnimation(); + } + else + Actor::AI_Pursue1(uActorID, a2, uActorID, 64, pDir); +} + +//----- (00403854) -------------------------------------------------------- +void Actor::AI_SpellAttack1(unsigned int uActorID, signed int sTargetPid, AIDirection *pDir) +{ + Actor *v3; // ebx@1 + int16_t v4; // esi@3 + int16_t v5; // edi@3 + signed int v6; // eax@4 + Vec3_int_ v7; // ST04_12@6 + AIDirection *v9; // eax@8 + __int16 v13; // ax@10 + signed int v16; // ecx@17 + AIDirection a3; // [sp+Ch] [bp-48h]@9 + AIDirection v18; // [sp+28h] [bp-2Ch]@9 + int v19; // [sp+44h] [bp-10h]@6 + int v21; // [sp+4Ch] [bp-8h]@3 + unsigned int pDira; // [sp+5Ch] [bp+8h]@10 + + v3 = &pActors[uActorID]; + if ( PID_TYPE(sTargetPid) == OBJECT_Actor) + { + v6 = PID_ID(sTargetPid); + v4 = pActors[v6].vPosition.x; + v5 = pActors[v6].vPosition.y; + v21 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z); + } + else if ( PID_TYPE(sTargetPid) == OBJECT_Player) + { + v4 = pParty->vPosition.x; + v5 = pParty->vPosition.y; + v21 = pParty->vPosition.z + pParty->sEyelevel; + } + else + { + Error("Should not get here"); + return; + } + v19 = v3->uActorHeight; + v7.z = v3->vPosition.z - (int)(v19 * -0.75); + v7.y = v3->vPosition.y; + v7.x = v3->vPosition.x; + if ( sub_407A1C(v4, v5, v21, v7) ) + { + if ( pDir == nullptr ) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), sTargetPid, &a3, 0); + v9 = &a3; + } + else + v9 = pDir; + v3->uYawAngle = LOWORD(v9->uYawAngle); + v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]].uAnimLength; + v3->uCurrentActionLength = 8 * v13; + v3->uCurrentActionTime = 0; + v3->uAIState = AttackingRanged3; + Actor::PlaySound(uActorID, 0); + pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime; + if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0) + pDira *= 2; + if ( pParty->bTurnBasedModeOn == 1 ) + v3->pMonsterInfo.uRecoveryTime = pDira; + else + v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength + (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333); + v16 = v3->pMonsterInfo.uSpell1ID; + v3->vVelocity.z = 0; + v3->vVelocity.y = 0; + v3->vVelocity.x = 0; + if ( ShouldMonsterPlayAttackAnim(v3->pMonsterInfo.uSpell1ID) ) + { + v3->uCurrentActionLength = 64; + v3->uCurrentActionTime = 0; + v3->uAIState = Fidgeting; + v3->UpdateAnimation(); + v3->uAIState = AttackingRanged3; + } + else + v3->UpdateAnimation(); + } + else + Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir); +} + +//----- (0040368B) -------------------------------------------------------- +void Actor::AI_MissileAttack2(unsigned int uActorID, signed int sTargetPid, AIDirection *pDir) +{ + Actor *v3; // ebx@1 + int16_t v4; // esi@3 + int16_t v5; // edi@3 + signed int v6; // eax@4 + Vec3_int_ v7; // ST04_12@6 + AIDirection *v9; // eax@8 + __int16 v13; // ax@10 + AIDirection a3; // [sp+Ch] [bp-48h]@9 + AIDirection v17; // [sp+28h] [bp-2Ch]@9 + int v18; // [sp+44h] [bp-10h]@6 + int v20; // [sp+4Ch] [bp-8h]@3 + unsigned int pDira; // [sp+5Ch] [bp+8h]@10 + + v3 = &pActors[uActorID]; + if ( PID_TYPE(sTargetPid) == OBJECT_Actor) + { + v6 = PID_ID(sTargetPid); + v4 = pActors[v6].vPosition.x; + v5 = pActors[v6].vPosition.y; + v20 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z); + } + else if ( PID_TYPE(sTargetPid) == OBJECT_Player) + { + v4 = pParty->vPosition.x; + v5 = pParty->vPosition.y; + v20 = pParty->vPosition.z + pParty->sEyelevel; + } + else + { + Error("Should not get here"); + return; + } + v18 = v3->uActorHeight; + v7.z = v3->vPosition.z - (int)(v18 * -0.75); + v7.y = v3->vPosition.y; + v7.x = v3->vPosition.x; + if ( sub_407A1C(v4, v5, v20, v7) ) + { + if ( pDir == nullptr ) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), sTargetPid, &a3, 0); + v9 = &a3; + } + else + v9 = pDir; + v3->uYawAngle = LOWORD(v9->uYawAngle); + v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]].uAnimLength; + v3->uCurrentActionLength = 8 * v13; + v3->uCurrentActionTime = 0; + v3->uAIState = AttackingRanged2; + Actor::PlaySound(uActorID, 0); + pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime; + if ( v3->pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0 ) + pDira *= 2; + if ( pParty->bTurnBasedModeOn != 1 ) + v3->pMonsterInfo.uRecoveryTime = (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333); + else + v3->pMonsterInfo.uRecoveryTime = pDira; + v3->vVelocity.z = 0; + v3->vVelocity.y = 0; + v3->vVelocity.x = 0; + v3->UpdateAnimation(); + } + else + Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir); +} + +//----- (00403476) -------------------------------------------------------- +void Actor::AI_MissileAttack1(unsigned int uActorID, signed int sTargetPid, AIDirection *pDir) +{ + Actor *v3; // ebx@1 + int v4; // esi@3 + int v5; // edi@3 + signed int v6; // eax@4 + Vec3_int_ v7; // ST04_12@6 + AIDirection *v10; // eax@9 + __int16 v14; // ax@11 + AIDirection a3; // [sp+Ch] [bp-48h]@10 + AIDirection v18; // [sp+28h] [bp-2Ch]@10 + int v19; // [sp+44h] [bp-10h]@6 + //signed int a2; // [sp+48h] [bp-Ch]@1 + int v22; // [sp+50h] [bp-4h]@3 + unsigned int pDira; // [sp+5Ch] [bp+8h]@11 + + v3 = &pActors[uActorID]; + //a2 = edx0; + if ( PID_TYPE(sTargetPid) == OBJECT_Actor) + { + v6 = PID_ID(sTargetPid); + v4 = pActors[v6].vPosition.x; + v5 = pActors[v6].vPosition.y; + v22 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z); + } + else + { + if ( PID_TYPE(sTargetPid) == OBJECT_Player) + { + v4 = pParty->vPosition.x; + v5 = pParty->vPosition.y; + v22 = pParty->vPosition.z + pParty->sEyelevel; + } + else + { + v4 = (int)pDir; + v5 = (int)pDir; + } + } + v19 = v3->uActorHeight; + v7.z = v3->vPosition.z - (unsigned int)(signed __int64)((double)v19 * -0.75); + v7.y = v3->vPosition.y; + v7.x = v3->vPosition.x; + if ( sub_407A1C(v4, v5, v22, v7) || sub_407A1C(v7.x, v7.y, v7.z, Vec3_int_(v4, v5, v22))) + { + if ( pDir == nullptr ) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), sTargetPid, &a3, 0); + v10 = &a3; + } + else + v10 = pDir; + v3->uYawAngle = LOWORD(v10->uYawAngle); + v14 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]].uAnimLength; + v3->uCurrentActionLength = 8 * v14; + v3->uCurrentActionTime = 0; + v3->uAIState = AttackingRanged1; + Actor::PlaySound(uActorID, 0); + pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime; + if ( v3->pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0 ) + pDira *= 2; + if ( pParty->bTurnBasedModeOn == 1 ) + v3->pMonsterInfo.uRecoveryTime = pDira; + else + v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength - (int)(flt_6BE3A8_debug_recmod2 * pDira * -2.133333333333333); + v3->vVelocity.z = 0; + v3->vVelocity.y = 0; + v3->vVelocity.x = 0; + v3->UpdateAnimation(); + } + else + Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir); +} + +//----- (004032B2) -------------------------------------------------------- +void Actor::AI_RandomMove( unsigned int uActor_id, unsigned int uTarget_id, int radius, int uActionLength ) +{ + int x; // ebx@1 + int absy; // eax@1 + unsigned int v9; // ebx@11 + int v10; // ebx@13 + AIDirection doNotInitializeBecauseShouldBeRandom; // [sp+Ch] [bp-30h]@7 + int y; // [sp+30h] [bp-Ch]@1 + int absx; // [sp+38h] [bp-4h]@1 + + x = pActors[uActor_id].vInitialPosition.x - pActors[uActor_id].vPosition.x; + y = pActors[uActor_id].vInitialPosition.y - pActors[uActor_id].vPosition.y; + absx = abs(x); + absy = abs(y); + if ( absx <= absy ) + absx = absy + (absx / 2 ); + else + absx = absx + absy / 2; + if ( MonsterStats::BelongsToSupertype(pActors[uActor_id].pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_StandOrBored(uActor_id, OBJECT_Player, uActionLength, &doNotInitializeBecauseShouldBeRandom); + return; + } + if ( pActors[uActor_id].pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_GLOBAL && absx < 128 ) + { + Actor::AI_Stand(uActor_id, uTarget_id, 256, &doNotInitializeBecauseShouldBeRandom); + return; + } + absx += ((rand() & 0xF) * radius) / 16; + v9 = (stru_5C6E00->uIntegerDoublePi - 1) & stru_5C6E00->Atan2(x, y); + if ( rand() % 100 < 25 ) + { + Actor::StandAwhile(uActor_id); + return; + } + v10 = v9 + rand() % 256 - 128; + if ( abs(v10 - pActors[uActor_id].uYawAngle) > 256 && !(pActors[uActor_id].uAttributes & ACTOR_ANIMATION) ) + { + Actor::AI_Stand(uActor_id, uTarget_id, 256, &doNotInitializeBecauseShouldBeRandom); + return; + } + pActors[uActor_id].uYawAngle = v10; + if ( pActors[uActor_id].uMovementSpeed) + pActors[uActor_id].uCurrentActionLength = 32 * absx / pActors[uActor_id].uMovementSpeed; + else + pActors[uActor_id].uCurrentActionLength = 0; + pActors[uActor_id].uCurrentActionTime = 0; + pActors[uActor_id].uAIState = Tethered; + if ( rand() % 100 < 2 ) + Actor::PlaySound(uActor_id, 3); + pActors[uActor_id].UpdateAnimation(); +} + +//----- (004031C1) -------------------------------------------------------- +char __fastcall Actor::_4031C1_update_job_never_gets_called(unsigned int uActorID, signed int a2, int a3) //attempted to implement something like jobs for actors, but apparently was never finished +{ + return 0; + /*unsigned int v3; // edi@1 + Actor *v4; // esi@1 + ActorJob *v5; // eax@1 + signed int v6; // edx@2 + ActorJob *v7; // eax@2 + signed int v8; // edi@2 + ActorJob *v9; // ecx@2 + __int16 v10; // cx@15 + signed int v12; // [sp+8h] [bp-4h]@1 + + v3 = uActorID; + v12 = a2; + v4 = &pActors[uActorID]; + v5 = (ActorJob *)pActors[uActorID].CanAct(); + if ( v5 ) + { + v6 = 65535; + v7 = &v4->pScheduledJobs[v3]; + v8 = 7; + v9 = &v7[7];//(char *)&v7[7].uHour; + while ( !(v9->uAttributes & 1) || v9->uHour > v12 ) + { + --v8; + --v9; + if ( v8 < 0 ) + break; + } + if( v8 >= 0 ) + v6 = v8; + if ( !v8 && v6 == 65535 ) + v6 = 7; + v5 = &v7[v6]; + if ( v4->vInitialPosition.x != v5->vPos.x + || v4->vInitialPosition.y != v5->vPos.y + || v4->vInitialPosition.z != v5->vPos.z + || v4->pMonsterInfo.uMovementType != v5->uAction ) + { + v4->vInitialPosition.x = v5->vPos.x; + v4->vInitialPosition.y = v5->vPos.y; + v10 = v5->vPos.z; + v4->vInitialPosition.z = v10; + LOBYTE(v5) = v5->uAction; + v4->pMonsterInfo.uMovementType = MONSTER_MOVEMENT_TYPE_STAIONARY; + if ( a3 == 1 ) + { + v4->vPosition.x = v4->vInitialPosition.x; + v4->vPosition.y = v4->vInitialPosition.y; + LOBYTE(v5) = v10; + v4->vPosition.z = v10; + } + } + } + return (char)v5;*/ +} + +//----- (004030AD) -------------------------------------------------------- +void Actor::AI_Stun(unsigned int uActorID, signed int edx0, int stunRegardlessOfState) +{ + __int16 v7; // ax@16 + AIDirection a3; // [sp+Ch] [bp-40h]@16 + + if ( pActors[uActorID].uAIState == Fleeing ) + pActors[uActorID].uAttributes |= ACTOR_FLEEING; + if ( pActors[uActorID].pMonsterInfo.uHostilityType != 4 ) + { + pActors[uActorID].uAttributes &= 0xFFFFFFFB;//~0x4 + pActors[uActorID].pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Long; + } + if ( pActors[uActorID].pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime > 0 ) + pActors[uActorID].pActorBuffs[ACTOR_BUFF_CHARM].Reset(); + if ( pActors[uActorID].pActorBuffs[ACTOR_BUFF_AFRAID].uExpireTime > 0 ) + pActors[uActorID].pActorBuffs[ACTOR_BUFF_AFRAID].Reset(); + if ( stunRegardlessOfState || (pActors[uActorID].uAIState != Stunned + && pActors[uActorID].uAIState != AttackingRanged1 + && pActors[uActorID].uAIState != AttackingRanged2 + && pActors[uActorID].uAIState != AttackingRanged3 + && pActors[uActorID].uAIState != AttackingRanged4 + && pActors[uActorID].uAIState != AttackingMelee)) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), edx0, &a3, 0); + //v10 = &a3; + pActors[uActorID].uYawAngle = LOWORD(a3.uYawAngle); + v7 = pSpriteFrameTable->pSpriteSFrames[pActors[uActorID].pSpriteIDs[ANIM_GotHit]].uAnimLength; + pActors[uActorID].uCurrentActionTime = 0; + pActors[uActorID].uAIState = Stunned; + pActors[uActorID].uCurrentActionLength = 8 * v7; + Actor::PlaySound(uActorID, 2); + pActors[uActorID].UpdateAnimation(); + } +} + +//----- (00402F87) -------------------------------------------------------- +void Actor::AI_Bored(unsigned int uActorID, unsigned int uObjID, AIDirection *a4) +{ + unsigned int v7; // eax@3 + unsigned int v9; // eax@3 + + Actor* actor = &pActors[uActorID]; + + AIDirection a3; // [sp+Ch] [bp-5Ch]@2 + if (!a4) + { + Actor::GetDirectionInfo(PID(OBJECT_Actor,uActorID), uObjID, &a3, 0); + a4 = &a3; + } + + actor->uCurrentActionLength = 8 * pSpriteFrameTable->pSpriteSFrames[actor->pSpriteIDs[ANIM_Bored]].uAnimLength; + + v7 = stru_5C6E00->Atan2(actor->vPosition.x - pGame->pIndoorCameraD3D->vPartyPos.x, actor->vPosition.y - pGame->pIndoorCameraD3D->vPartyPos.y); + v9 = stru_5C6E00->uIntegerPi + actor->uYawAngle + ((signed int)stru_5C6E00->uIntegerPi >> 3) - v7; + + if ( v9 & 0x700 ) // turned away - just stand + Actor::AI_Stand(uActorID, uObjID, actor->uCurrentActionLength, a4); + else // facing player - play bored anim + { + actor->uAIState = Fidgeting; + actor->uCurrentActionTime = 0; + actor->uYawAngle = a4->uYawAngle; + actor->vVelocity.z = 0; + actor->vVelocity.y = 0; + actor->vVelocity.x = 0; + if ( rand() % 100 < 5 ) + Actor::PlaySound(uActorID, 3); + actor->UpdateAnimation(); + } +} + +//----- (00402F27) -------------------------------------------------------- +void Actor::Resurrect(unsigned int uActorID) +{ + Actor *pActor; // esi@1 + + pActor = &pActors[uActorID]; + pActor->uCurrentActionTime = 0; + pActor->uAIState = Resurrected; + pActor->uCurrentActionAnimation = ANIM_Dying; + pActor->uCurrentActionLength = 8 * pSpriteFrameTable->pSpriteSFrames[pActor->pSpriteIDs[ANIM_Dying]].uAnimLength; + pActor->sCurrentHP = LOWORD(pActor->pMonsterInfo.uHP); + Actor::PlaySound(uActorID, 1); + pActor->UpdateAnimation(); +} + +//----- (00402D6E) -------------------------------------------------------- +void Actor::Die(unsigned int uActorID) +{ + Actor* actor = &pActors[uActorID]; + + actor->uCurrentActionTime = 0; + actor->uAIState = Dying; + actor->uCurrentActionAnimation = ANIM_Dying; + actor->sCurrentHP = 0; + actor->uCurrentActionLength = 8 * pSpriteFrameTable->pSpriteSFrames[actor->pSpriteIDs[ANIM_Dying]].uAnimLength; + actor->pActorBuffs[ACTOR_BUFF_PARALYZED].Reset(); + actor->pActorBuffs[ACTOR_BUFF_STONED].Reset(); + Actor::PlaySound(uActorID, 1); + actor->UpdateAnimation(); + + for (uint i = 0; i < 5; ++i) + if (pParty->monster_id_for_hunting[i] == actor->pMonsterInfo.uID) + pParty->monster_for_hunting_killed[i] = true; + + for (uint i = 0; i < 22; ++i) + actor->pActorBuffs[i].Reset(); + + ItemGen drop; + drop.Reset(); + switch (actor->pMonsterInfo.uID) + { + case MONSTER_HARPY_1: case MONSTER_HARPY_2: case MONSTER_HARPY_3: + drop.uItemID = ITEM_HARPY_FEATHER; + break; + + case MONSTER_OOZE_1: case MONSTER_OOZE_2: case MONSTER_OOZE_3: + drop.uItemID = ITEM_OOZE_ECTOPLASM_BOTTLE; + break; + + case MONSTER_TROLL_1: case MONSTER_TROLL_2: case MONSTER_TROLL_3: + drop.uItemID = ITEM_TROLL_BLOOD; + break; + + case MONSTER_DEVIL_1: case MONSTER_DEVIL_2: case MONSTER_DEVIL_3: + drop.uItemID = ITEM_DEVIL_ICHOR; + break; + + case MONSTER_DRAGON_1: case MONSTER_DRAGON_2: case MONSTER_DRAGON_3: + drop.uItemID = ITEM_DRAGON_EYE; + break; + } + + if (rand() % 100 < 20 && drop.uItemID != 0) + { + SpriteObject::sub_42F7EB_DropItemAt(pItemsTable->pItems[drop.uItemID].uSpriteID, + actor->vPosition.x, + actor->vPosition.y, + actor->vPosition.z + 16, + rand() % 200 + 200, + 1, + 1, + 0, + &drop); + } + + if (actor->pMonsterInfo.uSpecialAbilityType == MONSTER_SPECIAL_ABILITY_EXPLODE) + Actor::Explode(uActorID); +} + +//----- (00402CED) -------------------------------------------------------- +void Actor::PlaySound(unsigned int uActorID, unsigned int uSoundID) +{ + unsigned __int16 v3; // dx@1 + + v3 = pActors[uActorID].pSoundSampleIDs[uSoundID]; + if ( v3 ) + { + if ( pActors[uActorID].pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime <= 0 ) + pAudioPlayer->PlaySound((SoundID)v3, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + else + { + switch(pActors[uActorID].pActorBuffs[ACTOR_BUFF_SHRINK].uPower) + { + case 1: + pAudioPlayer->PlaySound((SoundID)v3, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0, 0, 33075); + break; + case 2: + pAudioPlayer->PlaySound((SoundID)v3, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0, 0, 33075); + break; + case 3: + case 4: + pAudioPlayer->PlaySound((SoundID)v3, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0, 0, 33075); + break; + default: + pAudioPlayer->PlaySound((SoundID)v3, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0, 0, 0); + break; + } + } + } +} + +//----- (00402AD7) -------------------------------------------------------- +void Actor::AI_Pursue1(unsigned int uActorID, unsigned int a2, signed int arg0, signed int uActionLength, AIDirection *pDir) +{ + int v6; // eax@1 + Actor *v7; // ebx@1 + unsigned int v8; // ecx@1 + AIDirection *v10; // esi@6 + AIDirection a3; // [sp+Ch] [bp-5Ch]@7 + unsigned int v18; // [sp+64h] [bp-4h]@1 + + v6 = 0; + v7 = &pActors[uActorID]; + v8 = PID(OBJECT_Actor,uActorID); + if ( v7->pMonsterInfo.uFlying != 0 && !pParty->bFlying ) //TODO: Does v6 have a point? + { + if ( v7->pMonsterInfo.uMissleAttack1Type ) + v6 = v7->uActorRadius + 512; + else + v6 = pParty->uPartyHeight; + } + + if ( pDir == nullptr ) + { + Actor::GetDirectionInfo(v8, a2, &a3, v6); + v10 = &a3; + } + else + v10 = pDir; + if ( MonsterStats::BelongsToSupertype(v7->pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_StandOrBored(uActorID, 4, uActionLength, v10); + return; + } + if ( v10->uDistance < 307.2 ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_Stand(uActorID, a2, uActionLength, v10); + return; + } + if ( v7->uMovementSpeed == 0 ) + { + Actor::AI_Stand(uActorID, a2, uActionLength, v10); + return; + } + if ( arg0 % 2 ) + v18 = -16; + else + v18 = 16; + + v7->uYawAngle = stru_5C6E00->Atan2( + pParty->vPosition.x + (int)fixpoint_mul(stru_5C6E00->Cos(v18 + stru_5C6E00->uIntegerPi + v10->uYawAngle), v10->uDistanceXZ) - v7->vPosition.x, + pParty->vPosition.y + (int)fixpoint_mul(stru_5C6E00->Sin(v18 + stru_5C6E00->uIntegerPi + v10->uYawAngle), v10->uDistanceXZ) - v7->vPosition.y); + if ( uActionLength ) + v7->uCurrentActionLength = uActionLength; + else + v7->uCurrentActionLength = 128; + v7->uPitchAngle = LOWORD(v10->uPitchAngle); + v7->uAIState = Pursuing; + v7->UpdateAnimation(); +} + +//----- (00402968) -------------------------------------------------------- +void Actor::AI_Flee(unsigned int uActorID, signed int sTargetPid, int uActionLength, AIDirection *a4) +{ + Actor *v5; // ebx@1 + int v7; // ecx@2 + unsigned __int16 v9; // ax@15 + AIDirection v10; // [sp+8h] [bp-7Ch]@4 + AIDirection a3; // [sp+24h] [bp-60h]@3 + AIDirection* v13; // [sp+5Ch] [bp-28h]@4 + + v5 = &pActors[uActorID]; + if ( v5->CanAct() ) + { + v7 = PID(OBJECT_Actor,uActorID); + if ( !a4 ) + { + Actor::GetDirectionInfo(v7, sTargetPid, &a3, v5->pMonsterInfo.uFlying); + a4 = &a3; + } + Actor::GetDirectionInfo(v7, 4u, &v10, 0); + v13 = &v10; + if ( MonsterStats::BelongsToSupertype(v5->pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) + || PID_TYPE(sTargetPid) == OBJECT_Actor && v13->uDistance < 307.2 ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_StandOrBored(uActorID, 4, uActionLength, v13); + } + else + { + if ( v5->uMovementSpeed ) + v5->uCurrentActionLength = (signed int)(a4->uDistanceXZ << 7) / v5->uMovementSpeed; + else + v5->uCurrentActionLength = 0; + if ( v5->uCurrentActionLength > 256 ) + v5->uCurrentActionLength = 256; + v5->uYawAngle = LOWORD(stru_5C6E00->uIntegerHalfPi) + LOWORD(a4->uYawAngle); + v5->uYawAngle = LOWORD(stru_5C6E00->uDoublePiMask) & (v5->uYawAngle + rand() % (signed int)stru_5C6E00->uIntegerPi); + v9 = LOWORD(a4->uPitchAngle); + v5->uCurrentActionTime = 0; + v5->uPitchAngle = v9; + v5->uAIState = Fleeing; + v5->UpdateAnimation(); + } + } +} + +//----- (0040281C) -------------------------------------------------------- +void Actor::AI_Pursue2(unsigned int uActorID, unsigned int a2, signed int uActionLength, AIDirection *pDir, int a5) +{ + int v6; // eax@1 + Actor *v7; // ebx@1 + unsigned int v8; // ecx@1 + AIDirection *v10; // esi@7 + signed __int16 v13; // cx@19 + unsigned __int16 v14; // ax@25 + AIDirection a3; // [sp+Ch] [bp-40h]@8 + AIDirection v18; // [sp+28h] [bp-24h]@8 + + v6 = 0; + v7 = &pActors[uActorID]; + v8 = PID(OBJECT_Actor,uActorID); + if ( v7->pMonsterInfo.uFlying != 0 && !pParty->bFlying ) + { + if ( v7->pMonsterInfo.uMissleAttack1Type && uCurrentlyLoadedLevelType == LEVEL_Outdoor ) + v6 = v7->uActorRadius + 512; + else + v6 = pParty->uPartyHeight; + } + v10 = pDir; + if ( !pDir ) + { + Actor::GetDirectionInfo(v8, a2, &a3, v6); + v10 = &a3; + } + if ( MonsterStats::BelongsToSupertype(v7->pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_StandOrBored(uActorID, 4, uActionLength, v10); + return; + } + if ( (signed int)v10->uDistance < a5 ) + { + if ( !uActionLength ) + uActionLength = 256; + Actor::AI_StandOrBored(uActorID, a2, uActionLength, v10); + return; + } + if ( uActionLength ) + { + v7->uCurrentActionLength = uActionLength; + } + else + { + v13 = v7->uMovementSpeed; + if ( v13 ) + v7->uCurrentActionLength = (signed int)(v10->uDistanceXZ << 7) / v13; + else + v7->uCurrentActionLength = 0; + if ( v7->uCurrentActionLength > 32 ) + v7->uCurrentActionLength = 32; + } + v7->uYawAngle = LOWORD(v10->uYawAngle); + v14 = LOWORD(v10->uPitchAngle); + v7->uCurrentActionTime = 0; + v7->uPitchAngle = v14; + v7->uAIState = Pursuing; + v7->UpdateAnimation(); +} + +//----- (00402686) -------------------------------------------------------- +void Actor::AI_Pursue3(unsigned int uActorID, unsigned int a2, signed int uActionLength, AIDirection *a4) +{ + int v5; // eax@1 + Actor *v6; // ebx@1 + int v7; // ecx@1 + signed __int16 v12; // cx@19 + __int16 v14; // ax@25 + unsigned __int16 v16; // ax@28 + AIDirection a3; // [sp+Ch] [bp-40h]@8 + AIDirection* v20; // [sp+28h] [bp-24h]@8 + + v5 = 0; + v6 = &pActors[uActorID]; + v7 = PID(OBJECT_Actor,uActorID); + if ( v6->pMonsterInfo.uFlying != 0 && !pParty->bFlying ) + { + if ( v6->pMonsterInfo.uMissleAttack1Type && uCurrentlyLoadedLevelType == LEVEL_Outdoor ) + v5 = v6->uActorRadius + 512; + else + v5 = pParty->uPartyHeight; + } + if ( !a4 ) + { + Actor::GetDirectionInfo(v7, a2, &a3, v5); + v20 = &a3; + } + if ( MonsterStats::BelongsToSupertype(v6->pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + if ( !uActionLength ) + uActionLength = 256; + return Actor::AI_StandOrBored(uActorID, 4, uActionLength, a4); + } + if ( a4->uDistance < 307.2 ) + { + if ( !uActionLength ) + uActionLength = 256; + return Actor::AI_StandOrBored(uActorID, a2, uActionLength, a4); + } + if ( uActionLength ) + v6->uCurrentActionLength = uActionLength + rand() % uActionLength; + else + { + v12 = v6->uMovementSpeed; + if ( v12 ) + v6->uCurrentActionLength = (signed int)(a4->uDistanceXZ << 7) / v12; + else + v6->uCurrentActionLength = 0; + if ( v6->uCurrentActionLength > 128 ) + v6->uCurrentActionLength = 128; + } + v14 = LOWORD(a4->uYawAngle); + if ( rand() % 2 ) + v14 += 256; + else + v14 -= 256; + v6->uYawAngle = v14; + v16 = LOWORD(a4->uPitchAngle); + v6->uCurrentActionTime = 0; + v6->uPitchAngle = v16; + v6->uAIState = Pursuing; + if ( rand() % 100 < 2 ) + Actor::PlaySound(uActorID, 2u); + v6->UpdateAnimation(); +} + +//----- (00401221) -------------------------------------------------------- +void Actor::_SelectTarget(unsigned int uActorID, int *a2, bool can_target_party) +{ + int v5; // ecx@1 + signed int v10; // eax@13 + uint v11; // ebx@16 + uint v12; // eax@16 + signed int v14; // eax@31 + uint v15; // edi@43 + uint v16; // ebx@45 + uint v17; // eax@45 + signed int closestId; // [sp+14h] [bp-1Ch]@1 + uint v23; // [sp+1Ch] [bp-14h]@16 + unsigned int lowestRadius; // [sp+24h] [bp-Ch]@1 + uint v27; // [sp+2Ch] [bp-4h]@16 + uint v28; // [sp+2Ch] [bp-4h]@45 + + lowestRadius = UINT_MAX; + v5 = 0; + *a2 = 0; + closestId = 0; + assert(uActorID < uNumActors); + Actor* thisActor = &pActors[uActorID]; + + for (uint i = 0; i < uNumActors; ++i) + { + Actor* actor = &pActors[i]; + if (actor->uAIState == Dead || actor->uAIState == Dying || + actor->uAIState == Removed || actor->uAIState == Summoned || actor->uAIState == Disabled || uActorID == i ) + continue; + + if (thisActor->uLastCharacterIDToHit == 0 || PID(OBJECT_Actor,v5) != thisActor->uLastCharacterIDToHit ) + { + v10 = thisActor->GetActorsRelation(actor); + if ( v10 == 0 ) + continue; + } + else if (thisActor->IsNotAlive()) + { + thisActor->uLastCharacterIDToHit = 0; + v10 = thisActor->GetActorsRelation(actor); + if ( v10 == 0 ) + continue; + } + else + { + if ( (actor->uGroup != 0 || thisActor->uGroup != 0) && actor->uGroup == thisActor->uGroup ) + continue; + v10 = 4; + } + if ( thisActor->pMonsterInfo.uHostilityType ) + v10 = pMonsterStats->pInfos[thisActor->pMonsterInfo.uID].uHostilityType; + v11 = _4DF380_hostilityRanges[v10]; + v23 = abs(thisActor->vPosition.x - actor->vPosition.x); + v27 = abs(thisActor->vPosition.y - actor->vPosition.y); + v12 = abs(thisActor->vPosition.z - actor->vPosition.z); + if ( v23 <= v11 + && v27 <= v11 + && v12 <= v11 + && sub_4070EF_prolly_detect_player(PID(OBJECT_Actor, i), PID(OBJECT_Actor, uActorID)) + && v23 * v23 + v27 * v27 + v12 * v12 < lowestRadius ) + { + lowestRadius = v23 * v23 + v27 * v27 + v12 * v12; + closestId = i; + } + } + + if ( lowestRadius != UINT_MAX ) + { + *a2 = PID(OBJECT_Actor, closestId); + } + + if (can_target_party && !pParty->Invisible()) + { + if ( thisActor->ActorEnemy() + && thisActor->pActorBuffs[ACTOR_BUFF_ENSLAVED].uExpireTime <= 0 + && thisActor->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime <= 0 + && thisActor->pActorBuffs[ACTOR_BUFF_SUMMONED].uExpireTime <= 0 ) + v14 = 4; + else + v14 = thisActor->GetActorsRelation(0); + if ( v14 != 0 ) + { + if ( !thisActor->pMonsterInfo.uHostilityType ) + v15 = _4DF380_hostilityRanges[v14]; + else + v15 = _4DF380_hostilityRanges[4]; + v16 = abs(thisActor->vPosition.x - pParty->vPosition.x); + v28 = abs(thisActor->vPosition.y - pParty->vPosition.y); + v17 = abs(thisActor->vPosition.z - pParty->vPosition.z); + if ( v16 <= v15 && v28 <= v15 && v17 <= v15 && (v16 * v16 + v28 * v28 + v17 * v17 < lowestRadius)) + { + *a2 = OBJECT_Player; + } + } + } +} +// 4DF380: using guessed type int dword_4DF380[]; +// 4DF390: using guessed type int dword_4DF390; + +//----- (0040104C) -------------------------------------------------------- +signed int Actor::GetActorsRelation(Actor *otherActPtr) +{ + unsigned int thisGroup; // ebp@19 + int otherGroup; // eax@22 + unsigned int thisAlly; // edx@25 + unsigned int otherAlly; // edx@33 + + if ( otherActPtr) + { + if ( otherActPtr->uGroup != 0 && this->uGroup != 0 && otherActPtr->uGroup == this->uGroup ) + return 0; + } + + if (this->pActorBuffs[ACTOR_BUFF_BERSERK].uExpireTime > 0) + return 4; + thisAlly = this->uAlly; + if ( this->pActorBuffs[ACTOR_BUFF_ENSLAVED].uExpireTime > 0 || thisAlly == 9999) + thisGroup = 0; + else if ( thisAlly > 0 ) + thisGroup = thisAlly; + else + thisGroup = (this->pMonsterInfo.uID - 1) / 3 + 1; + + if ( otherActPtr ) + { + if (otherActPtr->pActorBuffs[ACTOR_BUFF_BERSERK].uExpireTime > 0) + return 4; + otherAlly = otherActPtr->uAlly; + if ( otherActPtr->pActorBuffs[ACTOR_BUFF_ENSLAVED].uExpireTime > 0 || otherAlly == 9999) + otherGroup = 0; + else if ( otherAlly > 0 ) + otherGroup = otherAlly; + else + otherGroup = (otherActPtr->pMonsterInfo.uID - 1) / 3 + 1; + } + else + otherGroup = 0; + + if ( this->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime > 0 && !otherGroup + || otherActPtr && otherActPtr->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime > 0 && !thisGroup ) + return 0; + if ( this->pActorBuffs[ACTOR_BUFF_ENSLAVED].uExpireTime <= 0 && this->ActorEnemy() && !otherGroup ) + return 4; + if (thisGroup >= 89 || otherGroup >= 89) + return 0; + + if ( thisGroup == 0 ) + { + if ( (!otherActPtr || this->pActorBuffs[ACTOR_BUFF_ENSLAVED].uExpireTime > 0 && otherActPtr->ActorFriend()) && !pFactionTable->relations[otherGroup][0]) + return pFactionTable->relations[0][otherGroup]; + else + return 4; + } + else + return pFactionTable->relations[thisGroup][otherGroup]; +} + +//----- (0045976D) -------------------------------------------------------- +void Actor::UpdateAnimation() +{ + ResetAnimation(); + switch (uAIState) + { + case Tethered: + uCurrentActionAnimation = ANIM_Walking; + break; + + case AttackingMelee: + uCurrentActionAnimation = ANIM_AtkMelee; + uAttributes |= ACTOR_ANIMATION; + break; + + case AttackingRanged1: + case AttackingRanged2: + case AttackingRanged3: + case AttackingRanged4: + uCurrentActionAnimation = ANIM_AtkRanged; + uAttributes |= ACTOR_ANIMATION; + break; + + case Dying: + case Resurrected: + uCurrentActionAnimation = ANIM_Dying; + uAttributes |= ACTOR_ANIMATION; + break; + + case Pursuing: + case Fleeing: + uCurrentActionAnimation = ANIM_Walking; + uAttributes |= ACTOR_ANIMATION; + break; + + case Stunned: + uCurrentActionAnimation = ANIM_GotHit; + uAttributes |= ACTOR_ANIMATION; + break; + + case Fidgeting: + uCurrentActionAnimation = ANIM_Bored; + uAttributes |= ACTOR_ANIMATION; + break; + + case Standing: + case Interacting: + case Summoned: + uCurrentActionAnimation = ANIM_Standing; + uAttributes |= ACTOR_ANIMATION; + break; + + case Dead: + if (pSpriteFrameTable->pSpriteSFrames[pSpriteIDs[ANIM_Dead]].pHwSpriteIDs[0] <= 0) + uAIState = Removed; + else + uCurrentActionAnimation = ANIM_Dead; + break; + + case Removed: + case Disabled: + return; + + default: + assert(false); + } +} + +//----- (00459671) -------------------------------------------------------- +void Actor::Reset() +{ + this->pActorName[0] = 0; + this->word_000086_some_monster_id = 0; + this->sNPC_ID = 0; + this->vPosition.z = 0; + this->vPosition.y = 0; + this->vPosition.x = 0; + this->vVelocity.z = 0; + this->vVelocity.y = 0; + this->vVelocity.x = 0; + this->uYawAngle = 0; + this->uPitchAngle = 0; + this->uAttributes = 0; + this->uSectorID = 0; + this->uCurrentActionTime = 0; + this->vInitialPosition.z = 0; + this->vInitialPosition.y = 0; + this->vInitialPosition.x = 0; + this->vGuardingPosition.z = 0; + this->vGuardingPosition.y = 0; + this->vGuardingPosition.x = 0; + this->uTetherDistance = 256; + this->uActorRadius = 32; + this->uActorHeight = 128; + this->uAIState = Standing; + this->uCurrentActionAnimation = ANIM_Standing; + this->uMovementSpeed = 200; + this->uCarriedItemID = 0; + this->uGroup = 0; + this->uAlly = 0; + this->uSummonerID = 0; + this->uLastCharacterIDToHit = 0; + this->dword_000334_unique_name = 0; + memset(this->pSpriteIDs, 0, sizeof(pSpriteIDs)); + memset(this->pActorBuffs, 0, 0x160u); +} + +//----- (0045959A) -------------------------------------------------------- +void Actor::PrepareSprites(char load_sounds_if_bit1_set) +{ + + MonsterDesc *v3; // esi@1 + MonsterInfo *v9; // [sp+84h] [bp-10h]@1 + + v3 = &pMonsterList->pMonsters[pMonsterInfo.uID - 1]; + v9 = &pMonsterStats->pInfos[pMonsterInfo.uID - 1 + 1]; + //v12 = pSpriteIDs; + //Source = (char *)v3->pSpriteNames; + //do + for (uint i = 0; i < 8; ++i) + { + //strcpy(pSpriteName, v3->pSpriteNames[i]); + pSpriteIDs[i] = pSpriteFrameTable->FastFindSprite(v3->pSpriteNames[i]); + pSpriteFrameTable->InitializeSprite(pSpriteIDs[i]); + } + uActorHeight = v3->uMonsterHeight; + uActorRadius = v3->uMonsterRadius; + uMovementSpeed = v9->uBaseSpeed; + if ( !(load_sounds_if_bit1_set & 1) ) + { + for ( int i = 0; i < 4; ++i ) + pSoundSampleIDs[i] = v3->pSoundSampleIDs[i]; + } +} + +//----- (00459667) -------------------------------------------------------- +void Actor::Remove() +{ + this->uAIState = Removed; +} + + +//----- (0043B1B0) -------------------------------------------------------- +void Actor::ActorDamageFromMonster(signed int attacker_id, unsigned int actor_id, Vec3_int_ *pVelocity, signed int a4) +{ + int v4; // ebx@1 + int dmgToRecv; // qax@8 + signed int v12; // ecx@20 + int finalDmg; // edi@30 + int pushDistance; // [sp+20h] [bp+Ch]@34 + + v4 = 0; + if ( PID_TYPE(attacker_id) == OBJECT_Item) + { + v4 = pSpriteObjects[PID_ID(attacker_id)].field_60_distance_related_prolly_lod; + attacker_id = pSpriteObjects[PID_ID(attacker_id)].spell_caster_pid; + } + if ( PID_TYPE(attacker_id) == OBJECT_Actor) + { + if ( !pActors[actor_id].IsNotAlive() ) + { + pActors[actor_id].uLastCharacterIDToHit = attacker_id; + if ( pActors[actor_id].uAIState == Fleeing ) + pActors[actor_id].uAttributes |= ACTOR_FLEEING; + if ( pActors[PID_ID(attacker_id)]._4273BB_DoesHitOtherActor(&pActors[actor_id], v4, 0) ) + { + dmgToRecv = pActors[PID_ID(attacker_id)]._43B3E0_CalcDamage(a4); + if ( pActors[PID_ID(attacker_id)].pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime > 0 ) + { + if ( pActors[PID_ID(attacker_id)].pActorBuffs[ACTOR_BUFF_SHRINK].uPower ) + dmgToRecv = dmgToRecv / pActors[PID_ID(attacker_id)].pActorBuffs[ACTOR_BUFF_SHRINK].uPower; + } + if ( pActors[actor_id].pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0 ) + dmgToRecv = 0; + if ( a4 == 0 ) + v12 = pActors[PID_ID(attacker_id)].pMonsterInfo.uAttack1Type; + else if ( a4 == 1 ) + { + v12 = pActors[PID_ID(attacker_id)].pMonsterInfo.uAttack2Type; + if ( SHIDWORD(pActors[actor_id].pActorBuffs[ACTOR_BUFF_SHIELD].uExpireTime) > 0 ) + dmgToRecv = dmgToRecv / 2; + } + else if ( a4 == 2 ) + v12 = pSpellStats->pInfos[pActors[actor_id].pMonsterInfo.uSpell1ID].uSchool; + else if ( a4 == 3 ) + v12 = pSpellStats->pInfos[pActors[actor_id].pMonsterInfo.uSpell2ID].uSchool; + else if ( a4 == 4 ) + v12 = pActors[PID_ID(attacker_id)].pMonsterInfo.field_3C_some_special_attack; + else + v12 = 4; + finalDmg = pActors[actor_id].CalcMagicalDamageToActor((DAMAGE_TYPE)v12, dmgToRecv); + pActors[actor_id].sCurrentHP -= finalDmg; + if ( finalDmg ) + { + if ( pActors[actor_id].sCurrentHP > 0 ) + Actor::AI_Stun(actor_id, attacker_id, 0); + else + Actor::Die(actor_id); + Actor::AggroSurroundingPeasants(actor_id, 0); + pushDistance = 20 * finalDmg / pActors[actor_id].pMonsterInfo.uHP; + if ( pushDistance > 10 ) + pushDistance = 10; + if ( !MonsterStats::BelongsToSupertype(pActors[actor_id].pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + pVelocity->x = (int32)fixpoint_mul(pushDistance, pVelocity->x); + pVelocity->y = (int32)fixpoint_mul(pushDistance, pVelocity->y); + pVelocity->z = (int32)fixpoint_mul(pushDistance, pVelocity->z); + pActors[actor_id].vVelocity.x = 50 * LOWORD(pVelocity->x); + pActors[actor_id].vVelocity.y = 50 * LOWORD(pVelocity->y); + pActors[actor_id].vVelocity.z = 50 * LOWORD(pVelocity->z); + } + Actor::AddBloodsplatOnDamageOverlay(actor_id, 1, finalDmg); + } + else + Actor::AI_Stun(actor_id, attacker_id, 0); + return; + } + } + } +} + +//----- (0044FD29) -------------------------------------------------------- +void Actor::SummonMinion( int summonerId ) +{ + unsigned __int8 extraSummonLevel; // al@1 + int summonMonsterBaseType; // esi@1 + int v5; // edx@2 + int v7; // edi@10 + Actor *actor; // esi@10 + MonsterInfo *v9; // ebx@10 + //MonsterDesc *v10; // edi@10 + int v13; // ebx@10 + int v15; // edi@10 + int v17; // ebx@10 + unsigned int v19; // qax@10 + int result; // eax@13 + unsigned int monsterId; // [sp+10h] [bp-18h]@8 + int v27; // [sp+18h] [bp-10h]@10 + int actorSector; // [sp+1Ch] [bp-Ch]@8 + + + actorSector = 0; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + actorSector = pIndoor->GetSector(this->vPosition.x, this->vPosition.y, this->vPosition.z); + + v19 = this->uAlly; + if ( !this->uAlly ) + { + monsterId = this->pMonsterInfo.uID - 1; + v19 = (uint)(monsterId * 0.33333334); + } + v27 = uCurrentlyLoadedLevelType == LEVEL_Outdoor ? 128 : 64; + v13 = rand() % 2048; + v15 = fixpoint_mul(stru_5C6E00->Cos(v13), v27) + this->vPosition.x; + v17 = fixpoint_mul(stru_5C6E00->Sin(v13), v27) + this->vPosition.y; + + if (uCurrentlyLoadedLevelType == LEVEL_Indoor) + { + result = pIndoor->GetSector(v15, v17, this->vPosition.z); + if (result != actorSector) + return; + result = BLV_GetFloorLevel(v15, v17, v27, result, &monsterId); + if (result != -30000) + return; + if (abs(result - v27) > 1024) + return; + } + + extraSummonLevel = this->pMonsterInfo.uSpecialAbilityDamageDiceRolls; + summonMonsterBaseType = this->pMonsterInfo.field_3C_some_special_attack; + if ( extraSummonLevel ) + { + if ( extraSummonLevel >= 1 && extraSummonLevel <= 3 ) + summonMonsterBaseType = summonMonsterBaseType + extraSummonLevel - 1; + } + else + { + v5 = rand() % 100; + if ( v5 >= 90 ) + summonMonsterBaseType += 2; + else if ( v5 >= 60 ) + summonMonsterBaseType += 1; + } + v7 = summonMonsterBaseType - 1; + actor = &pActors[uNumActors]; + v9 = &pMonsterStats->pInfos[v7 + 1]; + pActors[uNumActors].Reset(); + strcpy(actor->pActorName, v9->pName); + actor->sCurrentHP = LOWORD(v9->uHP); + memcpy(&actor->pMonsterInfo, v9, sizeof(actor->pMonsterInfo)); + actor->word_000086_some_monster_id = summonMonsterBaseType; + actor->uActorRadius = pMonsterList->pMonsters[v7].uMonsterRadius; + actor->uActorHeight = pMonsterList->pMonsters[v7].uMonsterHeight; + actor->pMonsterInfo.uTreasureDiceRolls = 0; + actor->pMonsterInfo.uTreasureType = 0; + actor->pMonsterInfo.uExp = 0; + actor->uMovementSpeed = pMonsterList->pMonsters[v7].uMovementSpeed; + + actor->vInitialPosition.x = v15; + actor->vInitialPosition.y = v17; + actor->vInitialPosition.z = this->vPosition.z; + actor->vPosition.x = v15; + actor->vPosition.y = v17; + actor->vPosition.z = this->vPosition.z; + + actor->uTetherDistance = 256; + actor->uSectorID = actorSector; + actor->PrepareSprites(0); + actor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + actor->uAlly = v19; + actor->uCurrentActionTime = 0; + actor->uGroup = this->uGroup; + actor->uAIState = Summoned; + actor->uCurrentActionLength = 256; + actor->UpdateAnimation(); + + ++uNumActors; + ++this->pMonsterInfo.uSpecialAbilityDamageDiceBonus; + if ( ActorEnemy()) + actor->uAttributes |= ACTOR_AGGRESSOR; + actor->uSummonerID = PID(OBJECT_Actor,summonerId); + +} +// 46DF1A: using guessed type int __fastcall 46DF1A_collide_against_actor(int, int); +//----- (0046DF1A) -------------------------------------------------------- +bool Actor::_46DF1A_collide_against_actor( int a1, int a2 ) +{ + Actor *v2; // edi@1 + unsigned __int16 v3; // ax@1 + int v4; // esi@6 + int v8; // ecx@14 + int v9; // eax@14 + int v10; // ebx@14 + int v11; // esi@14 + int v12; // ebx@15 + int v13; // ebx@17 + + v2 = &pActors[a1]; + v3 = v2->uAIState; + if ( v3 == Removed || v3 == Dying || v3 == Disabled || v3 == Dead || v3 == Summoned ) + return 0; + v4 = v2->uActorRadius; + if ( a2 ) + v4 = a2; + + if (stru_721530.sMaxX > v2->vPosition.x + v4 || + stru_721530.sMinX < v2->vPosition.x - v4 || + stru_721530.sMaxY > v2->vPosition.y + v4 || + stru_721530.sMinY < v2->vPosition.y - v4 || + stru_721530.sMaxZ > v2->vPosition.z + v2->uActorHeight || + stru_721530.sMinZ < v2->vPosition.z) + { + return false; + } + v8 = v2->vPosition.x - stru_721530.normal.x; + v9 = v2->vPosition.y - stru_721530.normal.y; + v10 = stru_721530.prolly_normal_d + v4; + v11 = (v8 * stru_721530.direction.y - v9 * stru_721530.direction.x) >> 16; + v12 = (v8 * stru_721530.direction.x + v9 * stru_721530.direction.y) >> 16; + if ( abs(v11) > v10 || v12 <= 0) + return false; + if (fixpoint_mul(stru_721530.direction.z, v12) + stru_721530.normal.z < v2->vPosition.z) + return false; + + v13 = v12 - integer_sqrt(v10 * v10 - v11 * v11); + if ( v13 < 0 ) + v13 = 0; + if ( v13 < stru_721530.field_7C ) + { + stru_721530.field_7C = v13; + stru_721530.uFaceID = PID(OBJECT_Actor,a1); + } + return true; +} +//----- (00401A91) -------------------------------------------------------- +void Actor::UpdateActorAI() +{ + signed int v4; // edi@10 + signed int sDmg; // eax@14 + Player *pPlayer; // ecx@21 + Actor *pActor; // esi@34 + //unsigned __int16 v22; // ax@86 + unsigned int v27; // ecx@123 + unsigned int v28; // eax@123 + int v33; // eax@144 + int v34; // eax@147 + char v35; // al@150 + unsigned int v36; // edi@152 + signed int v37; // eax@154 + double v42; // st7@176 + double v43; // st6@176 + int v45; // eax@192 + unsigned __int8 v46; // cl@197 + signed int v47; // st7@206 + uint v58; // st7@246 + unsigned int v65; // [sp-10h] [bp-C0h]@144 + int v70; // [sp-10h] [bp-C0h]@213 + AIDirection v72; // [sp+0h] [bp-B0h]@246 + AIDirection a3; // [sp+1Ch] [bp-94h]@129 + int target_pid_type; // [sp+70h] [bp-40h]@83 + signed int a1; // [sp+74h] [bp-3Ch]@129 + int v78; // [sp+78h] [bp-38h]@79 + AIDirection* pDir; // [sp+7Ch] [bp-34h]@129 + float radiusMultiplier; // [sp+98h] [bp-18h]@33 + int v81; // [sp+9Ch] [bp-14h]@100 + signed int target_pid; // [sp+ACh] [bp-4h]@83 + AIState uAIState; + uint v38; + + //Build AI array + if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor) + Actor::MakeActorAIList_ODM(); + else + Actor::MakeActorAIList_BLV(); + + //Armageddon damage mechanic + if ( uCurrentlyLoadedLevelType != LEVEL_Indoor && pParty->armageddon_timer > 0 ) + { + if ( pParty->armageddon_timer > 417 ) + pParty->armageddon_timer = 0; + else + { + pParty->sRotationY = (stru_5C6E00->uIntegerDoublePi - 1) & (pParty->sRotationY + rand() % 16 - 8); + pParty->sRotationX = pParty->sRotationX + rand() % 16 - 8; + if ( pParty->sRotationX > 128) + pParty->sRotationX = 128; + else if ( pParty->sRotationX < -128 ) + pParty->sRotationX = -128; + + pParty->uFlags |= 2u; + pParty->armageddon_timer -= pMiscTimer->uTimeElapsed; + v4 = pParty->armageddonDamage + 50; + if ( pParty->armageddon_timer <= 0 ) + { + pParty->armageddon_timer = 0; + for(size_t i = 0; i < uNumActors; i++) + { + pActor=&pActors[i]; + if ( pActor->CanAct() ) + { + sDmg = pActor->CalcMagicalDamageToActor((DAMAGE_TYPE)5, v4); + pActor->sCurrentHP -= sDmg; + if ( sDmg ) + { + if ( pActor->sCurrentHP >= 0 ) + Actor::AI_Stun(i, 4, 0); + else + { + Actor::Die(i); + if ( pActor->pMonsterInfo.uExp ) + pParty->GivePartyExp(pMonsterStats->pInfos[pActor->pMonsterInfo.uID].uExp); + } + } + } + } + for(int i = 1; i <= 4; i++) + { + pPlayer = pPlayers[i]; + if ( !pPlayer->pConditions[Condition_Dead] && !pPlayer->pConditions[Condition_Pertified] && !pPlayer->pConditions[Condition_Eradicated] ) + pPlayer->ReceiveDamage(v4, DMGT_MAGICAL); + } + } + if (pTurnEngine->pending_actions) + --pTurnEngine->pending_actions; + } + } + + //Turn-based mode: return + if (pParty->bTurnBasedModeOn) + { + pTurnEngine->AITurnBasedAction(); + return; + } + + for (uint i = 0; i < uNumActors; ++i) + { + pActor = &pActors[i]; + ai_near_actors_targets_pid[i] = OBJECT_Player; + + //Skip actor if: Dead / Removed / Disabled / uAttributes & 0x0400 + if (pActor->uAIState == Dead || pActor->uAIState == Removed || pActor->uAIState == Disabled || pActor->uAttributes & ACTOR_ALIVE) + continue; + + //Kill actor if HP == 0 + if (!pActor->sCurrentHP && pActor->uAIState != Dying) + Actor::Die(i); + + //Kill buffs if expired + for (uint j = 0; j < 22; ++j) + { + if (j != 10) + pActor->pActorBuffs[j].IsBuffExpiredToTime(pParty->uTimePlayed); + } + + //If shrink expired: reset height + if (pActor->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime < 0) + pActor->uActorHeight = pMonsterList->pMonsters[pActor->pMonsterInfo.uID - 1].uMonsterHeight; + + //If Charm still active: make actor friendly + if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime > 0) + pActor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + //Else: reset hostilty + else if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime < 0) + pActor->pMonsterInfo.uHostilityType = pMonsterStats->pInfos[pActor->pMonsterInfo.uID].uHostilityType; + + //If actor Paralyzed or Stoned: skip + if (pActor->pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime > 0 || pActor->pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0) + continue; + + //Calculate RecoveryTime + pActor->pMonsterInfo.uRecoveryTime = max(pActor->pMonsterInfo.uRecoveryTime - pMiscTimer->uTimeElapsed, 0); + + pActor->uCurrentActionTime += pMiscTimer->uTimeElapsed; + if (pActor->uCurrentActionTime < pActor->uCurrentActionLength) + continue; + + if (pActor->uAIState == Dying) + pActor->uAIState = Dead; + else + { + if (pActor->uAIState != Summoned) + { + Actor::AI_StandOrBored(i, OBJECT_Player, 256, nullptr); + continue; + } + pActor->uAIState = Standing; + } + + pActor->uCurrentActionTime = 0; + pActor->uCurrentActionLength = 0; + pActor->UpdateAnimation(); + } + + for(v78 = 0; v78 < ai_arrays_size; ++v78) + { + uint actor_id = ai_near_actors_ids[v78]; + assert(actor_id < uNumActors); + + pActor = &pActors[actor_id]; + + v47 = (signed int)(pActor->pMonsterInfo.uRecoveryTime * 2.133333333333333); + + Actor::_SelectTarget(actor_id, &ai_near_actors_targets_pid[actor_id], true); + + if (pActor->pMonsterInfo.uHostilityType && !ai_near_actors_targets_pid[actor_id]) + pActor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + + target_pid = ai_near_actors_targets_pid[actor_id]; + target_pid_type = PID_TYPE(target_pid); + + if ( target_pid_type == OBJECT_Actor) + radiusMultiplier = 0.5; + else + radiusMultiplier = 1.0; + + //v22 = pActor->uAIState; + if ( pActor->uAIState == Dying || pActor->uAIState == Dead || pActor->uAIState == Removed + || pActor->uAIState == Disabled || pActor->uAIState == Summoned) + continue; + + if ( !pActor->sCurrentHP ) + Actor::Die(actor_id); + + for( int i = 0;i < 22; i++ ) + { + if ( i != 10 ) + pActor->pActorBuffs[i].IsBuffExpiredToTime(pParty->uTimePlayed); + } + + if ( pActor->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime < 0 ) + pActor->uActorHeight = pMonsterList->pMonsters[pActor->pMonsterInfo.uID - 1].uMonsterHeight; + if ( pActor->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime > 0 ) + pActor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + else if ( pActor->pActorBuffs[ACTOR_BUFF_CHARM].uExpireTime < 0 ) + pActor->pMonsterInfo.uHostilityType = pMonsterStats->pInfos[pActor->pMonsterInfo.uID].uHostilityType; + + //If actor is summoned and buff expired: continue and set state to Removed + if ( pActor->pActorBuffs[ACTOR_BUFF_SUMMONED].uExpireTime < 0 ) + { + pActor->uAIState = Removed; + continue; + } + + if ( (signed __int64)pActor->pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0 || (signed __int64)pActor->pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime > 0) + { + continue; + } + + v27 = pMiscTimer->uTimeElapsed; + v28 = pActor->pMonsterInfo.uRecoveryTime; + pActor->uCurrentActionTime += pMiscTimer->uTimeElapsed; + + if ( (signed int)v28 > 0 ) + pActor->pMonsterInfo.uRecoveryTime = v28 - v27; + if ( pActor->pMonsterInfo.uRecoveryTime < 0 ) + pActor->pMonsterInfo.uRecoveryTime = 0; + if ( !pActor->ActorNearby() ) + pActor->uAttributes |= ACTOR_NEARBY; + + a1 = PID(OBJECT_Actor,actor_id); + Actor::GetDirectionInfo(PID(OBJECT_Actor,actor_id), target_pid, &a3, 0); + pDir = &a3; + uAIState = pActor->uAIState; + + if ( pActor->pMonsterInfo.uHostilityType == MonsterInfo::Hostility_Friendly + || (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 + || radiusMultiplier * 307.2 < pDir->uDistance + || uAIState != Pursuing && uAIState != Standing && uAIState != Tethered && uAIState != Fidgeting + && !pActor->pMonsterInfo.uMissleAttack1Type || uAIState != Stunned ) + { + if ( (signed int)pActor->uCurrentActionTime < pActor->uCurrentActionLength ) + continue; + else if ( pActor->uAIState == AttackingMelee ) + { + v35 = pActor->special_ability_use_check(actor_id); + AttackerInfo.Add(a1, 5120, pActor->vPosition.x, pActor->vPosition.y, pActor->vPosition.z + ((signed int)pActor->uActorHeight >> 1), v35, 1 ); + } + else if ( pActor->uAIState == AttackingRanged1 ) + { + v34 = pActor->pMonsterInfo.uMissleAttack1Type; + Actor::AI_RangedAttack(actor_id, pDir, v34, 0); + } + else if ( pActor->uAIState == AttackingRanged2 ) + { + v34 = pActor->pMonsterInfo.uMissleAttack2Type; + Actor::AI_RangedAttack(actor_id, pDir, v34, 1); + } + else if ( pActor->uAIState == AttackingRanged3 ) + { + v65 = pActor->pMonsterInfo.uSpellSkillAndMastery1; + v33 = pActor->pMonsterInfo.uSpell1ID; + Actor::AI_SpellAttack(actor_id, pDir, v33, 2, v65); + } + else if ( pActor->uAIState == AttackingRanged4 ) + { + v65 = pActor->pMonsterInfo.uSpellSkillAndMastery2; + v33 = pActor->pMonsterInfo.uSpell2ID; + Actor::AI_SpellAttack(actor_id, pDir, v33, 3, v65); + } + } + + v36 = pDir->uDistance; + + if ( pActor->pMonsterInfo.uHostilityType == MonsterInfo::Hostility_Friendly) + { + if ( target_pid_type == OBJECT_Actor ) + { + v36 = pDir->uDistance; + v37 =pFactionTable->relations[(pActor->pMonsterInfo.uID-1) / 3 + 1][(pActors[PID_ID(target_pid)].pMonsterInfo.uID - 1) / 3 + 1]; + } + else + v37 = 4; + v38 = 0; + if ( v37 == 2 ) + v38 = 1024; + else if ( v37 == 3 ) + v38 = 2560; + else if ( v37 == 4 ) + v38 = 5120; + if ( v37 >= 1 && v37 <= 4 && v36 < v38 || v37 == 1 ) + pActor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Long; + } + + //If actor afraid: flee or if out of range random move + if (pActor->pActorBuffs[ACTOR_BUFF_AFRAID].uExpireTime > 0) + { + if ( (signed int)v36 >= 10240 ) + Actor::AI_RandomMove(actor_id, target_pid, 1024, 0); + else + Actor::AI_Flee(actor_id, target_pid, 0, pDir); + continue; + } + + if ( pActor->pMonsterInfo.uHostilityType == MonsterInfo::Hostility_Long && target_pid ) + { + if ( pActor->pMonsterInfo.uAIType == 1 ) + { + if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, (uint)(pActor->pMonsterInfo.uRecoveryTime * 2.133333333333333), pDir); + else + { + Actor::AI_Flee(actor_id, target_pid, 0, pDir); + continue; + } + + } + if ( !(pActor->uAttributes & ACTOR_FLEEING) ) + { + if ( pActor->pMonsterInfo.uAIType == 2 || pActor->pMonsterInfo.uAIType == 3) + { + if ( pActor->pMonsterInfo.uAIType == 2 ) + v43 = (double)(signed int)pActor->pMonsterInfo.uHP * 0.2; + if ( pActor->pMonsterInfo.uAIType == 3 ) + v43 = (double)(signed int)pActor->pMonsterInfo.uHP * 0.1; + v42 = (double)pActor->sCurrentHP; + if ( v43 > v42 && (signed int)v36 < 10240 ) + { + Actor::AI_Flee(actor_id, target_pid, 0, pDir); + continue; + } + } + } + + v81 = v36 - pActor->uActorRadius; + if ( target_pid_type == OBJECT_Actor ) + v81 -= pActors[PID_ID(target_pid)].uActorRadius; + if ( v81 < 0 ) + v81 = 0; + rand(); + pActor->uAttributes &= ~ACTOR_UNKNOW5;//~0x40000 + if ( v81 < 5120 ) + { + v45 = pActor->special_ability_use_check(actor_id); + if ( v45 == 0 ) + { + if ( pActor->pMonsterInfo.uMissleAttack1Type ) + { + if ( (signed int)pActor->pMonsterInfo.uRecoveryTime <= 0 ) + Actor::AI_MissileAttack1(actor_id, target_pid, pDir); + else if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else + { + if ( radiusMultiplier * 307.2 > (double)v81 ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else + Actor::AI_Pursue1(actor_id, target_pid, actor_id, v47, pDir); + } + } + else + { + if ( (double)v81 >= radiusMultiplier * 307.2 ) + { + if (pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else if ( v81 >= 1024 )//monsters + Actor::AI_Pursue3(actor_id, target_pid, 0, pDir); + else + { + v70 = (signed int)(radiusMultiplier * 307.2); + //monsters + //guard after player runs away + // follow player + Actor::AI_Pursue2(actor_id, target_pid, 0, pDir, v70); + } + } + else if ( (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 ) + { + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + } + else + { + //monsters + Actor::AI_MeleeAttack(actor_id, target_pid, pDir); + } + } + continue; + } + else if ( v45 == 2 || v45 == 3 ) + { + if ( v45 == 2 ) + v46 = pActor->pMonsterInfo.uSpell1ID; + else + v46 = pActor->pMonsterInfo.uSpell2ID; + if ( v46 ) + { + if ( (signed int)pActor->pMonsterInfo.uRecoveryTime <= 0 ) + { + if ( v45 == 2 ) + Actor::AI_SpellAttack1(actor_id, target_pid, pDir); + else + Actor::AI_SpellAttack2(actor_id, target_pid, pDir); + } + else if ( radiusMultiplier * 307.2 > (double)v81 || pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else + Actor::AI_Pursue1(actor_id, target_pid, actor_id, v47, pDir); + } + else + { + if ( (double)v81 >= radiusMultiplier * 307.2 ) + { + if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else if ( v81 >= 1024 ) + Actor::AI_Pursue3(actor_id, target_pid, 256, pDir); + else + { + v70 = (signed int)(radiusMultiplier * 307.2); + Actor::AI_Pursue2(actor_id, target_pid, 0, pDir, v70); + } + } + else if ( (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 ) + { + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + } + else + { + Actor::AI_MeleeAttack(actor_id, target_pid, pDir); + } + } + continue; + } + } + } + + if ( pActor->pMonsterInfo.uHostilityType != MonsterInfo::Hostility_Long || !target_pid || v81 >= 5120 || v45 != 1 ) + { + if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_SHORT ) + Actor::AI_RandomMove(actor_id, 4, 1024, 0); + else if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_MEDIUM ) + Actor::AI_RandomMove(actor_id, 4, 2560, 0); + else if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_LONG ) + Actor::AI_RandomMove(actor_id, 4, 5120, 0); + else if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_FREE ) + Actor::AI_RandomMove(actor_id, 4, 10240, 0); + else if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + { + Actor::GetDirectionInfo(a1, 4, &v72, 0); + v58 = (uint)(pActor->pMonsterInfo.uRecoveryTime * 2.133333333333333); + Actor::AI_Stand(actor_id, 4, v58, &v72); + } + } + else if ( !pActor->pMonsterInfo.uMissleAttack2Type ) + { + if ( (double)v81 >= radiusMultiplier * 307.2 ) + { + if ( pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else if ( v81 >= 1024 ) + Actor::AI_Pursue3(actor_id, target_pid, 256, pDir); + else + { + v70 = (int)(radiusMultiplier * 307.2); + Actor::AI_Pursue2(actor_id, target_pid, 0, pDir, v70); + } + } + else if ( (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else + Actor::AI_MeleeAttack(actor_id, target_pid, pDir); + } + else if ( (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 ) + { + if ( radiusMultiplier * 307.2 > (double)v81 || pActor->pMonsterInfo.uMovementType == MONSTER_MOVEMENT_TYPE_STAIONARY ) + Actor::AI_Stand(actor_id, target_pid, v47, pDir); + else + Actor::AI_Pursue1(actor_id, target_pid, actor_id, v47, pDir); + } + else + Actor::AI_MissileAttack2(actor_id, target_pid, pDir); + } +} +//----- (0044665D) -------------------------------------------------------- +// uType: 0 -> any monster +// 1 -> uParam is GroupID +// 2 -> uParam is MonsterID +// 3 -> uParam is ActorID +// uNumAlive: 0 -> all must be alive +int __fastcall IsActorAlive(unsigned int uType, unsigned int uParam, unsigned int uNumAlive) +{ + unsigned int uAliveActors; // eax@6 + unsigned int uTotalActors; // [sp+0h] [bp-4h]@1 + + uTotalActors = 0; + if ( uType ) + { + if ( uType == 1 ) + uAliveActors = Actor::SearchActorByGroup(&uTotalActors, uParam); + else + { + if ( uType == 2 ) + uAliveActors = Actor::SearchActorByMonsterID(&uTotalActors, uParam); + else + { + if ( uType != 3 ) + return 0; + uAliveActors = Actor::SearchActorByID(&uTotalActors, uParam); + } + } + } + else + uAliveActors = Actor::SearchAliveActors(&uTotalActors); + + if (uNumAlive) + return uAliveActors >= uNumAlive; + else + return uTotalActors == uAliveActors; +} +//----- (00408B54) -------------------------------------------------------- +unsigned int Actor::SearchActorByID(unsigned int *pTotalActors, unsigned int a2) +{ + //int v4; // eax@1 + unsigned int result; // ebx@1 + + //v4 = GetAlertStatus(); + *pTotalActors = 0; + result = 0; + if ( (pActors[a2].uAttributes & ACTOR_UNKNOW7) == GetAlertStatus() ) + { + *pTotalActors = 1; + if ( pActors[a2].IsNotAlive() == 1 ) + result = 1; + } + return result; +} +//----- (00408AE7) -------------------------------------------------------- +unsigned int Actor::SearchActorByGroup(unsigned int *pTotalActors, unsigned int uGroup) +{ + unsigned int result; // [sp+10h] [bp-4h]@1 + + int v8 = GetAlertStatus(); + *pTotalActors = 0; + result = 0; + for ( uint i = 0; i < uNumActors; i++) + { + if ( (pActors[i].uAttributes & ACTOR_UNKNOW7) == v8 && pActors[i].uGroup == uGroup) + { + ++*pTotalActors; + if ( pActors[i].IsNotAlive() == 1 ) + ++result; + } + } + return result; +} +//----- (00408A7E) -------------------------------------------------------- +unsigned int Actor::SearchActorByMonsterID(unsigned int *pTotalActors, int uMonsterID) +{ + int v8; // [sp+Ch] [bp-8h]@1 + unsigned int result; // [sp+10h] [bp-4h]@1 + + v8 = GetAlertStatus(); + *pTotalActors = 0; + result = 0; + for ( uint i = 0; i < uNumActors; i++) + { + if ( (pActors[i].uAttributes & ACTOR_UNKNOW7) == v8 && pActors[i].pMonsterInfo.field_33 == uMonsterID) + { + ++*pTotalActors; + if ( pActors[i].IsNotAlive() == 1 ) + ++result; + } + } + return result; +} +//----- (00408A27) -------------------------------------------------------- +unsigned int Actor::SearchAliveActors(unsigned int *pTotalActors) +{ + int v2; // eax@1 + unsigned int result; // ebp@1 + + v2 = GetAlertStatus(); + result = 0; + *pTotalActors = 0; + for ( uint i = 0; i < uNumActors; i++) + { + if ( (pActors[i].uAttributes & ACTOR_UNKNOW7) == v2 ) + { + ++*pTotalActors; + if ( pActors[i].IsNotAlive() == 1 ) + ++result; + } + } + return result; +} +//----- (00408768) -------------------------------------------------------- +void Actor::InitializeActors() +{ + bool evil; // [sp+Ch] [bp-10h]@1 + bool bPit; // [sp+10h] [bp-Ch]@1 + bool good; // [sp+14h] [bp-8h]@1 + bool bCelestia; // [sp+18h] [bp-4h]@1 + + bCelestia = false; + bPit = false; + good = false; + evil = false; + if ( !_stricmp(pCurrentMapName, "d25.blv") )//the Celestia + bCelestia = true; + if ( !_stricmp(pCurrentMapName, "d26.blv") )//the Pit + bPit = true; + if (pParty->IsPartyGood()) + good = true; + if (pParty->IsPartyEvil()) + evil = true; + + Log::Warning(L"%S %S %u", __FILE__, __FUNCTION__, __LINE__); // ai_near_actors_targets_pid[i] for AI_Stand seems always 0; original code behaviour is identical + for (uint i = 0; i < uNumActors; ++i) + { + Actor* actor = &pActors[i]; + + if (actor->CanAct() || actor->uAIState == Disabled) + { + actor->vPosition.x = actor->vInitialPosition.x; + actor->vPosition.y = actor->vInitialPosition.y; + actor->vPosition.z = actor->vInitialPosition.z; + actor->sCurrentHP = actor->pMonsterInfo.uHP; + if (actor->uAIState != Disabled) + { + Actor::AI_Stand(i, ai_near_actors_targets_pid[i], actor->pMonsterInfo.uRecoveryTime, 0); + } + } + + actor->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + + if (!bCelestia || good) + if (!bPit || evil) + if (actor->IsPeasant()) + actor->ResetAggressor();//~0x80000 + + actor->ResetHasItem();//~0x800000 + if (actor->uAttributes & ACTOR_UNKNOW9) + Actor::_4031C1_update_job_never_gets_called(i, pParty->uCurrentHour, 1); + } +} +//----- (00439474) -------------------------------------------------------- +void Actor::DamageMonsterFromParty(signed int a1, unsigned int uActorID_Monster, Vec3_int_ *pVelocity) +{ + SpriteObject *projectileSprite; // ebx@1 + Actor *pMonster; // esi@7 + unsigned __int16 v16; // cx@25 + int v33; // eax@100 + int v40; // ebx@107 + int extraRecoveryTime; // qax@125 + unsigned __int16 v43; // ax@132 + unsigned __int16 v45; // ax@132 + unsigned __int64 v46; // [sp+Ch] [bp-60h]@6 + char *pPlayerName; // [sp+18h] [bp-54h]@12 + char *pMonsterName; // [sp+1Ch] [bp-50h]@6 + signed int a4; // [sp+44h] [bp-28h]@1 + bool IsAdditionalDamagePossible; // [sp+50h] [bp-1Ch]@1 + int v61; // [sp+58h] [bp-14h]@1 + bool isLifeStealing; // [sp+5Ch] [bp-10h]@1 + int uDamageAmount; // [sp+60h] [bp-Ch]@1 + DAMAGE_TYPE attackElement; // [sp+64h] [bp-8h]@27 + + projectileSprite = 0; + uDamageAmount = 0; + a4 = 0; + v61 = 0; + IsAdditionalDamagePossible = false; + isLifeStealing = 0; + if ( PID_TYPE(a1) == OBJECT_Item) + { + projectileSprite = &pSpriteObjects[PID_ID(a1)]; + v61 = projectileSprite->field_60_distance_related_prolly_lod; + a1 = projectileSprite->spell_caster_pid; + } + if (PID_TYPE(a1) != OBJECT_Player) + return; + + assert(PID_ID(abs(a1)) < 4); + Player* player = &pParty->pPlayers[PID_ID(a1)]; + pMonster = &pActors[uActorID_Monster]; + if (pMonster->IsNotAlive()) + return; + + pMonster->uAttributes |= 0xC000; + if ( pMonster->uAIState == Fleeing ) + pMonster->uAttributes |= ACTOR_FLEEING; + bool hit_will_stun = false, + hit_will_paralyze = false; + if ( !projectileSprite ) + { + int main_hand_idx = player->pEquipment.uMainHand; + IsAdditionalDamagePossible = true; + if ( player->HasItemEquipped(EQUIP_TWO_HANDED) ) + { + uint main_hand_skill = player->GetMainHandItem()->GetPlayerSkillType(); + uint main_hand_mastery = SkillToMastery(player->pActiveSkills[main_hand_skill]); + switch (main_hand_skill) + { + case PLAYER_SKILL_STAFF: + if (main_hand_mastery >= 3) + { + if (rand() % 100 < (player->GetActualSkillLevel(PLAYER_SKILL_STAFF) & 0x3F)) // stun chance when mastery >= 3 + hit_will_stun = true; + } + break; + + case PLAYER_SKILL_MACE: + if (main_hand_mastery >= 3) + { + if (rand() % 100 < (player->GetActualSkillLevel(PLAYER_SKILL_MACE) & 0x3F)) + hit_will_stun = true; + } + if (main_hand_mastery >= 4) + { + if (rand() % 100 < (player->GetActualSkillLevel(PLAYER_SKILL_MACE) & 0x3F)) + hit_will_paralyze = true; + } + break; + } + } + attackElement = DMGT_PHISYCAL; + uDamageAmount = player->CalculateMeleeDamageTo(false, false, pMonster->pMonsterInfo.uID); + if ( !player->PlayerHitOrMiss(pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + } + else + { + v61 = projectileSprite->field_60_distance_related_prolly_lod; + if ( projectileSprite->spell_id != SPELL_DARK_SOULDRINKER ) + { + int d1 = abs(pParty->vPosition.x - projectileSprite->vPosition.x); + int d2 = abs(pParty->vPosition.y - projectileSprite->vPosition.y); + int d3 = abs(pParty->vPosition.z - projectileSprite->vPosition.z); + v61 = int_get_vector_length(d1, d2, d3); + + if ( v61 >= 5120 && !(pMonster->uAttributes & ACTOR_ALIVE) )//0x400 + return; + else if ( v61 >= 2560 ) + v61 = 2; + else + v61 = 1; + } + + switch (projectileSprite->spell_id) + { + case SPELL_LASER_PROJECTILE: + v16 = player->pActiveSkills[PLAYER_SKILL_BLASTER]; + v61 = 1; + if ( SkillToMastery(v16) >= 3 ) + a4 = player->pActiveSkills[PLAYER_SKILL_BLASTER] & 0x3F; + attackElement = DMGT_PHISYCAL; + uDamageAmount = player->CalculateMeleeDamageTo(true, true, 0); + if ( !player->PlayerHitOrMiss(pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + break; + case SPELL_101: + attackElement = DMGT_FIRE; + uDamageAmount = player->CalculateRangedDamageTo(0); + if ( pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].uExpireTime > 0 ) + uDamageAmount >>= 1; + IsAdditionalDamagePossible = true; + if ( !player->PlayerHitOrMiss(pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + break; + case SPELL_EARTH_BLADES: + a4 = 5 * projectileSprite->spell_level; + attackElement = (DAMAGE_TYPE)player->GetSpellSchool(SPELL_EARTH_BLADES); + uDamageAmount = _43AFE3_calc_spell_damage(39, projectileSprite->spell_level, projectileSprite->spell_skill, pMonster->sCurrentHP); + if ( pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].uExpireTime > 0 ) + uDamageAmount >>= 1; + IsAdditionalDamagePossible = false; + if ( !player->PlayerHitOrMiss( pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + break; + case SPELL_EARTH_STUN: + uDamageAmount = 0; + attackElement = DMGT_PHISYCAL; + hit_will_stun = 1; + if ( !player->PlayerHitOrMiss( pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + break; + case SPELL_BOW_ARROW: + attackElement = DMGT_PHISYCAL; + uDamageAmount = player->CalculateRangedDamageTo(pMonster->word_000086_some_monster_id); + if ( pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].uExpireTime > 0 ) + uDamageAmount /= 2; + IsAdditionalDamagePossible = true; + if ( projectileSprite->stru_24.uItemID != 0 && projectileSprite->stru_24.uSpecEnchantmentType == 3 ) //of carnage + { + attackElement = DMGT_FIRE; + } + else if ( !player->PlayerHitOrMiss( pMonster, v61, a4) ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + break; + + default: + attackElement = (DAMAGE_TYPE)player->GetSpellSchool(projectileSprite->spell_id); + IsAdditionalDamagePossible = false; + uDamageAmount = _43AFE3_calc_spell_damage(projectileSprite->spell_id, projectileSprite->spell_level, projectileSprite->spell_skill, pMonster->sCurrentHP); + break; + } + } + + if (player->IsWeak()) + uDamageAmount /= 2; + if ( pMonster->pActorBuffs[ACTOR_BUFF_STONED].uExpireTime > 0 ) + uDamageAmount = 0; + v61 = pMonster->CalcMagicalDamageToActor(attackElement, uDamageAmount); + if ( !projectileSprite && player->IsUnarmed() && player->pPlayerBuffs[PLAYER_BUFF_HAMMERHANDS].uExpireTime > 0 ) + { + v61 += pMonster->CalcMagicalDamageToActor((DAMAGE_TYPE)8, player->pPlayerBuffs[PLAYER_BUFF_HAMMERHANDS].uPower); + } + uDamageAmount = v61; + if ( IsAdditionalDamagePossible ) + { + if ( projectileSprite ) + { + a4 = projectileSprite->stru_24._439DF3_get_additional_damage((int*)&attackElement, &isLifeStealing); + if ( isLifeStealing && pMonster->sCurrentHP > 0 ) + { + player->sHealth += v61 / 5; + if ( player->sHealth > player->GetMaxHealth() ) + player->sHealth = player->GetMaxHealth(); + } + uDamageAmount += pMonster->CalcMagicalDamageToActor(attackElement, a4); + } + else + { + for (int i = 0; i < 2; i++) + { + if ( player->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + ItemGen* item; + if (i == 0) + item = player->GetOffHandItem(); + else + item = player->GetMainHandItem(); + a4 = item->_439DF3_get_additional_damage((int*)&attackElement, &isLifeStealing); + if ( isLifeStealing && pMonster->sCurrentHP > 0 ) + { + player->sHealth += v61 / 5; + if ( player->sHealth > player->GetMaxHealth() ) + player->sHealth = player->GetMaxHealth(); + } + uDamageAmount += pMonster->CalcMagicalDamageToActor(attackElement, a4); + } + } + } + } + pMonster->sCurrentHP -= uDamageAmount; + if ( uDamageAmount == 0 && !hit_will_stun ) + { + player->PlaySound(SPEECH_52, 0); + return; + } + if ( pMonster->sCurrentHP > 0 ) + { + Actor::AI_Stun(uActorID_Monster, a1, 0); + Actor::AggroSurroundingPeasants(uActorID_Monster, 1); + if ( bShowDamage ) + { + if ( projectileSprite ) + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[189], player->pName, pMonster->pActorName, uDamageAmount);// "%s shoots %s for %lu points" + else + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[164], player->pName, pMonster->pActorName, uDamageAmount);// "%s hits %s for %lu damage" + ShowStatusBarString(pTmpBuf.data(), 2u); + } + } + else + { + if ( pMonsterStats->pInfos[pMonster->pMonsterInfo.uID].bQuestMonster & 1 ) + { + if ( /*pRenderer->pRenderD3D &&*/ pGame->uFlags2 & GAME_FLAGS_2_DRAW_BLOODSPLATS ) + { + v33 = byte_4D864C && pGame->uFlags & 0x80000 ? 10 * pMonster->uActorRadius : pMonster->uActorRadius; + pDecalBuilder->AddBloodsplat((float)pMonster->vPosition.x, (float)pMonster->vPosition.y, (float)pMonster->vPosition.z, 1.0, 0.0, 0.0, (float)v33, 0, 0); + } + } + Actor::Die(uActorID_Monster); + Actor::ApplyFineForKillingPeasant(uActorID_Monster); + Actor::AggroSurroundingPeasants(uActorID_Monster, 1); + if ( pMonster->pMonsterInfo.uExp ) + pParty->GivePartyExp(pMonsterStats->pInfos[pMonster->pMonsterInfo.uID].uExp); + v40 = SPEECH_51; + if ( rand() % 100 < 20 ) + v40 = ((signed int)pMonster->pMonsterInfo.uHP >= 100) + 1; + player->PlaySound((PlayerSpeech)v40, 0); + if ( bShowDamage ) + { + pMonsterName = (char *)uDamageAmount; + pPlayerName = player->pName; // "%s inflicts %lu points killing %s" + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[175], player->pName, uDamageAmount, pMonster); + ShowStatusBarString(pTmpBuf.data(), 2u); + } + } + if ( pMonster->pActorBuffs[ACTOR_BUFF_PAIN_REFLECTION].uExpireTime > 0 + && uDamageAmount != 0 ) + player->ReceiveDamage(uDamageAmount, attackElement); + int knockbackValue = 20 * v61 / (signed int)pMonster->pMonsterInfo.uHP; + if ( (player->GetSpecialItemBonus(24) || hit_will_stun) && pMonster->DoesDmgTypeDoDamage(DMGT_EARTH) ) + { + extraRecoveryTime = 20; + knockbackValue = 10; + if ( !pParty->bTurnBasedModeOn ) + extraRecoveryTime = (int)(flt_6BE3A8_debug_recmod2 * 42.66666666666666); + pMonster->pMonsterInfo.uRecoveryTime += extraRecoveryTime; + if ( bShowDamage ) + { + pMonsterName = player->pName; // "%s stuns %s" + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[635], player->pName, pMonster); + ShowStatusBarString(pTmpBuf.data(), 2u); + } + } + if ( hit_will_paralyze && pMonster->CanAct() && pMonster->DoesDmgTypeDoDamage(DMGT_EARTH)) + { + v43 = player->GetActualSkillLevel(PLAYER_SKILL_MACE); + v45 = SkillToMastery(v43); + v46 = pParty->uTimePlayed + (signed int)(signed __int64)((double)(signed int)(7680 * (v43 & 0x3F)) * 0.033333335); + pMonster->pActorBuffs[ACTOR_BUFF_PARALYZED].Apply(v46, v45, 0, 0, 0); + if ( bShowDamage ) + { + pMonsterName = player->pName; // "%s paralyzes %s" + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[636], player->pName, pMonster); + ShowStatusBarString(pTmpBuf.data(), 2u); + } + } + if ( knockbackValue > 10 ) + knockbackValue = 10; + if ( !MonsterStats::BelongsToSupertype(pMonster->pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT) ) + { + pVelocity->x = fixpoint_mul(knockbackValue, pVelocity->x); + pVelocity->y = fixpoint_mul(knockbackValue, pVelocity->y); + pVelocity->z = fixpoint_mul(knockbackValue, pVelocity->z); + pMonster->vVelocity.x = 50 * LOWORD(pVelocity->x); + pMonster->vVelocity.y = 50 * LOWORD(pVelocity->y); + pMonster->vVelocity.z = 50 * LOWORD(pVelocity->z); + } + Actor::AddBloodsplatOnDamageOverlay(uActorID_Monster, 1, v61); +} +//----- (004BBF61) -------------------------------------------------------- +void Actor::Arena_summon_actor( int monster_id, __int16 x, int y, int z ) +{ + int v12; // ebx@7 + int v13; // eax@8 + __int16 v16; // [sp+10h] [bp-4h]@3 + + if (uNumActors < 500) + { + v16 = 0; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + v16 = pIndoor->GetSector(x, y, z); + pActors[uNumActors].Reset(); + strcpy(pActors[uNumActors].pActorName, pMonsterStats->pInfos[monster_id].pName); + pActors[uNumActors].sCurrentHP = LOWORD(pMonsterStats->pInfos[monster_id].uHP); + memcpy(&pActors[uNumActors].pMonsterInfo, &pMonsterStats->pInfos[monster_id], 0x58u); + pActors[uNumActors].word_000086_some_monster_id = monster_id; + pActors[uNumActors].uActorRadius = pMonsterList->pMonsters[monster_id - 1].uMonsterRadius; + pActors[uNumActors].uActorHeight = pMonsterList->pMonsters[monster_id - 1].uMonsterHeight; + pActors[uNumActors].uMovementSpeed = pMonsterList->pMonsters[monster_id - 1].uMovementSpeed; + pActors[uNumActors].vInitialPosition.x = x; + pActors[uNumActors].vPosition.x = x; + pActors[uNumActors].uAttributes |= ACTOR_AGGRESSOR; + pActors[uNumActors].pMonsterInfo.uTreasureType = 0; + pActors[uNumActors].pMonsterInfo.uTreasureLevel = 0; + pActors[uNumActors].pMonsterInfo.uTreasureDiceSides = 0; + pActors[uNumActors].pMonsterInfo.uTreasureDiceRolls = 0; + pActors[uNumActors].pMonsterInfo.uTreasureDropChance = 0; + pActors[uNumActors].vInitialPosition.y = y; + pActors[uNumActors].vPosition.y = y; + pActors[uNumActors].vInitialPosition.z = z; + pActors[uNumActors].vPosition.z = z; + pActors[uNumActors].uTetherDistance = 256; + pActors[uNumActors].uSectorID = v16; + pActors[uNumActors].uGroup = 1; + pActors[uNumActors].pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Long; + pActors[uNumActors].PrepareSprites(0); + for ( int i = 0; i < 4; i++) + pSoundList->LoadSound(pMonsterList->pMonsters[monster_id - 1].pSoundSampleIDs[i], 0); + v12 = 0; + do + { + v13 = pSoundList->LoadSound(v12 + word_4EE088_sound_ids[pMonsterStats->pInfos[monster_id].uSpell1ID], 1); + v12++; + } + while ( v13 ); + ++uNumActors; + } +} +//----- (00426E10) -------------------------------------------------------- +int stru319::which_player_to_attack(Actor *pActor) +{ + signed int v2; // ebx@1 + bool flag; // edi@37 + int v22; // [sp+8h] [bp-140h]@3 + int Victims_list[60]; // [sp+48h] [bp-100h]@48 + int for_sex; // [sp+13Ch] [bp-Ch]@1 + int for_race; // [sp+140h] [bp-8h]@1 + int for_class; // [sp+144h] [bp-4h]@1 + + for_class = -1; + for_race = -1; + for_sex = -1; + v2 = 0; + if ( pActor->pMonsterInfo.uAttackPreference ) + { + for ( uint i = 0; i < 16; i++ ) + { + v22 = pActor->pMonsterInfo.uAttackPreference & (1 << i); + if ( v22 ) + { + switch ( v22 ) + { + case 1: + for_class = 0; + break; + case 2: + for_class = 12; + break; + case 4: + for_class = 16; + break; + case 8: + for_class = 28; + break; + case 16: + for_class = 24; + break; + case 32: + for_class = 32; + break; + case 64: + for_class = 20; + break; + case 128: + for_class = 4; + break; + case 256: + for_class = 8; + break; + case 512: + for_sex = 0; + break; + case 1024: + for_sex = 1; + break; + case 2048: + for_race = 0; + break; + case 4096: + for_race = 1; + break; + case 8192: + for_race = 3; + break; + case 16384: + for_race = 2; + break; + } + v2 = 0; + for ( uint j = 0; j < 4; ++j ) + { + flag = 0; + if ( for_class != -1 && for_class == pPlayers[j + 1]->classType ) + flag = true; + if ( for_sex != -1 && for_sex == pPlayers[j + 1]->uSex ) + flag = true; + if ( for_race != -1 && for_race == pPlayers[j + 1]->GetRace() ) + flag = true; + if ( flag == true ) + { + if ( !(pPlayers[j + 1]->pConditions[Condition_Paralyzed] | pPlayers[j + 1]->pConditions[Condition_Unconcious] + | pPlayers[j + 1]->pConditions[Condition_Dead] | pPlayers[j + 1]->pConditions[Condition_Pertified] | pPlayers[j + 1]->pConditions[Condition_Eradicated]) ) + Victims_list[v2++] = j; + } + } + } + } + if ( v2 ) + return Victims_list[rand() % v2]; + } + for ( uint i = 0; i < 4; ++i ) + { + if ( !(pPlayers[i + 1]->pConditions[Condition_Paralyzed] | pPlayers[i + 1]->pConditions[Condition_Unconcious] + | pPlayers[i + 1]->pConditions[Condition_Dead] | pPlayers[i + 1]->pConditions[Condition_Pertified] | pPlayers[i + 1]->pConditions[Condition_Eradicated]) ) + Victims_list[v2++] = i; + } + if ( v2 ) + return Victims_list[rand() % v2]; + else + return 0; +} +//----- (00427546) -------------------------------------------------------- +int stru319::_427546(int a2) +{ + int result; // eax@2 + + if (a2 >= 0) + { + if (a2 >= 1) + result = (a2 >= 2) + 2; + else + result = 1; + } + else + { + result = 0; + } + return result; +} +//----- (0042F184) -------------------------------------------------------- +int stru319::FindClosestActor(int pick_depth, int a3, int a4) +{ + int v4; // edi@1 + stru319 *v5; // esi@1 + int v6; // eax@2 + int v7; // eax@4 + // int result; // eax@5 + // int *v9; // edx@8 + // signed int v10; // ebx@10 + // int v11; // edi@11 + //Actor *v12; // esi@12 + //unsigned __int16 v13; // ax@12 + // int v14; // eax@22 + //char v15; // zf@30 + // int v16; // esi@32 + // int v17; // ecx@34 + // stru319 *v18; // eax@39 + // int v19; // edx@39 + // int v20; // ecx@41 + // unsigned __int16 v21; // ax@42 + // unsigned int v22; // [sp+8h] [bp-24h]@11 + //unsigned int v23; // [sp+Ch] [bp-20h]@7 + stru319 *v24; // [sp+10h] [bp-1Ch]@1 + // unsigned int v25; // [sp+14h] [bp-18h]@8 + // int *v26; // [sp+18h] [bp-14h]@8 + // int v27; // [sp+1Ch] [bp-10h]@10 + // int *v28; // [sp+20h] [bp-Ch]@10 + //unsigned int v29; // [sp+24h] [bp-8h]@7 + // int v30; // [sp+28h] [bp-4h]@6 + // int i; // [sp+38h] [bp+Ch]@33 + // signed int v32; // [sp+3Ch] [bp+10h]@32 + + v4 = 0; + v5 = this; + v24 = this; + //if ( pRenderer->pRenderD3D ) + { + v6 = a3 != 0; + if (a4) + LOBYTE(v6) = v6 | 8; + v7 = pGame->pVisInstance->PickClosestActor(OBJECT_Actor, pick_depth, v6, 657456, -1); + if (v7 != -1) + return (unsigned __int16)v7; + else return 0; + } + /*else // software impl + { + v30 = 0; + if ( pRenderer->pActiveZBuffer ) + { + if ( (signed int)viewparams->uScreen_topL_Y < (signed int)viewparams->uScreen_BttmR_Y ) + { + v9 = &pRenderer->pActiveZBuffer[viewparams->uScreen_topL_X + 640 * viewparams->uScreen_topL_Y]; + v26 = &pRenderer->pActiveZBuffer[viewparams->uScreen_topL_X + 640 * viewparams->uScreen_topL_Y]; + for ( v25 = viewparams->uScreen_BttmR_Y - viewparams->uScreen_topL_Y; v25; --v25 ) + { + if ( (signed int)viewparams->uScreen_topL_X < (signed int)viewparams->uScreen_BttmR_X ) + { + v28 = v9; + v10 = v4; + for ( v27 = viewparams->uScreen_BttmR_X - viewparams->uScreen_topL_X; v27; --v27 ) + { + v22 = *v28; + v11 = *v28 & 0xFFFF; + if (PID_TYPE(v11) == OBJECT_Actor) + { + if ( pActors[PID_ID(v11)].uAIState != Dead ) + { + if ( pActors[PID_ID(v11)].uAIState != Dying && pActors[PID_ID(v11)].uAIState != Removed + && pActors[PID_ID(v11)].uAIState != Summoned && pActors[PID_ID(v11)].uAIState != Disabled + && (!a3 || pActors[PID_ID(v11)].GetActorsRelation(0)) ) + { + if ( (!a4 || MonsterStats::BelongsToSupertype(pActors[PID_ID(v11)].pMonsterInfo.uID, MONSTER_SUPERTYPE_UNDEAD)) + && v22 <= pick_depth << 16 ) + { + v14 = 0; + if ( v10 > 0 ) + { + for ( v14; v14 < v30; ++v14 ) + { + if ( dword_50BDA0[v14] == v11 ) + break; + } + } + if ( v14 == v30 && v10 < 100 ) + { + ++v30; + dword_50BC10[v10] = v22; + dword_50BDA0[v10] = v11; + ++v10; + } + } + } + } + } + ++v28; + } + v4 = v30; + v5 = v24; + } + v9 = v26 + 640; + v26 += 640; + } + } + if ( v4 > 0 ) + { + v16 = (int)dword_50BC10.data(); + for ( v32 = 1; v32 - 1 < v4; ++v32 ) + { + for ( i = v32; i < v4; ++i ) + { + v17 = dword_50BC10[i]; + if ( dword_50BC10[i] < *(int *)v16 ) + { + dword_50BC10[i] = *(int *)v16; + *(int *)v16 = v17; + } + } + v16 += 4; + } + v5 = v24; + if ( v4 > 0 ) + { + v18 = v24; + for ( v19 = v4; v19; --v19 ) + { + *(int *)&v18->field_0 = (*(int *)&v18[(char *)dword_50BC10.data() - (char *)v24].field_0 >> 3) & 0x1FFF; + v18 += 4; + } + } + } + v20 = 0; + for ( *(int *)&v5[2000].field_0 = v4; v20 < v4; ++v20 ) + { + v21 = pActors[*(int *)&v5[4 * v20].field_0].uAIState; + if ( v21 != 4 && v21 != 5 ) + break; + } + if ( v20 != v4 ) + { + result = 8 * *(int *)&v5[4 * v20].field_0; + LOBYTE(result) = result | 3; + return result; + } + } + } + return 0;*/ +} + +//----- (0042F4DA) -------------------------------------------------------- +bool CheckActors_proximity() +{ + signed int distance; // edi@1 + int for_x; // ebx@5 + int for_y; // [sp+Ch] [bp-10h]@5 + int for_z; // [sp+10h] [bp-Ch]@5 + + + distance = 5120; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor) + distance = 2560; + + if ( (signed int)uNumActors <= 0 ) + return false; + for ( uint i = 0; i < (signed int)uNumActors; ++i ) + { + for_x = abs(pActors[i].vInitialPosition.x - pParty->vPosition.x); + for_y = abs(pActors[i].vInitialPosition.y - pParty->vPosition.y); + for_z = abs(pActors[i].vInitialPosition.z - pParty->vPosition.z); + if ( int_get_vector_length(for_x, for_y, for_z) < distance ) + { + if ( pActors[i].uAIState != Dead ) + { + if ( pActors[i].uAIState != Dying && pActors[i].uAIState != Removed + && pActors[i].uAIState != Disabled && pActors[i].uAIState != Summoned + && (pActors[i].ActorEnemy() || pActors[i].GetActorsRelation(0) ) ) + return true; + } + } + } + return false; +} + + +//----- (00426A5A) -------------------------------------------------------- +void Actor::LootActor() +{ + signed int v2; // edi@1 + unsigned __int8 v7; // al@30 + char *v9; // [sp-4h] [bp-3Ch]@10 + char *v10; // [sp-4h] [bp-3Ch]@31 + char *v11; // [sp-4h] [bp-3Ch]@38 + ItemGen Dst; // [sp+Ch] [bp-2Ch]@1 + bool itemFound; // [sp+30h] [bp-8h]@1 + int v14; // [sp+34h] [bp-4h]@1 + + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + Dst.Reset(); + v2 = 0; + itemFound = false; + v14 = 0; + if ( !ActorHasItem() ) + { + for (uchar i = 0; i < this->pMonsterInfo.uTreasureDiceRolls; i++ ) + v14 += rand() % this->pMonsterInfo.uTreasureDiceSides + 1; + if ( v14 ) + { + pParty->PartyFindsGold(v14, 0); + viewparams->bRedrawGameUI = 1; + } + } + else + { + if ( this->ActorHasItems[3].uItemID != 0 && this->ActorHasItems[3].GetItemEquipType() == EQUIP_GOLD ) + { + v14 = this->ActorHasItems[3].uSpecEnchantmentType; + this->ActorHasItems[3].Reset(); + if ( v14 ) + { + pParty->PartyFindsGold(v14, 0); + viewparams->bRedrawGameUI = 1; + } + } + } + if ( this->uCarriedItemID ) + { + Dst.Reset(); + Dst.uItemID = this->uCarriedItemID; + v9 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName; + if ( v14 ) + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[490], v14, v9); + else + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[471], v9); + ShowStatusBarString(pTmpBuf2.data(), 2); + if ( Dst.GetItemEquipType() == 12 ) + { + Dst.uNumCharges = rand() % 6 + Dst.GetDamageMod() + 1; + Dst.uMaxCharges = Dst.uNumCharges; + } + if ( pItemsTable->pItems[Dst.uItemID].uEquipType == 14 && Dst.uItemID != 220 ) + Dst.uEnchantmentType = 2 * rand() % 4 + 2; + pItemsTable->SetSpecialBonus(&Dst); + if ( !pParty->AddItemToParty(&Dst) ) + pParty->SetHoldingItem(&Dst); + this->uCarriedItemID = 0; + if ( this->ActorHasItems[0].uItemID ) + { + if ( !pParty->AddItemToParty(this->ActorHasItems) ) + { + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + pParty->SetHoldingItem(this->ActorHasItems); + } + this->ActorHasItems[0].Reset(); + } + if ( this->ActorHasItems[1].uItemID ) + { + if ( !pParty->AddItemToParty(&this->ActorHasItems[1]) ) + { + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + pParty->SetHoldingItem(&this->ActorHasItems[1]); + } + this->ActorHasItems[1].Reset(); + } + this->Remove(); + return; + } + if ( this->ActorHasItem() ) + { + if ( this->ActorHasItems[3].uItemID ) + { + memcpy(&Dst, &this->ActorHasItems[3], sizeof(Dst)); + this->ActorHasItems[3].Reset(); + //v11 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName; + if ( v14 ) + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[490], v14, pItemsTable->pItems[Dst.uItemID].pUnidentifiedName); + else + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[471], pItemsTable->pItems[Dst.uItemID].pUnidentifiedName); + ShowStatusBarString(pTmpBuf2.data(), 2); + if ( !pParty->AddItemToParty(&Dst) ) + pParty->SetHoldingItem(&Dst); + itemFound = true; + } + } + else + { + if ( rand() % 100 < this->pMonsterInfo.uTreasureDropChance && (v7 = this->pMonsterInfo.uTreasureLevel) != 0 ) + { + pItemsTable->GenerateItem(v7, this->pMonsterInfo.uTreasureType, &Dst); + v10 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName; + if ( v14 ) + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[490], v14, v10);//Âû íàøëè ^I[%d] çîëîò^L[îé;ûõ;ûõ] è ïðåäìåò (%s)! + else + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[471], v10);//Âû íàøëè ^Pv[%s]! + ShowStatusBarString(pTmpBuf2.data(), 2); + if ( !pParty->AddItemToParty(&Dst) ) + pParty->SetHoldingItem(&Dst); + itemFound = true; + } + } + if ( this->ActorHasItems[0].uItemID ) + { + if ( !pParty->AddItemToParty(this->ActorHasItems) ) + { + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + pParty->SetHoldingItem(this->ActorHasItems); + itemFound = true; + } + this->ActorHasItems[0].Reset(); + } + if ( this->ActorHasItems[1].uItemID ) + { + if ( !pParty->AddItemToParty(&this->ActorHasItems[1]) ) + { + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + pParty->SetHoldingItem(&this->ActorHasItems[1]); + itemFound = true; + } + this->ActorHasItems[1].Reset(); + } + if ( !itemFound || rand() % 100 < 90 )//for repeatedly get gold and item + this->Remove(); +} + + +//----- (00427102) -------------------------------------------------------- +bool Actor::_427102_IsOkToCastSpell( signed int a2 ) +{ + switch(a2) + { + case SPELL_BODY_POWER_CURE: + { + if ( this->sCurrentHP >= (signed int)this->pMonsterInfo.uHP ) + return false; + return true; + } + case SPELL_LIGHT_DISPEL_MAGIC: + { + for (int i = 0; i < 20; i++) + { + if (pParty->pPartyBuffs[i].uExpireTime > 0) + return true; + } + for ( int i = 1; i <= 4; i++ ) + { + for ( int j = 0; j < 22; j++ ) + { + if (pPlayers[i]->pPlayerBuffs[j].uExpireTime > 0) + return true; + } + } + return false; + } + case SPELL_LIGHT_DAY_OF_PROTECTION: + { + return this->pActorBuffs[ACTOR_BUFF_DAY_OF_PROTECTION].uExpireTime <= 0; + break; + } + case SPELL_LIGHT_HOUR_OF_POWER: + { + return this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime <= 0; + break; + } + case SPELL_DARK_PAIN_REFLECTION: + { + return this->pActorBuffs[ACTOR_BUFF_PAIN_REFLECTION].uExpireTime <= 0; + break; + } + case SPELL_BODY_HAMMERHANDS: + { + return this->pActorBuffs[ACTOR_BUFF_PAIN_HAMMERHANDS].uExpireTime <= 0; + break; + } + case SPELL_FIRE_HASTE: + { + return this->pActorBuffs[ACTOR_BUFF_HASTE].uExpireTime <= 0; + break; + } + case SPELL_AIR_SHIELD: + { + return this->pActorBuffs[ACTOR_BUFF_SHIELD].uExpireTime <= 0; + break; + } + case SPELL_EARTH_STONESKIN: + { + return this->pActorBuffs[ACTOR_BUFF_STONESKIN].uExpireTime <= 0; + break; + } + case SPELL_SPIRIT_BLESS: + { + return this->pActorBuffs[ACTOR_BUFF_BLESS].uExpireTime <= 0; + break; + } + case SPELL_SPIRIT_FATE: + { + return this->pActorBuffs[ACTOR_BUFF_FATE].uExpireTime <= 0; + break; + } + case SPELL_SPIRIT_HEROISM: + { + return this->pActorBuffs[ACTOR_BUFF_HEROISM].uExpireTime <= 0; + break; + } + default: + return true; + } +} + + +//----- (0042704B) -------------------------------------------------------- +ABILITY_INDEX Actor::special_ability_use_check( int a2 ) +{ + signed int okToCastSpell1; // ebx@5 + signed int okToCastSpell2; // edi@5 + + if ( this->pMonsterInfo.uSpecialAbilityType == 2 + && this->pMonsterInfo.uSpecialAbilityDamageDiceBonus < 3 + && rand() % 100 < 5 ) + this->SummonMinion(a2); + okToCastSpell1 = this->_427102_IsOkToCastSpell(this->pMonsterInfo.uSpell1ID); + okToCastSpell2 = this->_427102_IsOkToCastSpell(this->pMonsterInfo.uSpell2ID); + if ( okToCastSpell1 && this->pMonsterInfo.uSpell1UseChance && rand() % 100 < this->pMonsterInfo.uSpell1UseChance ) + return ABILITY_SPELL1; + if ( okToCastSpell2 && this->pMonsterInfo.uSpell2UseChance && rand() % 100 < this->pMonsterInfo.uSpell2UseChance ) + return ABILITY_SPELL2; + if (this->pMonsterInfo.uAttack2Chance && rand() % 100 < this->pMonsterInfo.uAttack2Chance) + return ABILITY_ATTACK2; + return ABILITY_ATTACK1; +} + + + +//----- (004273BB) -------------------------------------------------------- +bool Actor::_4273BB_DoesHitOtherActor( Actor *defender, int a3, int a4 ) +{ + signed int v6; // ebx@1 + signed int v7; // esi@1 + int armorSum; // ebx@10 + signed int a2a; // [sp+18h] [bp+Ch]@1 + + v6 = defender->pMonsterInfo.uAC; + v7 = 0; + a2a = 0; + if ( defender->pActorBuffs[ACTOR_BUFF_SOMETHING_THAT_HALVES_AC].uExpireTime > 0 ) + v6 /= 2; + if ( defender->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + v7 = defender->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uPower; + if ( defender->pActorBuffs[ACTOR_BUFF_STONESKIN].uExpireTime > 0 && defender->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower > v7 ) + v7 = defender->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower; + armorSum = v7 + v6; + if ( this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + a2a = this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_BLESS].uExpireTime > 0 && this->pActorBuffs[ACTOR_BUFF_BLESS].uPower > a2a ) + a2a = this->pActorBuffs[ACTOR_BUFF_BLESS].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_FATE].uExpireTime > 0 ) + { + a2a += this->pActorBuffs[ACTOR_BUFF_FATE].uPower; + this->pActorBuffs[ACTOR_BUFF_FATE].Reset(); + } + return rand() % (armorSum + 2 * this->pMonsterInfo.uLevel + 10) + a2a + 1 > armorSum + 5; +} + +//----- (004274AD) -------------------------------------------------------- +bool Actor::ActorHitOrMiss(Player *pPlayer) +{ + signed int v3; // edi@1 + signed int v4; // esi@8 + int v5; // esi@8 + + v3 = 0; + if ( this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + v3 = this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_BLESS].uExpireTime > 0 && this->pActorBuffs[ACTOR_BUFF_BLESS].uPower > v3 ) + v3 = this->pActorBuffs[ACTOR_BUFF_BLESS].uPower; + if ( this->pActorBuffs[ACTOR_BUFF_FATE].uExpireTime > 0 ) + { + v3 += this->pActorBuffs[ACTOR_BUFF_FATE].uPower; + this->pActorBuffs[ACTOR_BUFF_FATE].Reset(); + } + v4 = pPlayer->GetActualAC() + 2 * this->pMonsterInfo.uLevel + 10; + v5 = rand() % v4 + 1; + return (v3 + v5 > pPlayer->GetActualAC() + 5); +} + + +//----- (0042756B) -------------------------------------------------------- +int Actor::CalcMagicalDamageToActor(DAMAGE_TYPE dmgType, signed int incomingDmg) +{ + int v4; // edx@1 + int v5; // ecx@1 + signed int v6; // eax@4 + signed int result; // eax@17 + signed int v8; // esi@18 + + v4 = 0; + v5 = 0; + if ( this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + v5 = this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uPower; + switch ( dmgType ) + { + case DMGT_FIRE: + v6 = this->pMonsterInfo.uResFire; + v4 = v5; + break; + case DMGT_ELECTR: + v6 = this->pMonsterInfo.uResAir; + v4 = v5; + break; + case DMGT_COLD: + v6 = this->pMonsterInfo.uResWater; + v4 = v5; + break; + case DMGT_EARTH: + v6 = this->pMonsterInfo.uResEarth; + v4 = v5; + break; + case DMGT_PHISYCAL: + v6 = this->pMonsterInfo.uResPhysical; + break; + case DMGT_SPIRIT: + v6 = this->pMonsterInfo.uResSpirit; + break; + case DMGT_MIND: + v6 = this->pMonsterInfo.uResMind; + v4 = v5; + break; + case DMGT_BODY: + v6 = this->pMonsterInfo.uResBody; + v4 = v5; + break; + case DMGT_LIGHT: + v6 = this->pMonsterInfo.uResLight; + break; + case DMGT_DARK: + v6 = this->pMonsterInfo.uResDark; + break; + default: + v6 = 0; + break; + } + if ( v6 < 200 ) + { + v8 = v4 + v6 + 30; + for (int i = 0; i < 4; i++) + { + if ( rand() % v8 < 30 ) + break; + incomingDmg /= 2; + } + result = incomingDmg; + } + else + result = 0; + return result; +} + +//----- (00427662) -------------------------------------------------------- +bool Actor::DoesDmgTypeDoDamage(DAMAGE_TYPE uType) +{ + signed int resist; // esi@2 + bool result; // eax@13 + + switch ( uType ) + { + case 0: + resist = this->pMonsterInfo.uResFire; + break; + case 1: + resist = this->pMonsterInfo.uResAir; + break; + case 2: + resist = this->pMonsterInfo.uResWater; + break; + case 3: + resist = this->pMonsterInfo.uResEarth; + break; + case 4: + resist = this->pMonsterInfo.uResPhysical; + break; + case 6: + resist = this->pMonsterInfo.uResSpirit; + break; + case 7: + resist = this->pMonsterInfo.uResMind; + case 8: + resist = this->pMonsterInfo.uResBody; + break; + case 9: + resist = this->pMonsterInfo.uResLight; + break; + case 10: + resist = this->pMonsterInfo.uResDark; + break; + default: + return 1; + } + if ( resist < 200 ) + result = rand() % ((this->pMonsterInfo.uLevel >> 2) + resist + 30) < 30; + else + result = 0; + return result; +} + +//----- (00448A98) -------------------------------------------------------- +void __fastcall ToggleActorGroupFlag(unsigned int uGroupID, unsigned int uFlag, unsigned int bToggle) +{ + if ( uGroupID ) + { + if ( bToggle ) + { + for ( uint i = 0; i < (unsigned int)uNumActors; ++i ) + { + if ( pActors[i].uGroup == uGroupID ) + { + pActors[i].uAttributes |= uFlag; + if ( uFlag == 0x10000 ) + { + pActors[i].uAIState = Disabled; + pActors[i].UpdateAnimation(); + } + } + } + } + else + { + for ( uint i = 0; i < (unsigned int)uNumActors; ++i ) + { + if ( pActors[i].uGroup == uGroupID ) + { + if ( uFlag == 0x10000 ) + { + if ( pActors[i].uAIState != Dead ) + { + if ( pActors[i].uAIState != 4 && pActors[i].uAIState != 11 ) + pActors[i].uAIState = Standing; + } + } + LODWORD(pActors[i].uAttributes) &= ~uFlag; + } + } + } + } +} + +//----- (004014E6) -------------------------------------------------------- +void Actor::MakeActorAIList_ODM() +{ + int v1; // eax@4 + unsigned int v7; // ST20_4@10 + int distance; // edi@10 + int v10; // ebx@14 + int v21; // [sp+Ch] [bp-14h]@4 + int v22; // [sp+10h] [bp-10h]@4 + + pParty->uFlags &= 0xFFFFFFCF;//~0x30 + + ai_arrays_size = 0; + for (uint i = 0; i < uNumActors; ++i) + { + Actor* actor = &pActors[i]; + + actor->ResetAlive();//~0x400 + if (!actor->CanAct()) + { + actor->ResetActive(); + continue; + } + + v22 = abs(pParty->vPosition.z - actor->vPosition.z); + v21 = abs(pParty->vPosition.y - actor->vPosition.y); + v1 = abs(pParty->vPosition.x - actor->vPosition.x); + v7 = int_get_vector_length(v22, v21, v1); + distance = v7 - actor->uActorRadius; + if ( distance < 0 ) + distance = 0; + + if (distance < 5632) + { + actor->ResetHostile(); + if ( actor->ActorEnemy() || actor->GetActorsRelation(0) ) + { + //v11 = (pParty->uFlags & 0x10) == 0; + actor->uAttributes |= ACTOR_HOSTILE; + if (distance < 5120 ) + pParty->SetYellowAlert(); + if (distance < 307) + pParty->SetRedAlert(); + } + actor->uAttributes |= ACTOR_ACTIVE; + ai_near_actors_distances[ai_arrays_size] = distance; + ai_near_actors_ids[ai_arrays_size++] = i; + } + else + actor->ResetActive(); + } + + /* + result = v27; + if ( v27 > 0 ) + { + v14 = 0; + v15 = 1; + v26 = 1; + do + { + while ( 1 ) + { + v24 = v15; + if ( v15 >= result ) + break; + v16 = ai_near_actors_distances[v14]; + if ( v16 > ai_near_actors_distances[v15] ) + { + v17 = &ai_near_actors_ids[v15]; + v18 = ai_near_actors_ids[v14]; + ai_near_actors_ids[v14] = *v17; + *v17 = v18; + v15 = v24; + ai_near_actors_distances[v14] = ai_near_actors_distances[v24]; + ai_near_actors_distances[v24] = v16; + } + result = v27; + ++v15; + } + ++v14; + v15 = v26 + 1; + v26 = v15; + } + while ( v15 - 1 < result ); + }*/ + + for (uint i = 0; i < ai_arrays_size; ++i) + for (uint j = 0; j < i; ++j) + if (ai_near_actors_distances[j] > ai_near_actors_distances[i]) + { + int tmp = ai_near_actors_distances[j]; + ai_near_actors_distances[j] = ai_near_actors_distances[i]; + ai_near_actors_distances[i] = tmp; + + tmp = ai_near_actors_ids[j]; + ai_near_actors_ids[j] = ai_near_actors_ids[i]; + ai_near_actors_ids[i] = tmp; + } + + + if (ai_arrays_size > 30) + ai_arrays_size = 30; + + for (uint i = 0; i < ai_arrays_size; ++i) + pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_ALIVE;//0x400 +} + +//----- (004016FA) -------------------------------------------------------- +int Actor::MakeActorAIList_BLV() +{ + int v1; // eax@4 + int distance; // edi@10 + int v13; // edx@24 + int v15; // ebx@26 + unsigned int v17; // esi@27 + int v18; // ecx@31 + signed int v19; // edi@31 + signed int v25; // eax@40 + int j; // edi@45 + int v30; // eax@48 + int v37; // [sp+Ch] [bp-18h]@1 + int v38; // [sp+10h] [bp-14h]@4 + int v39; // [sp+14h] [bp-10h]@4 + int i; // [sp+18h] [bp-Ch]@31 + uint v45; // [sp+20h] [bp-4h]@1 + + // __debugbreak(); // refactor for blv ai + pParty->uFlags &= 0xFFFFFFCF;//~0x30 + v37 = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z); + v45 = 0; + for ( uint i = 0; i < (signed int)uNumActors; ++i ) + { + pActors[i].ResetAlive();//~0x0400 + if ( !pActors[i].CanAct() ) + { + pActors[i].ResetActive(); + continue; + } + v1 = abs(pParty->vPosition.x - pActors[i].vPosition.x); + v38 = abs(pParty->vPosition.y - pActors[i].vPosition.y); + v39 = abs(pParty->vPosition.z - pActors[i].vPosition.z); + + distance = int_get_vector_length(v39, v38, v1) - pActors[i].uActorRadius; + if ( distance < 0 ) + distance = 0; + if ( distance < 10240 ) + { + pActors[i].ResetHostile();//~0x01000000 + if ( pActors[i].ActorEnemy() || pActors[i].GetActorsRelation(0) ) + { + pActors[i].uAttributes |= ACTOR_HOSTILE; + if ( !(pParty->uFlags & 0x10) && (double)distance < 307.2 ) + pParty->SetRedAlert(); + if ( !(pParty->uFlags & 0x20) && distance < 5120 ) + pParty->SetYellowAlert(); + } + ai_near_actors_distances[v45] = distance; + ai_near_actors_ids[v45] = i; + v45++; + } + else + pActors[i].ResetActive(); + } + v13 = 0; + if ( v45 > 0 ) + { + for ( uint i = 1; i < v45; i++ ) + { + for ( uint j = 1; j < v45; ++j ) + { + v15 = ai_near_actors_distances[v13]; + if ( ai_near_actors_distances[v13] > ai_near_actors_distances[j] ) + { + v17 = ai_near_actors_ids[v13]; + ai_near_actors_ids[v13] = ai_near_actors_ids[j]; + ai_near_actors_ids[j] = v17; + ai_near_actors_distances[v13] = ai_near_actors_distances[j]; + ai_near_actors_distances[j] = v15; + } + } + ++v13; + } + } + v18 = 0; + v19 = 0; + for ( i = 0; i < v45; i++ ) + { + if ( pActors[ai_near_actors_ids[i]].ActorNearby() + || sub_4070EF_prolly_detect_player(PID(OBJECT_Actor,ai_near_actors_ids[i]), 4) ) + { + pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_NEARBY; + ai_array_4F6638_actor_ids[v19] = ai_near_actors_ids[i]; + ai_array_4F5E68[v19++] = ai_near_actors_distances[i]; + if ( v19 >= 30 ) + break; + } + } + ai_arrays_size = v19; + if ( (signed int)uNumActors > 0 ) + { + for ( uint i = 0; i < (signed int)uNumActors; ++i ) + { + if ( pActors[i].CanAct() && pActors[i].uSectorID == v37 ) + { + v25 = 0; + if ( v19 <= 0 ) + { + pActors[i].uAttributes |= ACTOR_ACTIVE; + ai_array_4F6638_actor_ids[ai_arrays_size++] = i; + } + else + { + while ( ai_array_4F6638_actor_ids[v25] != i ) + { + ++v25; + if ( v25 >= v19 ) + { + pActors[i].uAttributes |= ACTOR_ACTIVE; + ai_array_4F6638_actor_ids[ai_arrays_size++] = i; + break; + } + } + } + } + } + } + for ( j = 0; j < v45; ++j ) + { + if ( pActors[ai_near_actors_ids[j]].uAttributes & 0xC000 && pActors[ai_near_actors_ids[j]].CanAct() ) + { + v30 = 0; + if ( ai_arrays_size <= 0 ) + ai_array_4F6638_actor_ids[ai_arrays_size++] = ai_near_actors_ids[j]; + else + { + while ( ai_array_4F6638_actor_ids[v30] != ai_near_actors_ids[j] ) + { + ++v30; + if ( v30 >= ai_arrays_size ) + { + ai_array_4F6638_actor_ids[ai_arrays_size++] = ai_near_actors_ids[j]; + break; + } + } + } + } + } + if ( ai_arrays_size > 30 ) + ai_arrays_size = 30; + memcpy(ai_near_actors_ids.data(), ai_array_4F6638_actor_ids.data(), 4 * ai_arrays_size); + memcpy(ai_near_actors_distances.data(), ai_array_4F5E68.data(), 4 * ai_arrays_size); + for ( uint i = 0; i < ai_arrays_size; i++ ) + pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_ALIVE;//0x400 + return ai_arrays_size; +} + + +//----- (004070EF) -------------------------------------------------------- +bool __fastcall sub_4070EF_prolly_detect_player(unsigned int uObjID, unsigned int uObj2ID) +{ + signed int v2; // eax@1 + int obj1_sector; // eax@4 + float v8; // ST24_4@5 + signed int v12; // eax@7 + int obj2_z; // edi@11 + int obj2_x; // esi@11 + int obj2_sector; // eax@13 + float v20; // ST24_4@14 + int dist_x; // ebx@16 + signed int dist_3d; // ecx@16 + int v25; // eax@18 + BLVFace *v29; // ebx@32 + Vec3_short_ *v30; // esi@32 + int v31; // eax@32 + int v32; // ST50_4@44 + int v33; // ST54_4@44 + int v34; // eax@44 + signed int v38; // esi@45 + __int16 next_sector; // bx@58 + int v47; // [sp+18h] [bp-50h]@20 + int v48; // [sp+1Ch] [bp-4Ch]@20 + int v49; // [sp+20h] [bp-48h]@20 + int dist_z; // [sp+24h] [bp-44h]@16 + signed int higher_z; // [sp+24h] [bp-44h]@27 + signed int lower_z; // [sp+28h] [bp-40h]@26 + signed int higher_y; // [sp+2Ch] [bp-3Ch]@23 + signed int lower_y; // [sp+30h] [bp-38h]@22 + signed int higher_x; // [sp+34h] [bp-34h]@21 + signed int lower_x; // [sp+38h] [bp-30h]@20 + signed int sectors_visited; // [sp+3Ch] [bp-2Ch]@28 + int v58; // [sp+44h] [bp-24h]@50 + int v59; // [sp+48h] [bp-20h]@44 + int obj2_y; // [sp+50h] [bp-18h]@11 + int obj1_x; // [sp+58h] [bp-10h]@4 + int obj1_y; // [sp+5Ch] [bp-Ch]@4 + int obj1_z; // [sp+60h] [bp-8h]@4 + int current_sector; // [sp+64h] [bp-4h]@7 + int dist_y; + int v70; + + v2 = PID_ID(uObjID); + switch( PID_TYPE(uObjID) ) + { + case OBJECT_Decoration: + obj1_x = pLevelDecorations[v2].vPosition.x; + obj1_y = pLevelDecorations[v2].vPosition.y; + obj1_z = pLevelDecorations[v2].vPosition.z; + obj1_sector = pIndoor->GetSector(obj1_x, obj1_y, obj1_z); + break; + case OBJECT_Actor: + obj1_x = pActors[v2].vPosition.x; + obj1_y = pActors[v2].vPosition.y; + v8 = (double)pActors[v2].uActorHeight * 0.69999999; + //v9 = v8 + 6.7553994e15; + //obj1_z = LODWORD(v9) + pActors[v2].vPosition.z; + obj1_z = (int)v8 + pActors[v2].vPosition.z; + obj1_sector = pActors[v2].uSectorID; + break; + case OBJECT_Item: + obj1_x = pSpriteObjects[v2].vPosition.x; + obj1_y = pSpriteObjects[v2].vPosition.y; + obj1_z = pSpriteObjects[v2].vPosition.z; + obj1_sector = pSpriteObjects[v2].uSectorID; + break; + default: + return 0; + } + v12 = PID_ID(uObj2ID); + switch( PID_TYPE(uObj2ID) ) + { + case OBJECT_Decoration: + obj2_z = pLevelDecorations[v12].vPosition.z; + obj2_x = pLevelDecorations[v12].vPosition.x; + obj2_y = pLevelDecorations[v12].vPosition.y; + obj2_sector = pIndoor->GetSector(obj2_x, obj2_y, obj2_z); + break; + case OBJECT_Player: + obj2_x = pParty->vPosition.x; + obj2_z = pParty->sEyelevel + pParty->vPosition.z; + obj2_y = pParty->vPosition.y; + obj2_sector = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->sEyelevel + pParty->vPosition.z); + break; + case OBJECT_Actor: + obj2_y = pActors[v12].vPosition.y; + obj2_x = pActors[v12].vPosition.x; + v20 = (double)pActors[v12].uActorHeight * 0.69999999; + //v21 = v20 + 6.7553994e15; + //obj2_z = LODWORD(v21) + pActors[v12].vPosition.z; + obj2_z = (int)v20 + pActors[v12].vPosition.z; + obj2_sector = pActors[v12].uSectorID; + break; + case OBJECT_Item: + obj2_x = pSpriteObjects[v12].vPosition.x; + obj2_z = pSpriteObjects[v12].vPosition.z; + obj2_y = pSpriteObjects[v12].vPosition.y; + obj2_sector = pSpriteObjects[v12].uSectorID; + break; + default: + return 0; + } + dist_x = obj2_x - obj1_x; + dist_z = obj2_z - obj1_z; + dist_y = obj2_y - obj1_y; + dist_3d = integer_sqrt(dist_x * dist_x + dist_y * dist_y + dist_z * dist_z); + //range check + if ( dist_3d > 5120 ) + return 0; + if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor) + return 1; + v25 = 65536; + if ( dist_3d ) + v25 = 65536 / dist_3d; + v49 = dist_x * v25; + v47 = dist_z * v25; + v48 = dist_y * v25; + if ( obj1_x < obj2_x ) + { + lower_x = obj1_x; + higher_x = obj2_x; + } + else + { + lower_x = obj2_x; + higher_x = obj1_x; + } + if ( obj1_y < obj2_y ) + { + lower_y = obj1_y; + higher_y = obj2_y; + } + else + { + lower_y = obj2_y; + higher_y = obj1_y; + } + if ( obj1_z < obj2_z ) + { + lower_z = obj1_z; + higher_z = obj2_z; + } + else + { + lower_z = obj2_z; + higher_z = obj1_z; + } + sectors_visited = 0; + //monster in same sector with player + if ( obj1_sector == obj2_sector ) + return 1; + //search starts from monster + current_sector = obj1_sector; + for( int current_portal = 0; current_portal < pIndoor->pSectors[current_sector].uNumPortals; current_portal++ ) + { + v29 = &pIndoor->pFaces[pIndoor->pSectors[current_sector].pPortals[current_portal]]; + v30 = &pIndoor->pVertices[*v29->pVertexIDs]; + v31 = v29->pFacePlane_old.vNormal.z * (v30->z - obj1_z) + + v29->pFacePlane_old.vNormal.y * (v30->y - obj1_y) + + v29->pFacePlane_old.vNormal.x * (v30->x - obj1_x); + + if ( current_sector != v29->uSectorID ) + v31 = -v31; + + if ( v31 >= 0 && v30->x != obj1_x && v30->y != obj1_y && v30->z != obj1_z) + continue; + + if( lower_x > v29->pBounding.x2 + || higher_x < v29->pBounding.x1 + || lower_y > v29->pBounding.y2 + || higher_y < v29->pBounding.y1 + || lower_z > v29->pBounding.z2 + || higher_z < v29->pBounding.z1 ) + { + continue; + } + + v32 = fixpoint_mul(v29->pFacePlane_old.vNormal.x,v49); + v34 = fixpoint_mul(v29->pFacePlane_old.vNormal.y,v48); + v33 = fixpoint_mul(v29->pFacePlane_old.vNormal.z,v47); + + v59 = v32 + v33 + v34; + if ( v59 ) + { + v70 = v29->pFacePlane_old.dist + + obj1_z * v29->pFacePlane_old.vNormal.z + + obj1_x * v29->pFacePlane_old.vNormal.x + + obj1_y * v29->pFacePlane_old.vNormal.y; + v38 = -v70; + + // if ( v59 <= 0 ^ v70 <= 0 ) + + /* TEMPORARY + if ( v59 <= 0 && v70 <= 0 ) + { + continue; + } + if ( !(v59 <= 0 && v70 <= 0) ) + { + continue; + } + */ + + if( abs(v38) >> 14 > abs(v59) ) + continue; + + v58 = fixpoint_div(v38,v59); + + if( v58 < 0 ) + continue; + + if(!sub_4075DB(obj1_x + ((fixpoint_mul(v49,v58) + 32768) >> 16), obj1_y + ((fixpoint_mul(v48,v58) + 32768) >> 16), + obj1_z + ((fixpoint_mul(v47,v58) + 32768) >> 16), v29) ) + { + continue; + } + + //if there is no next sector turn back + if ( v29->uSectorID == current_sector ) + next_sector = v29->uBackSectorID; + else + next_sector = v29->uSectorID; + + //no more portals, quit + if ( next_sector == current_sector ) + break; + + ++sectors_visited; + current_sector = next_sector; + + //found player, quit + if ( next_sector == obj2_sector ) + return 1; + + current_sector = next_sector; + + //did we hit limit for portals? + //does the next room have portals? + if ( sectors_visited < 30 && pIndoor->pSectors[current_sector].uNumPortals > 0) + { + current_portal=-1; + continue; + } + else + break; + } + } + //did we stop in the sector where player is? + if ( current_sector != obj2_sector ) + return 0; + return 1; +} + + +//----- (00450B0A) -------------------------------------------------------- +bool __fastcall SpawnActor(unsigned int uMonsterID) +{ + unsigned int v1; // ebx@1 + bool result; // eax@2 + unsigned int v6; // ecx@5 + Actor actor; // [sp+4h] [bp-350h]@5 + Vec3_int_ pOut; // [sp+348h] [bp-Ch]@5 + + v1 = uMonsterID; + if ( uNumActors == 499 ) + result = 0; + else + { + if ( (signed int)uMonsterID >= (signed int)pMonsterList->uNumMonsters ) + v1 = 0; + memset(&actor, 0, sizeof(Actor)); + strcpy(actor.pActorName, pMonsterStats->pInfos[v1 + 1].pName); + actor.sCurrentHP = LOWORD(pMonsterStats->pInfos[v1 + 1].uHP); + memcpy(&actor.pMonsterInfo, &pMonsterStats->pInfos[v1 + 1], sizeof(MonsterInfo)); + actor.word_000086_some_monster_id = v1 + 1; + actor.uActorRadius = pMonsterList->pMonsters[v1].uMonsterRadius; + actor.uActorHeight = pMonsterList->pMonsters[v1].uMonsterHeight; + actor.uMovementSpeed = pMonsterList->pMonsters[v1].uMovementSpeed; + + Vec3_int_::Rotate(200, pParty->sRotationY, 0, pParty->vPosition, &pOut.x, &pOut.z, &pOut.y); + actor.vInitialPosition.x = pOut.x; + actor.vPosition.x = pOut.x; + actor.uTetherDistance = 256; + actor.vInitialPosition.y = LOWORD(pOut.z); + actor.vPosition.y = LOWORD(pOut.z); + actor.vInitialPosition.z = LOWORD(pOut.y); + actor.vPosition.z = LOWORD(pOut.y); + pSprites_LOD->DeleteSomeSprites(); + pPaletteManager->ResetNonTestLocked(); + v6 = uNumActors - 1; + if ( dword_5C6DF8 == 1 ) + { + dword_5C6DF8 = 0; + v6 = uNumActors++; + } + memcpy(&pActors[v6], &actor, sizeof(Actor)); + pActors[v6].PrepareSprites(1); + result = 1; + } + return result; +} +// 5C6DF8: using guessed type int dword_5C6DF8; + + +//----- (0044FA4C) -------------------------------------------------------- +signed int __fastcall sub_44FA4C_spawn_light_elemental(int a1, int a2, int a3) +{ + signed int result; // eax@13 + int v10; // ebx@16 + const char *v15; // [sp-4h] [bp-24h]@2 + unsigned int uFaceID; // [sp+8h] [bp-18h]@16 + int v19; // [sp+Ch] [bp-14h]@16 + size_t v20; // [sp+10h] [bp-10h]@6 + int v21; // [sp+14h] [bp-Ch]@14 + unsigned int v23; // [sp+1Ch] [bp-4h]@6 + + if ( a2 == 4 ) + v15 = "Elemental Light C"; + else if ( a2 == 3 ) + v15 = "Elemental Light B"; + else + v15 = "Elemental Light A"; + + v23 = pMonsterList->GetMonsterIDByName(v15); + v20 = 0; + for ( v20; v20 < uNumActors; v20++ ) + { + if ( pActors[v20].uAIState == Removed ) + break; + } + + result = uNumActors + 1; + if ( v20 != uNumActors || result < 500 ) + { + v21 = 0; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + v21 = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z); + v19 = (((uCurrentlyLoadedLevelType != LEVEL_Outdoor) - 1) & 0x40) + 64; + pActors[v20].Reset(); + strcpy(pActors[v20].pActorName, pMonsterStats->pInfos[v23 + 1].pName); + pActors[v20].sCurrentHP = pMonsterStats->pInfos[v23 + 1].uHP; + memcpy(&pActors[v20].pMonsterInfo, &pMonsterStats->pInfos[v23 + 1], sizeof(MonsterInfo)); + pActors[v20].word_000086_some_monster_id = v23 + 1; + pActors[v20].uActorRadius = pMonsterList->pMonsters[v23].uMonsterRadius; + pActors[v20].uActorHeight = pMonsterList->pMonsters[v23].uMonsterHeight; + pActors[v20].pMonsterInfo.uTreasureDiceRolls = 0; + pActors[v20].pMonsterInfo.uTreasureType = 0; + pActors[v20].pMonsterInfo.uExp = 0; + pActors[v20].uMovementSpeed = pMonsterList->pMonsters[v23].uMovementSpeed; + v10 = rand() % 2048; + pActors[v20].vInitialPosition.x = pParty->vPosition.x + fixpoint_mul(stru_5C6E00->Cos(v10), v19); + pActors[v20].vPosition.x = pActors[v20].vInitialPosition.x; + pActors[v20].vInitialPosition.y = pParty->vPosition.y + fixpoint_mul(stru_5C6E00->Sin(v10), v19); + pActors[v20].vPosition.y = pActors[v20].vInitialPosition.y; + pActors[v20].vInitialPosition.z = pParty->vPosition.z; + pActors[v20].vPosition.z = pActors[v20].vInitialPosition.z; + pActors[v20].uTetherDistance = 256; + pActors[v20].uSectorID = v21; + pActors[v20].PrepareSprites(0); + pActors[v20].pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + pActors[v20].uAlly = 9999; + pActors[v20].uGroup = 0; + pActors[v20].uCurrentActionTime = 0; + pActors[v20].uAIState = Summoned; + pActors[v20].uCurrentActionLength = 256; + pActors[v20].UpdateAnimation(); + + result = pIndoor->GetSector(pActors[v20].vPosition.x, pActors[v20].vPosition.y, pActors[v20].vPosition.z); + if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor + || result == v21 + && (result = BLV_GetFloorLevel(pActors[v20].vPosition.x, pActors[v20].vPosition.y, pActors[v20].vPosition.z, result, &uFaceID), result != -30000) + && (result = abs(result - pParty->vPosition.z), result <= 1024) ) + { + if ( v20 == uNumActors ) + ++uNumActors; + pActors[v20].uSummonerID = PID(OBJECT_Player, a1); + result = pActors[v20].pActorBuffs[ACTOR_BUFF_SUMMONED].Apply(pParty->uTimePlayed + (a3 * 128) / 30.0f, a2, a1, 0, 0); + } + } + return result; +} + +//----- (0044F57C) -------------------------------------------------------- +void SpawnEncounter(MapInfo *pMapInfo, SpawnPointMM7 *spawn, int a3, int a4, int a5) +{ + int v7; // eax@2 + char v8; // zf@5 + int v12; // edx@9 + int v18; // esi@31 + Actor *pMonster; // esi@35 + int v23; // edx@36 + signed int v24; // edi@36 + int v25; // ecx@36 + MonsterDesc *v27; // edi@48 + signed int v28; // eax@48 + int v32; // eax@50 + int v37; // eax@51 + int v38; // eax@52 + int v39; // edi@52 + std::string v40; // [sp-18h] [bp-100h]@60 + const char *v44; // [sp-8h] [bp-F0h]@13 + char *pTexture; // [sp-4h] [bp-ECh]@9 + char Str[32]; // [sp+Ch] [bp-DCh]@60 + char Str2[120]; // [sp+2Ch] [bp-BCh]@29 + unsigned int uFaceID; // [sp+A4h] [bp-44h]@52 + MonsterInfo *Src; // [sp+A8h] [bp-40h]@50 + int v50; // [sp+ACh] [bp-3Ch]@47 + char Source[32]; // [sp+B0h] [bp-38h]@20 + int v52; // [sp+D0h] [bp-18h]@34 + int v53; // [sp+D4h] [bp-14h]@34 + int pSector; // [sp+D8h] [bp-10h]@32 + int pPosX; // [sp+DCh] [bp-Ch]@32 + int v56; // [sp+E0h] [bp-8h]@8 + int v57; // [sp+E4h] [bp-4h]@1 + + //auto a2 = spawn; + v57 = 0; + //v5 = pMapInfo; + //v6 = spawn; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + v7 = pOutdoor->ddm.field_C_alert; + else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor) + v7 = pIndoor->dlv.field_C_alert; + else + v7 = 0; + if (v7) + v8 = (spawn->uAttributes & 1) == 0; + else + v8 = (spawn->uAttributes & 1) == 1; + if (v8) + return; + //result = (void *)(spawn->uIndex - 1); + v56 = 1; + switch (spawn->uIndex - 1) + { + case 0: + //v9 = pMapInfo->uEncounterMonster1AtLeast; + //v10 = rand(); + //v11 = pMapInfo->uEncounterMonster1AtMost; + //pTexture = pMapInfo->pEncounterMonster1Texture; + v12 = rand() % (pMapInfo->uEncounterMonster1AtMost - pMapInfo->uEncounterMonster1AtLeast + 1); + //v13 = pMapInfo->Dif_M1; + v57 = pMapInfo->Dif_M1; + v56 = pMapInfo->uEncounterMonster1AtLeast + v12; + strcpy(Source, pMapInfo->pEncounterMonster1Texture); + break; + case 3: + //pTexture = pMapInfo->pEncounterMonster1Texture; + //v44 = "%s A"; + sprintf(Source, "%s A", pMapInfo->pEncounterMonster1Texture); + break; + case 4: + //pTexture = pMapInfo->pEncounterMonster2Texture; + //v44 = "%s A"; + sprintf(Source, "%s A", pMapInfo->pEncounterMonster2Texture); + break; + case 5: + //pTexture = pMapInfo->pEncounterMonster3Texture; + //v44 = "%s A"; + sprintf(Source, "%s A", pMapInfo->pEncounterMonster3Texture); + break; + case 1: + //v9 = pMapInfo->uEncounterMonster2AtLeast; + //v14 = rand(); + //v15 = pMapInfo->uEncounterMonster2AtMost; + //pTexture = pMapInfo->pEncounterMonster2Texture; + v12 = rand() % (pMapInfo->uEncounterMonster2AtMost - pMapInfo->uEncounterMonster2AtLeast + 1); + //v13 = pMapInfo->Dif_M2; + v57 = pMapInfo->Dif_M2; + v56 = pMapInfo->uEncounterMonster2AtLeast + v12; + strcpy(Source, pMapInfo->pEncounterMonster2Texture); + break; + case 6: + //pTexture = pMapInfo->pEncounterMonster1Texture; + //v44 = "%s B"; + sprintf(Source, "%s B", pMapInfo->pEncounterMonster1Texture); + break; + case 7: + //pTexture = pMapInfo->pEncounterMonster2Texture; + //v44 = "%s B"; + sprintf(Source, "%s B", pMapInfo->pEncounterMonster2Texture); + break; + case 8: + //pTexture = pMapInfo->pEncounterMonster3Texture; + //v44 = "%s B"; + sprintf(Source, "%s B", pMapInfo->pEncounterMonster3Texture); + break; + case 2: + //v9 = pMapInfo->uEncounterMonster3AtLeast; + //v16 = rand(); + //v17 = pMapInfo->uEncounterMonster3AtMost; + //pTexture = pMapInfo->pEncounterMonster3Texture; + v12 = rand() % (pMapInfo->uEncounterMonster3AtMost - pMapInfo->uEncounterMonster3AtLeast + 1); + //v13 = pMapInfo->Dif_M3; + v57 = pMapInfo->Dif_M3; + v56 = pMapInfo->uEncounterMonster3AtLeast + v12; + strcpy(Source, pMapInfo->pEncounterMonster3Texture); + break; + case 9: + //pTexture = pMapInfo->pEncounterMonster1Texture; + //v44 = "%s C"; + sprintf(Source, "%s C", pMapInfo->pEncounterMonster1Texture); + break; + case 10: + //pTexture = pMapInfo->pEncounterMonster2Texture; + //v44 = "%s C"; + sprintf(Source, "%s C", pMapInfo->pEncounterMonster2Texture); + break; + case 11: + //pTexture = pMapInfo->pEncounterMonster3Texture; + //v44 = "%s C"; + sprintf(Source, "%s C", pMapInfo->pEncounterMonster3Texture); + break; + default: + return; + } + if (Source[0] == '0') + return; + v57 += a3; + if ( v57 > 4 ) + v57 = 4; + strcpy(Str2, Source); + if ( a4 ) + v56 = a4; + v18 = v56; + if ( (signed int)(v56 + uNumActors) >= 500 ) + return; + pSector = 0; + pPosX = spawn->vPosition.x; + a4 = spawn->vPosition.y; + a3 = spawn->vPosition.z; + if ( uCurrentlyLoadedLevelType == LEVEL_Indoor ) + pSector = pIndoor->GetSector(spawn->vPosition.x, spawn->vPosition.y, spawn->vPosition.z); + v53 = 0; + v52 = (((uCurrentlyLoadedLevelType != LEVEL_Outdoor) - 1) & 0x40) + 64; + if ( v18 <= 0 ) + return; + for (uint i = v53; i < v56; ++i) + { + pMonster = &pActors[uNumActors]; + pActors[uNumActors].Reset(); + if ( v57 ) + { + v23 = rand() % 100; + v24 = 3; + v25 = (unsigned __int16)word_4E8152[3 * v57]; + if ( v23 >= v25 ) + { + if ( v23 < v25 + (unsigned __int16)word_4E8152[3 * v57 + 1] ) + v24 = 2; + } + else + v24 = 1; + if ( v24 == 1 ) + { + pTexture = Source; + v44 = "%s A"; + } + else + { + if ( v24 == 2 ) + { + pTexture = Source; + v44 = "%s B"; + } + else + { + if ( v24 != 3 ) + continue; + pTexture = Source; + v44 = "%s C"; + } + } + sprintf(Str2, v44, pTexture); + } + v50 = pMonsterList->GetMonsterIDByName(Str2); + pTexture = Str2; + if ( (signed __int16)v50 == -1 ) + { + sprintf(Str, "Can't create random monster: '%s'! See MapStats.txt and Monsters.txt!", pTexture); + MessageBoxA(nullptr, Str, nullptr, 0); + ExitProcess(0); + } + v27 = &pMonsterList->pMonsters[(signed __int16)v50]; + v28 = pMonsterStats->FindMonsterByTextureName(pTexture); + if ( !v28 ) + v28 = 1; + Src = &pMonsterStats->pInfos[v28]; + strcpy(pMonster->pActorName, Src->pName); + pMonster->sCurrentHP = Src->uHP; + assert(sizeof(MonsterInfo) == 88); + memcpy(&pMonster->pMonsterInfo, Src, sizeof(MonsterInfo));//Uninitialized portail memory access + pMonster->word_000086_some_monster_id = v50 + 1; + pMonster->uActorRadius = v27->uMonsterRadius; + pMonster->uActorHeight = v27->uMonsterHeight; + pMonster->uMovementSpeed = v27->uMovementSpeed; + pMonster->vInitialPosition.x = spawn->vPosition.x; + pMonster->vPosition.x = spawn->vPosition.x; + pMonster->uTetherDistance = 256; + pMonster->vInitialPosition.y = a4; + pMonster->vPosition.y = a4; + pMonster->vInitialPosition.z = a3; + pMonster->vPosition.z = a3; + pMonster->uSectorID = pSector; + pMonster->uGroup = spawn->uGroup; + pMonster->PrepareSprites(0); + pMonster->pMonsterInfo.uHostilityType = MonsterInfo::Hostility_Friendly; + v32 = rand(); + a3 = fixpoint_mul(stru_5C6E00->Cos(v32 % 2048), v52); + pPosX = a3 + spawn->vPosition.x; + a3 = fixpoint_mul(stru_5C6E00->Sin(v32 % 2048), v52); + a4 = a3 + spawn->vPosition.y; + a3 = spawn->vPosition.z; + if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor ) + { + if ( a5 ) + pMonster->uAttributes |= ACTOR_AGGRESSOR; + ++uNumActors; + continue; + } + v37 = pIndoor->GetSector(pPosX, a4, spawn->vPosition.z); + if ( v37 == pSector ) + { + v38 = BLV_GetFloorLevel(pPosX, a4, a3, v37, &uFaceID); + v39 = v38; + if ( v38 != -30000 ) + { + if ( abs(v38 - a3) <= 1024 ) + { + a3 = v39; + if ( a5 ) + pMonster->uAttributes |= ACTOR_AGGRESSOR; + ++uNumActors; + continue; + } + } + } + ; + //v53 = (char *)v53 + 1; + //result = v53; + } + //while ( (signed int)v53 < v56 ); +} + +//----- (00438F8F) -------------------------------------------------------- +void area_of_effect__damage_evaluate() +{ + int attacker_type; // ecx@3 + signed int v3; // eax@3 + unsigned int target_id; // edi@6 + int target_type; // eax@6 + int v10; // edi@8 + Vec3_int_ attacker_coord; // ST04_12@9 + // int v12; // ST0C_4@10 + int v15; // edx@15 + int v19; // edi@15 + int v23; // edx@18 + int v24; // eax@18 + // int v30; // eax@29 + int v31; // edx@29 + int v32; // eax@29 + int v33; // ST24_4@29 + SpriteObject *v36; // [sp+0h] [bp-28h]@0 + int attacker_id; // [sp+10h] [bp-18h]@1 + int v44; // [sp+14h] [bp-14h]@15 + //Vec3_int_ *pVelocity; // [sp+1Ch] [bp-Ch]@2 + signed int a1; // [sp+20h] [bp-8h]@8 + int v48; // [sp+24h] [bp-4h]@8 + + + for (attacker_id = 0; attacker_id < AttackerInfo.count; ++attacker_id) + { + attacker_type = PID_TYPE(AttackerInfo.pIDs[attacker_id]); + v3 = PID_ID(AttackerInfo.pIDs[attacker_id]); + + if (attacker_type == 2) + { + v36 = &pSpriteObjects[v3]; + attacker_type = PID_TYPE(pSpriteObjects[v3].spell_caster_pid); + v3 = PID_ID(pSpriteObjects[v3].spell_caster_pid); + } + + if (AttackerInfo.field_3EC[attacker_id] & 1) + { + target_id = PID_ID(ai_near_actors_targets_pid[v3]); + target_type = PID_TYPE(ai_near_actors_targets_pid[v3]) - 3; + if (target_type) + { + if (target_type == 1)//party damage from monsters(ïîâðåæäåíèÿ ãðóïïå îò ìîíñòðîâ) + { + v10 = pParty->vPosition.y - AttackerInfo.pYs[attacker_id]; + a1 = pParty->vPosition.x - AttackerInfo.pXs[attacker_id]; + v48 = pParty->vPosition.y - AttackerInfo.pYs[attacker_id]; + if (a1 * a1 + v10 * v10 + + ((signed int)(pParty->vPosition.z + pParty->uPartyHeight) >> (1 - AttackerInfo.pZs[attacker_id])) + * ((signed int)(pParty->vPosition.z + pParty->uPartyHeight) >> (1 - AttackerInfo.pZs[attacker_id])) + < (unsigned int)((AttackerInfo.field_324[attacker_id] + 32) * (AttackerInfo.field_324[attacker_id] + 32))) + { + attacker_coord.x = AttackerInfo.pXs[attacker_id]; + attacker_coord.y = AttackerInfo.pYs[attacker_id]; + attacker_coord.z = AttackerInfo.pZs[attacker_id]; + if (sub_407A1C(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z + pParty->sEyelevel, attacker_coord)) + DamagePlayerFromMonster(AttackerInfo.pIDs[attacker_id], AttackerInfo.field_450[attacker_id], &AttackerInfo.vec_4B4[attacker_id], stru_50C198.which_player_to_attack(&pActors[v3])); + } + } + } + else//Actor damage from monsters(ïîâðåæäåíèå ìåñòíîãî æèòåëÿ) + { + if (SHIDWORD(pActors[target_id].pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime) > 0 + || SHIDWORD(pActors[target_id].pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime) >= 0 + && LODWORD(pActors[target_id].pActorBuffs[ACTOR_BUFF_PARALYZED].uExpireTime) + || pActors[target_id].CanAct()) + { + v15 = pActors[target_id].vPosition.y - AttackerInfo.pYs[attacker_id]; + a1 = pActors[target_id].vPosition.x - AttackerInfo.pXs[attacker_id]; + v44 = pActors[target_id].vPosition.z; + v19 = AttackerInfo.field_324[attacker_id] + pActors[target_id].uActorRadius; + v48 = v15; + if (a1 * a1 + v15 * v15 + (pActors[target_id].vPosition.z + (pActors[target_id].uActorHeight >> 1) - AttackerInfo.pZs[attacker_id]) + * (pActors[target_id].vPosition.z + (pActors[target_id].uActorHeight >> 1) - AttackerInfo.pZs[attacker_id]) < (unsigned int)(v19 * v19)) + { + attacker_coord.x = AttackerInfo.pXs[attacker_id]; + attacker_coord.y = AttackerInfo.pYs[attacker_id]; + attacker_coord.z = AttackerInfo.pZs[attacker_id]; + if (sub_407A1C(pActors[target_id].vPosition.x, pActors[target_id].vPosition.y, pActors[target_id].vPosition.z + 50, attacker_coord)) + { + Vec3_int_::Normalize(&a1, &v48, &v44); + AttackerInfo.vec_4B4[attacker_id].x = a1; + AttackerInfo.vec_4B4[attacker_id].y = v48; + AttackerInfo.vec_4B4[attacker_id].z = v44; + Actor::ActorDamageFromMonster(AttackerInfo.pIDs[attacker_id], target_id, &AttackerInfo.vec_4B4[attacker_id], AttackerInfo.field_450[attacker_id]); + } + } + } + } + } + else //damage from spells(ïîâðåæäåíèÿ îò çàêëîâ(ìåòåîðèòíûé äîæäü)) + { + v23 = pParty->vPosition.y - AttackerInfo.pYs[attacker_id]; + v24 = ((signed int)pParty->uPartyHeight / 2) - AttackerInfo.pZs[attacker_id]; + a1 = pParty->vPosition.x - AttackerInfo.pXs[attacker_id]; + v48 = pParty->vPosition.y - AttackerInfo.pYs[attacker_id]; + if (a1 * a1 + v23 * v23 + (pParty->vPosition.z + v24) * (pParty->vPosition.z + v24) < (unsigned int)((AttackerInfo.field_324[attacker_id] + 32) * (AttackerInfo.field_324[attacker_id] + 32))) + {//party damage (ïîâðåæäåíèÿ ãðóïïå) + attacker_coord.x = AttackerInfo.pXs[attacker_id]; + attacker_coord.y = AttackerInfo.pYs[attacker_id]; + attacker_coord.z = AttackerInfo.pZs[attacker_id]; + if (sub_407A1C(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z + pParty->sEyelevel, attacker_coord)) + { + for (uint i = 0; i < 4; ++i) + { + if (!(HIDWORD(pParty->pPlayers[i].pConditions[Condition_Dead]) | LODWORD(pParty->pPlayers[i].pConditions[Condition_Dead])) + && !pParty->pPlayers[i].pConditions[Condition_Pertified] && !pParty->pPlayers[i].pConditions[Condition_Eradicated]) + DamagePlayerFromMonster(AttackerInfo.pIDs[attacker_id], AttackerInfo.field_450[attacker_id], &AttackerInfo.vec_4B4[attacker_id], i); + } + } + } + if ((signed int)uNumActors > 0) + {//actors damage(ïîâðåæäåíèÿ äðóãèì ó÷àñòíèêàì) + for (int actorID = 0; (signed int)actorID < (signed int)uNumActors; ++actorID) + { + if (pActors[actorID].CanAct()) + { + //v30 = pActors[actorID].vPosition.y - AttackerInfo.pYs[attacker_id]; + a1 = pActors[actorID].vPosition.x - AttackerInfo.pXs[attacker_id]; + v31 = pActors[actorID].vPosition.z; + v48 = pActors[actorID].vPosition.y - AttackerInfo.pYs[attacker_id]; + v44 = pActors[actorID].vPosition.z; + v32 = (pActors[actorID].uActorHeight / 2) - AttackerInfo.pZs[attacker_id]; + v33 = pActors[actorID].uActorRadius + AttackerInfo.field_324[attacker_id]; + if (a1 * a1 + v48 * v48 + (v31 + v32) * (v31 + v32) < (unsigned int)(v33 * v33)) + { + attacker_coord.x = AttackerInfo.pXs[attacker_id]; + attacker_coord.y = AttackerInfo.pYs[attacker_id]; + attacker_coord.z = AttackerInfo.pZs[attacker_id]; + if (sub_407A1C(pActors[actorID].vPosition.x, pActors[actorID].vPosition.y, pActors[actorID].vPosition.z + 50, attacker_coord))//÷òî äåëàåò ô-öèÿ? + { + Vec3_int_::Normalize(&a1, &v48, &v44); + AttackerInfo.vec_4B4[attacker_id].x = a1; + AttackerInfo.vec_4B4[attacker_id].y = v48; + AttackerInfo.vec_4B4[attacker_id].z = v44; + switch (attacker_type) + { + case OBJECT_Player: + Actor::DamageMonsterFromParty(AttackerInfo.pIDs[attacker_id], actorID, &AttackerInfo.vec_4B4[attacker_id]); + break; + case OBJECT_Actor: + if (v36 && pActors[v3].GetActorsRelation(&pActors[actorID])) + Actor::ActorDamageFromMonster(AttackerInfo.pIDs[attacker_id], actorID, &AttackerInfo.vec_4B4[attacker_id], v36->field_61); + break; + case OBJECT_Item: + ItemDamageFromActor(AttackerInfo.pIDs[attacker_id], actorID, &AttackerInfo.vec_4B4[attacker_id]); + break; + } + } + } + } + } + } + } + } + AttackerInfo.count = 0; +} + +//----- (0043AE12) -------------------------------------------------------- +double __fastcall sub_43AE12(signed int a1) +{ + //signed int v1; // ST00_4@1 + signed int v2; // ecx@1 + double v3; // st7@1 + double result; // st7@6 + + v3 = (double)a1; + for (v2 = 0; v2 < 5; ++v2) + { + if (v3 < flt_4E4A80[v2 + 5]) + break; + } + if (v2 <= 0 || v2 >= 5) + { + if (v2) + result = flt_4E4A80[4]; + else + result = flt_4E4A80[0]; + } + else + result = (flt_4E4A80[v2] - flt_4E4A80[v2 - 1]) * (v3 - flt_4E4A80[v2 + 4]) / (flt_4E4A80[v2 + 5] - flt_4E4A80[v2 + 4]) + flt_4E4A80[v2]; + return result; +} + +//----- (0043B057) -------------------------------------------------------- +void ItemDamageFromActor(unsigned int uObjID, unsigned int uActorID, Vec3_int_ *pVelocity) +{ + int v6; // eax@4 + int damage; // edi@4 + int a2a; // [sp+Ch] [bp-4h]@8 + + if (!pActors[uActorID].IsNotAlive()) + { + if (PID_TYPE(uObjID) == OBJECT_Item) + { + if (pSpriteObjects[PID_ID(uObjID)].spell_id) + { + v6 = _43AFE3_calc_spell_damage(pSpriteObjects[PID_ID(uObjID)].spell_id, pSpriteObjects[PID_ID(uObjID)].spell_level, pSpriteObjects[PID_ID(uObjID)].spell_skill, pActors[uActorID].sCurrentHP); + damage = pActors[uActorID].CalcMagicalDamageToActor((DAMAGE_TYPE)0, v6); + pActors[uActorID].sCurrentHP -= damage; + if (damage) + { + if (pActors[uActorID].sCurrentHP > 0) + Actor::AI_Stun(uActorID, uObjID, 0); + else + Actor::Die(uActorID); + a2a = 20 * damage / (signed int)pActors[uActorID].pMonsterInfo.uHP; + if (20 * damage / (signed int)pActors[uActorID].pMonsterInfo.uHP > 10) + a2a = 10; + if (!MonsterStats::BelongsToSupertype(pActors[uActorID].pMonsterInfo.uID, MONSTER_SUPERTYPE_TREANT)) + { + pVelocity->x = fixpoint_mul(a2a, pVelocity->x); + pVelocity->y = fixpoint_mul(a2a, pVelocity->y); + pVelocity->z = fixpoint_mul(a2a, pVelocity->z); + pActors[uActorID].vVelocity.x = 50 * LOWORD(pVelocity->x); + pActors[uActorID].vVelocity.y = 50 * LOWORD(pVelocity->y); + pActors[uActorID].vVelocity.z = 50 * LOWORD(pVelocity->z); + } + Actor::AddBloodsplatOnDamageOverlay(uActorID, 1, damage); + } + else + Actor::AI_Stun(uActorID, uObjID, 0); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Actor.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,340 @@ +#pragma once +#include "Monsters.h" +#include "Spells.h" +#include "Items.h" + + + + + + +/* 357 */ +#pragma pack(push, 1) +struct stru319 +{ + int which_player_to_attack(struct Actor *pActor); + int _427546(int a2); + int FindClosestActor(int a2, int a3, int a4); + + char field_0; +}; +#pragma pack(pop) + + +extern stru319 stru_50C198; // idb + + +enum ABILITY_INDEX +{ + ABILITY_ATTACK1 = 0, + ABILITY_ATTACK2 = 1, + ABILITY_SPELL1 = 2, + ABILITY_SPELL2 = 3, +}; + + + +/* 361 */ +enum ACTOR_BUFF_INDEX +{ + ACTOR_BUFF_CHARM = 1, + ACTOR_BUFF_SUMMONED = 2, + ACTOR_BUFF_SHRINK = 3, + ACTOR_BUFF_AFRAID = 4, + ACTOR_BUFF_STONED = 5, + ACTOR_BUFF_PARALYZED = 6, + ACTOR_BUFF_SLOWED = 7, + ACTOR_BUFF_SOMETHING_THAT_HALVES_AC = 8, + ACTOR_BUFF_BERSERK = 9, + ACTOR_BUFF_MASS_DISTORTION = 10, + ACTOR_BUFF_FATE = 11, + ACTOR_BUFF_ENSLAVED = 12, + ACTOR_BUFF_DAY_OF_PROTECTION = 13, + ACTOR_BUFF_HOUR_OF_POWER = 14, + ACTOR_BUFF_SHIELD = 15, + ACTOR_BUFF_STONESKIN = 16, + ACTOR_BUFF_BLESS = 17, + ACTOR_BUFF_HEROISM = 18, + ACTOR_BUFF_HASTE = 19, + ACTOR_BUFF_PAIN_REFLECTION = 20, + ACTOR_BUFF_PAIN_HAMMERHANDS = 21, +}; + + + + + +/* 295 */ +enum ObjectType +{ + OBJECT_Any = 0x0, + OBJECT_BLVDoor = 0x1, + OBJECT_Item = 0x2, + OBJECT_Actor = 0x3, + OBJECT_Player = 0x4, + OBJECT_Decoration = 0x5, + OBJECT_BModel = 0x6, +}; + + + + + + + +/* 264 */ +enum AIState : unsigned __int16 +{ + Standing = 0x0, + Tethered = 0x1, + AttackingMelee = 0x2, + AttackingRanged1 = 0x3, + Dying = 0x4, + Dead = 0x5, + Pursuing = 0x6, + Fleeing = 0x7, + Stunned = 0x8, + Fidgeting = 0x9, + Interacting = 10, + Removed = 11, + AttackingRanged2 = 0xC, + AttackingRanged3 = 0xD, + Stoned = 0xE, + Paralyzed = 0xF, + Resurrected = 16, + Summoned = 17, + AttackingRanged4 = 18, + Disabled = 19, +}; + +/* 265 */ +enum ActorAnimation : __int32 +{ + ANIM_Standing = 0x0, + ANIM_Walking = 0x1, + ANIM_AtkMelee = 0x2, + ANIM_AtkRanged = 0x3, + ANIM_GotHit = 0x4, + ANIM_Dying = 0x5, + ANIM_Dead = 0x6, + ANIM_Bored = 0x7, +}; +#pragma pack(pop) + +#define ACTOR_UNKNOW2 0x00000008 +#define ACTOR_STAND_IN_QUEUE 0x00000080 +#define ACTOR_ALIVE 0x00000400 +#define ACTOR_ACTIVE 0x00004000 +#define ACTOR_NEARBY 0x00008000 +#define ACTOR_UNKNOW11 0x00010000 +#define ACTOR_FLEEING 0x00020000 +#define ACTOR_UNKNOW5 0x00040000 +#define ACTOR_AGGRESSOR 0x00080000 +#define ACTOR_UNKNOW7 0x00100000 +#define ACTOR_ANIMATION 0x00200000 +#define ACTOR_UNKNOW9 0x00400000 +#define ACTOR_HAS_ITEM 0x00800000 +#define ACTOR_HOSTILE 0x01000000 + +#pragma pack(push, 1) + + + + +/* 247 */ +#pragma pack(push, 1) +struct AIDirection +{ + Vec3_int_ vDirection; + unsigned int uDistance; + unsigned int uDistanceXZ; + unsigned int uYawAngle; + unsigned int uPitchAngle; +}; +#pragma pack(pop) + + + + + +/* 71 */ +#pragma pack(push, 1) +struct ActorJob +{ + struct Vec3_short_ vPos; + unsigned __int16 uAttributes; + unsigned __int8 uAction; + unsigned __int8 uHour; + unsigned __int8 uDay; + unsigned __int8 uMonth; +}; +#pragma pack(pop) + + +/* 66 */ +#pragma pack(push, 1) +struct Actor +{ +//----- (0041F4C1) -------------------------------------------------------- + inline Actor() + { + signed int i; // edx@1 + + for ( i = 0; i < 22; i++ ) + { + this->pActorBuffs[i].uSkill = 0; + this->pActorBuffs[i].uPower = 0; + this->pActorBuffs[i].uExpireTime = 0; + this->pActorBuffs[i].uCaster = 0; + this->pActorBuffs[i].uFlags = 0; + } + for ( i = 0; i < 4; i++ ) + this->ActorHasItems[i].Reset(); + Reset(); + } + + void SummonMinion(int summonerId); + void Reset(); + void Remove(); + void PrepareSprites(char load_sounds_if_bit1_set); + void UpdateAnimation(); + signed int GetActorsRelation(Actor *a2); + void SetRandomGoldIfTheresNoItem(); + bool CanAct(); + bool IsNotAlive(); + bool IsPeasant(); + + inline void ResetAnimation(){uAttributes &= 0xFFDFFFFF;} + inline void ResetQueue(){uAttributes &= ~ACTOR_STAND_IN_QUEUE;} + inline void ResetActive(){uAttributes &= 0xFFFFBFFF;} + inline void ResetAlive(){uAttributes &= 0xFFFFFBFF;} + inline void ResetHasItem(){uAttributes &= 0xFF7FFFFF;} + inline void ResetHostile(){uAttributes &= 0xFEFFFFFF;} + inline void ResetAggressor(){uAttributes &= 0xFFF7FFFF;} + inline bool ActorEnemy()const {return(uAttributes & ACTOR_AGGRESSOR) != 0;} + inline bool ActorFriend()const {return(uAttributes & ACTOR_AGGRESSOR) == 0;} + inline bool ActorHasItem()const {return(uAttributes & ACTOR_HAS_ITEM) != 0;} + inline bool ActorNearby()const {return(uAttributes & ACTOR_NEARBY) != 0;} + + static void _SelectTarget(unsigned int uActorID, int *a2, bool can_target_party); + static void AI_Pursue3(unsigned int uActorID, unsigned int a2, signed int uActionLength, struct AIDirection *a4); + static void AI_Pursue2(unsigned int uActorID, unsigned int a2, signed int uActionLength, struct AIDirection *pDir, int a5); + static void AI_Flee(unsigned int uActorID, signed int edx0, int uActionLength, struct AIDirection *a4); + static void AI_Pursue1(unsigned int uActorID, unsigned int a2, signed int arg0, signed int uActionLength, struct AIDirection *pDir); + static void PlaySound(unsigned int uActorID, unsigned int uSoundID); + static void Die(unsigned int uActorID); + static void Resurrect(unsigned int uActorID); + static void AI_Bored(unsigned int uActorID, unsigned int uObjID, struct AIDirection *a4); + static void AI_Stun(unsigned int uActorID, signed int edx0, int arg0); + static char __fastcall _4031C1_update_job_never_gets_called(unsigned int uActorID, signed int a2, int a3); + static void AI_RandomMove(unsigned int uActor_id, unsigned int uTarget_id, int radius, int uActionLength); + static void AI_MissileAttack1(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir); + static void AI_MissileAttack2(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir); + static void AI_SpellAttack1(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir); + static void AI_SpellAttack2(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir); + static void AI_MeleeAttack(unsigned int uActorID, signed int sTargetPid, struct AIDirection *arg0); + static void __fastcall StandAwhile(unsigned int uActorID); + static void AI_Stand(unsigned int uActorID, unsigned int object_to_face_pid, unsigned int uActionLength, struct AIDirection *a4); + static void AI_StandOrBored(unsigned int uActorID, signed int uObjID, int uActionLength, struct AIDirection *a4); + static void AI_FaceObject(unsigned int uActorID, unsigned int uObjID, int _48, struct AIDirection *a4); + static void GetDirectionInfo(unsigned int uObj1ID, unsigned int uObj2ID, struct AIDirection *pOut, int a4); + static void Explode(unsigned int uActorID); + static void AI_RangedAttack(unsigned int uActorID, struct AIDirection *a2, int type, char a4); + static void AI_SpellAttack(unsigned int uActorID, struct AIDirection *pDir, int uSpellID, int a4, unsigned int uSkillLevel); + static void ActorDamageFromMonster(signed int attacker_id, unsigned int actor_id, struct Vec3_int_ *pVelocity, signed int a4); + + static unsigned short GetObjDescId( int spellId ); + + static void AggroSurroundingPeasants(unsigned int uActorID, int a2); + static bool ArePeasantsOfSameFaction(Actor *a1, Actor *a2); + static void StealFrom(unsigned int uActorID); + static void GiveItem(signed int uActorID, unsigned int uItemID, unsigned int bGive); + static void ToggleFlag(signed int uActorID, unsigned int uFlag, int bToggle); + static void ApplyFineForKillingPeasant(unsigned int uActorID); + static void DrawHealthBar(Actor *actor, struct GUIWindow *window); + int _43B3E0_CalcDamage(signed int dmgSource); + static void AddBloodsplatOnDamageOverlay(unsigned int uActorID, int a2, signed int a3); + + static bool _46DF1A_collide_against_actor(int a1, int a2); + static void Arena_summon_actor(int monster_id, __int16 x, int y, int z); + static void DamageMonsterFromParty(signed int a1, unsigned int uActorID_Monster, struct Vec3_int_ *pVelocity); + static void MakeActorAIList_ODM(); + static int MakeActorAIList_BLV(); + static void UpdateActorAI(); + static void InitializeActors(); + static unsigned int SearchAliveActors(unsigned int *pTotalActors); + static unsigned int SearchActorByMonsterID(unsigned int *pTotalActors, int uMonsterID); + static unsigned int SearchActorByGroup(unsigned int *pTotalActors, unsigned int uGroup); + static unsigned int SearchActorByID(unsigned int *pTotalActors, unsigned int a2); + + + void LootActor(); + bool _427102_IsOkToCastSpell(signed int a2); + ABILITY_INDEX special_ability_use_check(int a2); + bool _4273BB_DoesHitOtherActor(Actor *defender, int a3, int a4); + bool ActorHitOrMiss(Player *pPlayer); + int CalcMagicalDamageToActor(DAMAGE_TYPE dmgType, signed int incomingDmg); + bool DoesDmgTypeDoDamage(DAMAGE_TYPE uType); + + char pActorName[32]; + signed __int16 sNPC_ID; + __int16 field_22; + unsigned int uAttributes; + __int16 sCurrentHP; + char field_2A[2]; + struct MonsterInfo pMonsterInfo; + __int16 word_000084_range_attack; + __int16 word_000086_some_monster_id; + unsigned __int16 uActorRadius; + unsigned __int16 uActorHeight; + unsigned __int16 uMovementSpeed; + struct Vec3_short_ vPosition; + struct Vec3_short_ vVelocity; + unsigned __int16 uYawAngle; + unsigned __int16 uPitchAngle; + __int16 uSectorID; + unsigned __int16 uCurrentActionLength; + struct Vec3_short_ vInitialPosition; + struct Vec3_short_ vGuardingPosition; + unsigned __int16 uTetherDistance; + AIState uAIState; + unsigned __int16 uCurrentActionAnimation; + unsigned __int16 uCarriedItemID; + char field_B6; + char field_B7; + unsigned int uCurrentActionTime; + unsigned __int16 pSpriteIDs[8]; + unsigned __int16 pSoundSampleIDs[4]; // 1 die 3 bored + struct SpellBuff pActorBuffs[22]; + struct ItemGen ActorHasItems[4]; + unsigned int uGroup; + unsigned int uAlly; + struct ActorJob pScheduledJobs[8]; + unsigned int uSummonerID; + unsigned int uLastCharacterIDToHit; + int dword_000334_unique_name; + char field_338[12]; +}; +#pragma pack(pop) + + + + + + +//extern Actor pMonsterInfoUI_Doll; + +extern std::array<Actor, 500> pActors; +extern size_t uNumActors; + +bool CheckActors_proximity(); +int __fastcall IsActorAlive(unsigned int uType, unsigned int uParam, unsigned int uNumAlive); // idb +void __fastcall sub_448518_npc_set_item(int npc, unsigned int item, int a3); +void __fastcall ToggleActorGroupFlag(unsigned int uGroupID, unsigned int uFlag, unsigned int bToggle); +bool __fastcall sub_4070EF_prolly_detect_player(unsigned int uObjID, unsigned int uObj2ID); +bool __fastcall SpawnActor(unsigned int uMonsterID); +int __fastcall sub_44FA4C_spawn_light_elemental(int a1, int a2, int a3); +void SpawnEncounter(struct MapInfo *pMapInfo, struct SpawnPointMM7 *spawn, int a3, int a4, int a5); +void area_of_effect__damage_evaluate(); +double __fastcall sub_43AE12(signed int a1); +void ItemDamageFromActor(unsigned int uObjID, unsigned int uActorID, struct Vec3_int_ *pVelocity);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Chest.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,806 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include <stdio.h> + +#include "ErrorHandling.h" + +#include "Items.h" +#include "Chest.h" +#include "FrameTableInc.h" +#include "LOD.h" +#include "MapInfo.h" +#include "Actor.h" +#include "Engine/Graphics/Outdoor.h" +#include "Engine/Graphics/DecorationList.h" +#include "Party.h" +#include "AudioPlayer.h" +#include "OurMath.h" +#include "Texts.h" +#include "ObjectList.h" +#include "GUIWindow.h" +#include "Timer.h" + +#include "MM7.h" +#include "SpriteObject.h" +#include "Mouse.h" +#include "Engine/Graphics/Viewport.h" +#include "Engine/Graphics/Level/Decoration.h" + +size_t uNumChests; // idb +struct ChestList *pChestList; +std::array<Chest, 20> pChests; + + +const int pChestPixelOffsetX[8] = {42, 18, 18, 42, 42, 42, 18, 42}; +const int pChestPixelOffsetY[8] = {34, 30, 30, 34, 34, 34, 30, 34}; +const int pChestWidthsByType[8] = {9, 9, 9, 9, 9, 9, 9, 9}; +const int pChestHeightsByType[8] = {9, 9, 9, 9, 9, 9, 9, 9}; + + +//----- (0042041E) -------------------------------------------------------- +bool Chest::Open( signed int uChestID ) +{ + unsigned int pMapID; // eax@8 + int pRandom; // edx@16 + int v6; // eax@16 + ODMFace *pODMFace; // eax@19 + BLVFace *pBLVFace; // eax@20 + int pObjectX; // ebx@21 + int pObjectZ; // edi@21 + double dir_x; // st7@23 + double dir_y; // st6@23 + double length_vector; // st7@23 + int pDepth; // ecx@26 + Vec3_int_ v; // ST4C_12@28 + bool flag_shout; // edi@28 + int pSpriteID[4]; // [sp+84h] [bp-40h]@16 + Vec3_int_ pOut; // [sp+A0h] [bp-24h]@28 + int pObjectY; // [sp+B0h] [bp-14h]@21 + int sRotX; // [sp+B4h] [bp-10h]@23 + float dir_z; // [sp+BCh] [bp-8h]@23 + int sRotY; // [sp+C0h] [bp-4h]@8 + SpriteObject pSpellObject; // [sp+14h] [bp-B0h]@28 + + assert( uChestID < 20 ); + if ( ( uChestID < 0 ) && ( uChestID >= 20 ) ) + return false; + Chest* chest = &pChests[uChestID]; + + ++pIcons_LOD->uTexturePacksCount; + if (!pIcons_LOD->uNumPrevLoadedFiles) + pIcons_LOD->uNumPrevLoadedFiles = pIcons_LOD->uNumLoadedFiles; + + if (!chest->Initialized()) + Chest::PlaceItems(uChestID); + + if ( !uActiveCharacter ) + return false; + flag_shout = false; + pMapID = pMapStats->GetMapInfo(pCurrentMapName); + if ( chest->Trapped() && pMapID ) + { + if ( pPlayers[uActiveCharacter]->GetDisarmTrap() < 2 * pMapStats->pInfos[pMapID].LockX5 ) + { + pSpriteID[0] = 811; + pSpriteID[1] = 812; + pSpriteID[2] = 813; + pSpriteID[3] = 814; + pRandom = rand() % 4; + v6 = PID_ID(EvtTargetObj); + if ( PID_TYPE(EvtTargetObj) == OBJECT_Decoration) + { + pObjectX = pLevelDecorations[v6].vPosition.x; + pObjectY = pLevelDecorations[v6].vPosition.y; + pObjectZ = pLevelDecorations[v6].vPosition.z + ( pDecorationList->pDecorations[pLevelDecorations[v6].uDecorationDescID].uDecorationHeight / 2 ); + } + if ( PID_TYPE(EvtTargetObj) == OBJECT_BModel) + { + if ( uCurrentlyLoadedLevelType == LEVEL_Outdoor) + { + pODMFace = &pOutdoor->pBModels[EvtTargetObj >> 9].pFaces[(EvtTargetObj >> 3) & 0x3F]; + pObjectX = ( pODMFace->pBoundingBox.x1 + pODMFace->pBoundingBox.x2 ) / 2; + pObjectY = ( pODMFace->pBoundingBox.y1 + pODMFace->pBoundingBox.y2 ) / 2; + pObjectZ = ( pODMFace->pBoundingBox.z1 + pODMFace->pBoundingBox.z2 ) / 2; + } + else//Indoor + { + pBLVFace = &pIndoor->pFaces[v6]; + pObjectX = ( pBLVFace->pBounding.x1 + pBLVFace->pBounding.x2 ) / 2; + pObjectY = ( pBLVFace->pBounding.y1 + pBLVFace->pBounding.y2 ) / 2; + pObjectZ = ( pBLVFace->pBounding.z1 + pBLVFace->pBounding.z2 ) / 2; + } + } + dir_x = (double)pParty->vPosition.x - (double)pObjectX; + dir_y = (double)pParty->vPosition.y - (double)pObjectY; + dir_z = ( (double)pParty->sEyelevel + (double)pParty->vPosition.z ) - (double)pObjectZ; + length_vector = sqrt( (dir_x * dir_x) + (dir_y * dir_y) + (dir_z * dir_z) ); + if ( length_vector <= 1.0 ) + { + *(float *)&sRotX = 0.0; + *(float *)&sRotY = 0.0; + } + else + { + sRotY = (signed __int64)sqrt(dir_x * dir_x + dir_y * dir_y); + sRotX = stru_5C6E00->Atan2((signed __int64)dir_x, (signed __int64)dir_y); + sRotY = stru_5C6E00->Atan2(dir_y * dir_y, (signed __int64)dir_z); + } + pDepth = 256; + if ( length_vector < 256.0 ) + pDepth = (signed __int64)length_vector / 4; + v.x = pObjectX; + v.y = pObjectY; + v.z = pObjectZ; + Vec3_int_::Rotate(pDepth, sRotX, sRotY, v, &pOut.x, &pOut.z, &pOut.y); + SpriteObject::sub_42F7EB_DropItemAt(pSpriteID[pRandom], pOut.x, pOut.z, pOut.y, 0, 1, 0, 48, 0); + + pSpellObject.stru_24.Reset(); + pSpellObject.spell_skill = 0; + pSpellObject.spell_level = 0; + pSpellObject.spell_id = 0; + pSpellObject.field_54 = 0; + pSpellObject.uType = pSpriteID[pRandom]; + pSpellObject.uObjectDescID = 0; + if ( pObjectList->uNumObjects ) + { + for ( uint i = 0; i < (signed int)pObjectList->uNumObjects; ++i ) + { + if ( pSpriteID[pRandom] == pObjectList->pObjects[i].uObjectID ) + pSpellObject.uObjectDescID = i; + } + } + pSpellObject.vPosition.y = pOut.z; + pSpellObject.vPosition.x = pOut.x; + pSpellObject.vPosition.z = pOut.y; + pSpellObject.uSoundID = 0; + pSpellObject.uAttributes = 48; + pSpellObject.uSectorID = pIndoor->GetSector(pOut.x, pOut.z, pOut.y); + pSpellObject.uSpriteFrameID = 0; + pSpellObject.spell_caster_pid = 0; + pSpellObject.spell_target_pid = 0; + pSpellObject.uFacing = 0; + pSpellObject.Create(0, 0, 0, 0); + pAudioPlayer->PlaySound(SOUND_8, 0, 0, -1, 0, 0, 0, 0); + pSpellObject.ExplosionTraps(); + chest->uFlags &= 0xFEu; + if ( uActiveCharacter && !_A750D8_player_speech_timer && !OpenedTelekinesis ) + { + _A750D8_player_speech_timer = 256i64; + PlayerSpeechID = SPEECH_5; + uSpeakingCharacter = uActiveCharacter; + } + pIcons_LOD->RemoveTexturesPackFromTextureList(); + OpenedTelekinesis = false; + return false; + } + chest->uFlags &= 0xFEu; + flag_shout = true; + } + pAudioPlayer->StopChannels(-1, -1); + pAudioPlayer->PlaySound(SOUND_OpenChest, 0, 0, -1, 0, 0, 0, 0); + if ( flag_shout == true ) + { + if ( !OpenedTelekinesis ) + pPlayers[uActiveCharacter]->PlaySound(SPEECH_4, 0); + } + OpenedTelekinesis = false; + pChestWindow = pGUIWindow_CurrentMenu = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_Chest, uChestID, 0); + pBtn_ExitCancel = pChestWindow->CreateButton(471, 445, 169, 35, 1, 0, UIMSG_Escape, 0, 0, pGlobalTXT_LocalizationStrings[79], pIcons_LOD->GetTexture(uExitCancelTextureId), 0);// Exit + pChestWindow->CreateButton( 7, 8, 460, 343, 1, 0, UIMSG_CHEST_ClickItem, 0, 0, "", 0); + pCurrentScreen = SCREEN_CHEST; + pEventTimer->Pause(); + return true; +} + +//----- (0042038D) -------------------------------------------------------- +void Chest::ChestUI_WritePointedObjectStatusString() +{ + int v1; // ecx@2 + POINT cursor; // [sp+8h] [bp-8h]@1 + + pMouse->GetCursorPos(&cursor); + if ( cursor.y < 350 ) + { + v1 = pRenderer->pActiveZBuffer[cursor.x + pSRZBufferLineOffsets[cursor.y]]; + if ( v1 != 0 && v1 != -65536 ) + { + if ( v1 ) + { + ItemGen* item = &pChests[pChestWindow->par1C].igChestItems[pChests[pChestWindow->par1C].pInventoryIndices[(v1 & 0xFFFF) - 1] - 1]; + GameUI_SetFooterString(item->GetDisplayName()); + } + } + } +} + +//----- (0042092D) -------------------------------------------------------- +void Chest::DrawChestUI(signed int uChestID) + { + + int chestBitmapId; // eax@1 + unsigned int v5; // eax@1 + int chest_item_index; // ecx@3 + unsigned int item_texture_id; // eax@4 + Texture *item_texture; // esi@4 + signed int itemPixelWidth; // ecx@4 + signed int itemPixelHeght; // edx@4 +// signed int v11; // eax@4 + int v12; // eax@6 + int v13; // eax@6 + unsigned int itemPixelPosX; // ST34_4@8 + int itemPixelPosY; // edi@8 + int *v16; // [sp+Ch] [bp-28h]@1 +// int v17; // [sp+10h] [bp-24h]@4 + int chest_offs_y; // [sp+14h] [bp-20h]@1 + signed int chestHeghtCells; // [sp+18h] [bp-1Ch]@1 + int chest_offs_x; // [sp+1Ch] [bp-18h]@1 + signed int chestWidthCells; // [sp+20h] [bp-14h]@1 + signed int item_counter; // [sp+30h] [bp-4h]@1 + + v16 = pRenderer->pActiveZBuffer; + pRenderer->ClearZBuffer(0, 479); + chestBitmapId = pChests[uChestID].uChestBitmapID; + chest_offs_x = pChestPixelOffsetX[chestBitmapId]; + chest_offs_y = pChestPixelOffsetY[chestBitmapId]; + chestWidthCells = pChestWidthsByType[chestBitmapId]; + chestHeghtCells = pChestHeightsByType[chestBitmapId]; + sprintfex(pTmpBuf.data(), "chest%02d", pChestList->pChests[chestBitmapId].uTextureID); + v5 = pIcons_LOD->LoadTexture(pTmpBuf.data(), TEXTURE_16BIT_PALETTE); + pRenderer->DrawTextureIndexed(8u, 8u, pIcons_LOD->GetTexture(v5)); + + for (item_counter = 0; item_counter < chestWidthCells * chestHeghtCells; ++item_counter) + { + chest_item_index = pChests[uChestID].pInventoryIndices[item_counter]; + if ( chest_item_index > 0 ) + { + item_texture_id = pIcons_LOD->LoadTexture( + //pItemsTable->pItems[*(int *)((char *)&pOtherOverlayList->pOverlays[49].field_4 + 36 * v6 + v3 * 5324)].pIconName, + pChests[uChestID].igChestItems[chest_item_index - 1].GetIconName(), TEXTURE_16BIT_PALETTE); + item_texture = pIcons_LOD->GetTexture(item_texture_id); + itemPixelWidth = item_texture->uTextureWidth; + itemPixelHeght = item_texture->uTextureHeight; + if ( itemPixelWidth < 14 ) + itemPixelWidth = 14; + v12 = itemPixelWidth - 14; + v12 = v12 & 0xFFFFFFE0; + v13 = v12 + 32; + if ( itemPixelHeght < 14 ) + itemPixelHeght = 14; + itemPixelPosX = chest_offs_x + 32 * (item_counter % chestWidthCells) + ((signed int)(v13 - itemPixelWidth)/2); + itemPixelPosY = chest_offs_y + 32 * (item_counter / chestHeghtCells) + + ((signed int)(((itemPixelHeght - 14) & 0xFFFFFFE0) + 32- item_texture->uTextureHeight ) /2); + pRenderer->DrawTextureTransparent( itemPixelPosX, itemPixelPosY, item_texture); + ZBuffer_DoFill2(&v16[itemPixelPosX + pSRZBufferLineOffsets[itemPixelPosY]], item_texture, item_counter + 1); + } + } + pRenderer->DrawTextureIndexed(pBtn_ExitCancel->uX, pBtn_ExitCancel->uY, pIcons_LOD->GetTexture(uExitCancelTextureId)); + } + + +//----- (0041FE71) -------------------------------------------------------- +bool Chest::CanPlaceItemAt( signed int test_cell_position, int item_id, signed int uChestID ) + { +// int v3; // eax@1 + unsigned int item_texture_id; // eax@1 + Texture *item_texture; // ecx@1 + signed int v6; // eax@1 +// signed int v7; // edi@3 + signed int v8; // eax@3 + int texture_cell_width; // edi@3 + int texture_cell_height; // ebx@5 + int _row; // esi@9 + int _cell_rows; // edx@10 + int _column; // ecx@11 +// char *v14; // eax@12 + int chest_cell_heght; // [sp+Ch] [bp-Ch]@1 +// signed int v17; // [sp+10h] [bp-8h]@1 + signed int chest_cell_width; // [sp+14h] [bp-4h]@1 + + chest_cell_heght = pChestHeightsByType[pChests[uChestID].uChestBitmapID]; + chest_cell_width = pChestWidthsByType[pChests[uChestID].uChestBitmapID]; + item_texture_id = pIcons_LOD->LoadTexture(pItemsTable->pItems[item_id].pIconName, TEXTURE_16BIT_PALETTE); + item_texture = pIcons_LOD->GetTexture(item_texture_id); + v6 = item_texture->uTextureWidth; + if ( v6 < 14 ) + v6 = 14; + texture_cell_width = ((v6 - 14) >> 5) + 1; + v8 = item_texture->uTextureHeight; + if ( v8 < 14 ) + v8 = 14; + texture_cell_height = ((v8 - 14) >> 5) + 1; + if ( !areWeLoadingTexture ) + { + item_texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + if ( (texture_cell_width + test_cell_position % chest_cell_width <= chest_cell_width) && + (texture_cell_height + test_cell_position / chest_cell_width <= chest_cell_heght) ) + { //we not put over borders + _row = 0; + if ( texture_cell_height <= 0 ) + return true; + _cell_rows = 0; + while ( 1 ) + { + _column = 0; + if ( texture_cell_width > 0 ) + { + while ( pChests[uChestID].pInventoryIndices[test_cell_position + _cell_rows+_column]==0) + { + ++_column; + if ( _column >= texture_cell_width ) + break; + } + if (pChests[uChestID].pInventoryIndices[test_cell_position + _cell_rows+_column]!=0) + return false; + } + _cell_rows += chest_cell_width; + ++_row; + if ( _row >= texture_cell_height ) + return true; + } + + } + return false; + } +// 506128: using guessed type int areWeLoadingTexture; + +//----- (0041FF64) -------------------------------------------------------- +int Chest::CountChestItems(signed int uChestID) +{ + signed int item_count; // eax@1 + int max_items; // edx@1 + item_count = 0; + max_items = pChestWidthsByType[pChests[uChestID].uChestBitmapID] * pChestHeightsByType[pChests[uChestID].uChestBitmapID]; + if ( max_items <= 0 ) + item_count = -1; + else + { + while ( pChests[uChestID].igChestItems[item_count].uItemID ) + { + ++item_count; + if ( item_count >= max_items ) + { + item_count = -1; + break; + } + } + } + return item_count; +} + +//----- (0041FFA2) -------------------------------------------------------- +int Chest::PutItemInChest(int position, ItemGen *put_item, signed int uChestID) +{//(rus: ïîëîæèòü ïðåäìåò â ÿùèê) + ItemGen *v4; // edi@1 + int v5; // esi@1 + int result; // eax@11 + unsigned int v7; // eax@12 + int v8; // edx@12 + Texture *texture; // ecx@12 + signed int v10; // eax@12 + signed int v11; // edi@14 + unsigned int v12; // esi@14 + int v13; // edi@16 + void *v14; // edi@21 + int v15; // edi@21 + int i; // ecx@21 + ItemGen *Src; // [sp+Ch] [bp-18h]@1 + signed int item_in_chest_count; // [sp+10h] [bp-14h]@2 + int v19; // [sp+14h] [bp-10h]@1 + int v20; // [sp+18h] [bp-Ch]@19 + signed int v21; // [sp+1Ch] [bp-8h]@1 +// signed int v22; // [sp+20h] [bp-4h]@3 + int v23; // [sp+20h] [bp-4h]@19 + + v21 = 0; + v4 = put_item; + v5 = pChestWidthsByType[pChests[uChestID].uChestBitmapID] * pChestHeightsByType[pChests[uChestID].uChestBitmapID]; + Src = put_item; + v19 = pChestWidthsByType[pChests[uChestID].uChestBitmapID]; + if ( position == -1 ) + { + item_in_chest_count = CountChestItems(uChestID); + if ( item_in_chest_count == -1 ) + return 0; + for( int _i = 0; _i < v5; _i++) + { + if ( Chest::CanPlaceItemAt(_i, v4->uItemID, pChestWindow->par1C) ) + v21 = _i; + } + if ( v21 == v5 ) + { + if ( uActiveCharacter ) + pPlayers[uActiveCharacter]->PlaySound(SPEECH_NoRoom, 0); + return 0; + } + v7 = pIcons_LOD->LoadTexture(v4->GetIconName(), TEXTURE_16BIT_PALETTE); + HIWORD(v8) = 0; + texture = pIcons_LOD->GetTexture(v7); + v10 = texture->uTextureWidth; + if ( texture->uTextureWidth < 14 ) + v10 = 14; + v12 = ((v10 - 14) >> 5) + 1; + v11 = texture->uTextureHeight; + if ( texture->uTextureHeight < 14 ) + v11 = 14; + v13 = ((v11 - 14) >> 5) + 1; + if ( !areWeLoadingTexture ) + { + texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + if ( v13 > 0 ) + { + v23 = 0; + v20 = v13; + do + { + if ( (signed int)v12 > 0 ) + { + v14 = &pChests[uChestID].pInventoryIndices[v21 + v23]; + LOWORD(v8) = -1 - v21; + v8 <<= 16; + LOWORD(v8) = -1 - v21; + memset32(v14, v8, v12 >> 1); + v15 = (int)((char *)v14 + 4 * (v12 >> 1)); + for ( i = v12 & 1; i; --i ) + { + *(short *)v15 = v8; + v15 += 2; + } + } + v23 += v19; + --v20; + } + while ( v20 ); + } + pChests[uChestID].pInventoryIndices[v21] = item_in_chest_count + 1; + memcpy(&pChests[uChestID].igChestItems[item_in_chest_count], put_item, sizeof(ItemGen)); + result = v21 + 1; + } + else + result = 1; + return result; +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (0042013E) -------------------------------------------------------- +void Chest::PlaceItemAt( unsigned int put_cell_pos, unsigned int item_at_cell, signed int uChestID ) +{ + int uItemID; // edi@1 + int v6; // edx@4 + unsigned int v7; // eax@5 + Texture *texture; // ecx@5 + signed int v9; // eax@5 + signed int v10; // edi@7 + unsigned int texture_cell_width; // ebx@7 + int textute_cell_height; // edi@9 + int chest_cell_row_pos; // edx@12 + int chest_cell_width; // [sp+10h] [bp-Ch]@11 + + uItemID = pChests[ uChestID].igChestItems[item_at_cell].uItemID; + pItemsTable->SetSpecialBonus(&pChests[ uChestID].igChestItems[item_at_cell]); + if ( uItemID >= 135 && uItemID <= 159 && !pChests[ uChestID].igChestItems[item_at_cell].uNumCharges) + { + v6 = rand() % 21 + 10; + pChests[ uChestID].igChestItems[item_at_cell].uNumCharges = v6; + pChests[ uChestID].igChestItems[item_at_cell].uMaxCharges = v6; + } + v7 = pIcons_LOD->LoadTexture(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE); + texture = pIcons_LOD->GetTexture(v7); + v9 = texture->uTextureWidth; + if ( texture->uTextureWidth < 14 ) + v9 = 14; + texture_cell_width = ((v9 - 14) >> 5) + 1; + v10 = texture->uTextureHeight; + if ( texture->uTextureHeight < 14 ) + v10 = 14; + textute_cell_height = ((v10 - 14) >> 5) + 1; + if ( !areWeLoadingTexture ) + { + texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + chest_cell_width = pChestWidthsByType[pChests[ uChestID].uChestBitmapID]; + chest_cell_row_pos = 0; + for(int i = 0; i < textute_cell_height; ++i) + { + for (int j = 0; j < texture_cell_width; ++j) + pChests[uChestID].pInventoryIndices[put_cell_pos + chest_cell_row_pos+j]=(signed __int16)-(put_cell_pos+1); + chest_cell_row_pos += chest_cell_width; + } + pChests[uChestID].pInventoryIndices[put_cell_pos] = item_at_cell + 1; +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (00420284) -------------------------------------------------------- +void Chest::PlaceItems(signed int uChestID ) + { + int uChestArea; // edi@1 + int random_chest_pos; // eax@2 + int test_position; // ebx@11 + char chest_cells_map[144]; // [sp+Ch] [bp-A0h]@1 + int chest_item_id; // [sp+9Ch] [bp-10h]@10 + unsigned int items_counter; // [sp+A4h] [bp-8h]@8 + + pRenderer->ClearZBuffer(0, 479); + uChestArea = pChestWidthsByType[pChests[uChestID].uChestBitmapID] * pChestHeightsByType[pChests[uChestID].uChestBitmapID]; + memset(chest_cells_map, 0, 144); + //fill cell map at random positions + for ( items_counter = 0; items_counter < uChestArea; ++items_counter ) + { + //get random position in chest + do + random_chest_pos = (unsigned __int8)rand(); + while ( random_chest_pos >= uChestArea ); + //if this pos occupied move to next + while ( chest_cells_map[random_chest_pos] ) + { + ++random_chest_pos; + if ( random_chest_pos == uChestArea ) + random_chest_pos = 0; + } + chest_cells_map[random_chest_pos] = items_counter; + } + items_counter = 0; + + for (items_counter = 0; items_counter<uChestArea; ++items_counter) + { + chest_item_id = pChests[uChestID].igChestItems[items_counter].uItemID; + if ( chest_item_id ) + { + test_position = 0; + while ( !Chest::CanPlaceItemAt((unsigned __int8)chest_cells_map[test_position], chest_item_id, uChestID) ) + { + ++test_position; + if ( test_position >= uChestArea ) + break; + } + if(test_position<uChestArea) + { + Chest::PlaceItemAt((unsigned __int8)chest_cells_map[test_position], items_counter, uChestID); + if ( pChests[uChestID].uFlags & CHEST_OPENED) + pChests[uChestID].igChestItems[items_counter].SetIdentified(); + } + } + } + pChests[uChestID].SetInitialized(true); + } +// 420284: using guessed type char Dst[144]; + +//----- (00448A17) -------------------------------------------------------- +void Chest::ToggleFlag(signed int uChestID, unsigned __int16 uFlag, unsigned int bToggle) +{ + if ( uChestID >= 0 && uChestID <= 19 ) + { + if ( bToggle ) + pChests[uChestID].uFlags |= uFlag; + else + pChests[uChestID].uFlags &= ~uFlag; + } +} + +//----- (00458B03) -------------------------------------------------------- +void ChestList::ToFile() +{ + FILE *v2; // eax@1 + FILE *v3; // edi@1 + + v2 = fopen("data\\dchest.bin", "wb"); + v3 = v2; + if ( !v2 ) + Error("Unable to save dchest.bin!"); + + fwrite(this, 4, 1, v2); + fwrite(this->pChests, 36, this->uNumChests, v3); + fclose(v3); +} + + +//----- (00458B4F) -------------------------------------------------------- +void ChestList::FromFile(void *data_mm6, void *data_mm7, void *data_mm8) +{ + uint num_mm6_chests = data_mm6 ? *(int *)data_mm6 : 0, + num_mm7_chests = data_mm7 ? *(int *)data_mm7 : 0, + num_mm8_chests = data_mm8 ? *(int *)data_mm8 : 0; + + uNumChests = num_mm6_chests + num_mm7_chests + num_mm8_chests; + assert(uNumChests); + assert(!num_mm8_chests); + + pChests = (ChestDesc *)malloc(uNumChests * sizeof(ChestDesc)); + memcpy(pChests, (char *)data_mm7 + 4, num_mm7_chests * sizeof(ChestDesc)); + memcpy(pChests + num_mm7_chests, (char *)data_mm6 + 4, num_mm6_chests * sizeof(ChestDesc)); + memcpy(pChests + num_mm6_chests + num_mm7_chests, (char *)data_mm8 + 4, num_mm8_chests * sizeof(ChestDesc)); +} + + +//----- (00458B9C) -------------------------------------------------------- +int ChestList::FromFileTxt(const char *Args) +{ + //ChestList *v2; // ebx@1 + __int32 v3; // edi@1 + FILE *v4; // eax@1 + unsigned int v5; // esi@3 + const void *v6; // ST18_4@9 + void *v7; // eax@9 + FILE *v8; // ST0C_4@11 + char *i; // eax@11 + char v10; // al@14 + const char *v11; // ST14_4@14 + char v12; // al@14 + const char *v13; // ST10_4@14 + char Buf; // [sp+8h] [bp-2F0h]@3 + FrameTableTxtLine v16; // [sp+1FCh] [bp-FCh]@4 + FrameTableTxtLine v17; // [sp+278h] [bp-80h]@4 + FILE *File; // [sp+2F4h] [bp-4h]@1 + unsigned int Argsa; // [sp+300h] [bp+8h]@3 + + //v2 = this; + free(this->pChests); + v3 = 0; + this->pChests = 0; + this->uNumChests = 0; + v4 = fopen(Args, "r"); + File = v4; + if ( !v4 ) + Error("ChestDescriptionList::load - Unable to open file: %s."); + + v5 = 0; + Argsa = 0; + if ( fgets(&Buf, 490, v4) ) + { + do + { + *strchr(&Buf, 10) = 0; + memcpy(&v17, txt_file_frametable_parser(&Buf, &v16), sizeof(v17)); + if ( v17.uPropCount && *v17.pProperties[0] != 47 ) + ++Argsa; + } + while ( fgets(&Buf, 490, File) ); + v5 = Argsa; + v3 = 0; + } + v6 = this->pChests; + this->uNumChests = v5; + v7 = malloc(36 * v5); + this->pChests = (ChestDesc *)v7; + if ( v7 == (void *)v3 ) + Error("ChestDescriptionList::load - Out of Memory!"); + + memset(v7, v3, 36 * this->uNumChests); + v8 = File; + this->uNumChests = v3; + fseek(v8, v3, v3); + for ( i = fgets(&Buf, 490, File); i; i = fgets(&Buf, 490, File) ) + { + *strchr(&Buf, 10) = 0; + memcpy(&v17, txt_file_frametable_parser(&Buf, &v16), sizeof(v17)); + if ( v17.uPropCount && *v17.pProperties[0] != 47 ) + { + strcpy(this->pChests[this->uNumChests].pName, v17.pProperties[0]); + v10 = atoi(v17.pProperties[1]); + v11 = v17.pProperties[2]; + this->pChests[this->uNumChests].uWidth = v10; + v12 = atoi(v11); + v13 = v17.pProperties[3]; + this->pChests[this->uNumChests].uHeight = v12; + this->pChests[this->uNumChests++].uTextureID = atoi(v13); + } + } + fclose(File); + return 1; +} + +//----- (00420B13) -------------------------------------------------------- +void __fastcall sub_420B13(int a1, int a2) +{ //Give item from chest(rus: Âçÿòü ïðåäìåò èç ÿùèêà) + void *v2; // eax@1 + unsigned int v4; // eax@1 + Texture *texture; // ecx@1 + signed int v6; // eax@1 + signed int v7; // edi@3 + signed int v8; // eax@3 + int v9; // edi@3 + int v10; // eax@5 + int v11; // esi@8 + unsigned int v12; // ecx@10 + void *v13; // edi@10 + unsigned __int8 v14; // cf@10 + int v15; // edi@10 + int i; // ecx@10 + int v17; // [sp+Ch] [bp-14h]@1 + int v18; // [sp+10h] [bp-10h]@3 + int v21; // [sp+1Ch] [bp-4h]@5 + int v22; // [sp+1Ch] [bp-4h]@8 + + v2 = (void *)(5324 * (int)pChestWindow->ptr_1C); + v17 = pChestWidthsByType[pChests[(int)pChestWindow->ptr_1C].uChestBitmapID]; + v4 = pIcons_LOD->LoadTexture(pChests[(int)pChestWindow->ptr_1C].igChestItems[a1].GetIconName(), TEXTURE_16BIT_PALETTE); + texture = pIcons_LOD->GetTexture(v4); + + v6 = texture->uTextureWidth; + if ( texture->uTextureWidth < 14 ) + v6 = 14; + v7 = v6 - 14; + v9 = (v7 >> 5) + 1; + v18 = v9; + + v8 = texture->uTextureHeight; + if ( texture->uTextureHeight < 14 ) + v8 = 14; + v10 = ((v8 - 14) >> 5) + 1; + v21 = v10; + + if ( !areWeLoadingTexture ) + { + texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + v10 = v21; + } + if ( v10 > 0 ) + { + v11 = 0; + for ( v22 = v10; v22; --v22 ) + { + if ( v9 > 0 ) + { + v12 = v9; + v13 = &pChests[(int)pChestWindow->ptr_1C].pInventoryIndices[a2 + v11]; + v14 = v12 & 1; + v12 >>= 1; + memset(&pChests[(int)pChestWindow->ptr_1C].pInventoryIndices[a2 + v11], 0, 4 * v12); + v15 = (int)((char *)v13 + 4 * v12); + for ( i = v14; i; --i ) + { + *(short *)v15 = 0; + v15 += 2; + } + v9 = v18; + } + v11 += v17; + } + } + pChests[(int)pChestWindow->ptr_1C].igChestItems[a1].Reset(); +} +// 506128: using guessed type int areWeLoadingTexture; +//----- (00420E01) -------------------------------------------------------- +void Chest::OnChestLeftClick() +{ + int v2; // eax@2 + int v3; // ebx@4 + int v4; // esi@6 + POINT cursor; // [sp+84h] [bp-8h]@2 + + SpriteObject v6; // [sp+Ch] [bp-80h]@1 + if ( pParty->pPickedItem.uItemID ) + { + if ( Chest::PutItemInChest(-1, &pParty->pPickedItem, pGUIWindow_CurrentMenu->par1C) ) + pMouse->RemoveHoldingItem(); + } + else + { + pMouse->GetCursorPos(&cursor); + v2 = pRenderer->pActiveZBuffer[cursor.x + pSRZBufferLineOffsets[cursor.y]] & 0xFFFF; + if ( v2 ) + { + if ( v2 ) + v3 = v2 - 1; + else + v3 = -1; + v4 = pChests[(int)pGUIWindow_CurrentMenu->par1C].pInventoryIndices[v3] - 1; + if ( pChests[(int)pGUIWindow_CurrentMenu->par1C].igChestItems[v4].GetItemEquipType() == EQUIP_GOLD ) + { + pParty->PartyFindsGold(pChests[(int)pGUIWindow_CurrentMenu->par1C].igChestItems[v4].uSpecEnchantmentType, 0); + viewparams->bRedrawGameUI = 1; + } + else + pParty->SetHoldingItem(&pChests[(int)pGUIWindow_CurrentMenu->par1C].igChestItems[v4]); + sub_420B13(v4, v3); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Chest.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,78 @@ +#pragma once + + + + +/* 348 */ +enum CHEST_FLAGS +{ + CHEST_TRAPPED = 0x1, + CHEST_ITEMS_PLACED = 0x2, + CHEST_OPENED = 0x4, +}; + + + +#pragma pack(push, 1) +struct ChestDesc +{ + char pName[32]; + char uWidth; + char uHeight; + __int16 uTextureID; +}; +#pragma pack(pop) + + + +#pragma pack(push, 1) +struct ChestList +{ + inline ChestList(): //----- (00458438) + uNumChests(0), pChests(nullptr) + {} + + void ToFile(); + void FromFile(void *data_mm6, void *data_mm7, void *data_mm8); + int FromFileTxt(const char *Args); + + + unsigned int uNumChests; + struct ChestDesc *pChests; +}; +#pragma pack(pop) + + + +/* 65 */ +#pragma pack(push, 1) +struct Chest //0x14cc +{ + inline bool Initialized() const {return (uFlags & CHEST_ITEMS_PLACED) != 0;} + inline void SetInitialized(bool b) {if (b) uFlags |= CHEST_ITEMS_PLACED; else uFlags &= ~CHEST_ITEMS_PLACED;} + inline bool Trapped() const {return (uFlags & CHEST_TRAPPED) != 0;} + + static bool CanPlaceItemAt(signed int a1, int a2, signed int uChestID); + static int CountChestItems(signed int uChestID); + static int PutItemInChest(int a1, ItemGen *a2, signed int uChestID); + static void PlaceItemAt(unsigned int put_cell_pos, unsigned int uItemIdx, signed int uChestID); + static void PlaceItems(signed int uChestID); + static bool Open(signed int uChestID); + static void DrawChestUI(signed int uChestID); + static void ToggleFlag(signed int uChestID, unsigned __int16 uFlag, unsigned int bToggle); + static void ChestUI_WritePointedObjectStatusString(); + static void OnChestLeftClick(); + + unsigned __int16 uChestBitmapID; //0 + unsigned __int16 uFlags; //2 + struct ItemGen igChestItems[140]; //4 + signed __int16 pInventoryIndices[140]; //0x13b4 +}; +#pragma pack(pop) + +void __fastcall sub_420B13(int a1, int a2); + + +extern size_t uNumChests; // idb +extern struct ChestList *pChestList; +extern std::array<Chest, 20> pChests; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/NPC.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,1762 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include "texts.h" +#include "LOD.h" +#include "Autonotes.h" +#include "Awards.h" +#include "Party.h" +#include "NPC.h" +#include "GUIWindow.h" +#include "Events.h" +#include "UI\UIHouses.h" +#include "Engine/Graphics/Indoor.h" +#include "MapInfo.h" +#include "Actor.h" +#include "AudioPlayer.h" +#include "CastSpellInfo.h" +#include "Engine/Graphics/Overlays.h" + +int pDialogueNPCCount; +std::array<struct Texture *, 6> pDialogueNPCPortraits; +int uNumDialogueNPCPortraits; // weak +struct NPCStats *pNPCStats = nullptr; + +int NPCStats::dword_AE336C_LastMispronouncedNameFirstLetter = -1; +int NPCStats::dword_AE3370_LastMispronouncedNameResult = -1; + +void InitializeAwards(); +void InitializeScrolls(); +void InitializeMerchants(); +void InitializeTransitions(); +void InitializeAutonotes(); +void InitializeQuests(); +bool CheckPortretAgainstSex(int portret_num, int sex); + +//----- (004459F9) -------------------------------------------------------- +NPCData *__fastcall GetNPCData(signed int npcid) +{ + unsigned int v1; // esi@1 + NPCData *result; // eax@5 + int v3; // esi@9 + int v4; // ecx@9 + //int v5; // edx@9 + //NPCData *v6; // eax@9 +// char *v7; // ebx@14 +// NPCData *v8; // edi@14 + char v9; // al@22 +// char v10; + //std::string v10; // [sp-18h] [bp-2Ch]@4 +// int v11; + //const char *v11; // [sp-8h] [bp-1Ch]@4 +// int v12; // [sp-4h] [bp-18h]@4 +// int v13; +// char *v14; + //std::string *v13; // [sp+Ch] [bp-8h]@4 +// int a3; // [sp+13h] [bp-1h]@4 + int i; + + /*v1 = npcid; + if ( (npcid & 0x80000000u) == 0 ) + { + if ( (signed int)npcid < 5000 ) + { + if ( (signed int)npcid >= 501 ) + { + MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0); + } + return &pNPCStats->pNewNPCData[v1]; + } + return &pNPCStats->array_13EF4[npcid - 5000]; + } + if ( (signed int)npcid >= 5000 ) + return &pNPCStats->array_13EF4[npcid - 5000]; + if ( (sDialogue_SpeakingActorNPC_ID & 0x80000000u) == 0 ) + { + result = 0; + } + else + { + v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1; + v4 = 0; + v5 = 0; + v6 = pParty->pHirelings; + do + { + if ( v6->pName ) + pTmpBuf[v4++] = v5; + ++v6; + ++v5; + } + while ( (signed int)v6 < (signed int)&pParty->pPickedItem ); + v13 = 0; + if ( (signed int)pNPCStats->uNumNewNPCs > 0 ) + { + v7 = &pTmpBuf[v4]; + v8 = pNPCStats->pNewNPCData; + do + { + if ( v8->uFlags & 0x80 + && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) + && (!pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName)) ) + *v7++ = (char)v13 + 2; + v13 = (std::string *)((char *)v13 + 1); + ++v8; + } + while ( (signed int)v13 < (signed int)pNPCStats->uNumNewNPCs ); + } + v9 = pTmpBuf[v3]; + if ( (unsigned __int8)v9 >= 2u ) + result = &pNPCStats->pNPCData[(unsigned __int8)v9 + 499]; + else + result = &pParty->pHirelings[(unsigned __int8)v9]; + } + return result;*/ + v1 = npcid; + if ( npcid >= 0 ) + { + if ( npcid < 5000 ) + { + if ( npcid >= 501 ) + { + MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0); + } + return &pNPCStats->pNewNPCData[v1];// - 1]; + } + return &pNPCStats->pAdditionalNPC[npcid - 5000]; + } + + + if ( npcid >= 5000 ) + return &pNPCStats->pAdditionalNPC[npcid - 5000]; + if (sDialogue_SpeakingActorNPC_ID >= 0) + { + result = 0; + } + else + { + v3 = abs(sDialogue_SpeakingActorNPC_ID) - 1; + v4 = 0; + + for (i = 0; i < 2; ++i) + { + if (pParty->pHirelings[i].pName) + pTmpBuf[v4++] = i; + } + + if (pNPCStats->uNumNewNPCs > 0) + { + for (i = 0; i < pNPCStats->uNumNewNPCs; ++i) + { + if (pNPCStats->pNewNPCData[i].Hired()) + { + if (!pParty->pHirelings[0].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[0].pName)) + { + if (!pParty->pHirelings[1].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[1].pName)) + pTmpBuf[v4++] = i + 2; + } + } + } + } + + v9 = pTmpBuf[v3]; + if ( v9 >= 2 ) + result = &pNPCStats->pNPCData[499 + v9]; + else + result = &pParty->pHirelings[v9]; + } + return result; +} + +//----- (00445B2C) -------------------------------------------------------- +struct NPCData * GetNewNPCData( signed int npcid, int* npc_indx ) + { + + int* v3; // edi@1 + NPCData *result; // eax@5 + int v5; // esi@9 + int v6; // ecx@9 + char v11; // al@23 + + v3 = npc_indx; + if ( npcid >= 0 ) + { + if ( npcid < 5000 ) + { + if ( npcid >= 501 ) + { + MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:2040", 0); + } + *v3 = npcid; + return &pNPCStats->pNewNPCData[npcid]; + } + *npc_indx = npcid - 5000; + return &pNPCStats->pAdditionalNPC[npcid - 5000]; + } + if ( npcid >= 5000 ) + { + *npc_indx = npcid - 5000; + return &pNPCStats->pAdditionalNPC[npcid - 5000]; + } + if ( sDialogue_SpeakingActorNPC_ID >= 0 ) + { + *npc_indx = 0; + result = nullptr; + } + else + { + v5 = abs(sDialogue_SpeakingActorNPC_ID) - 1; + v6 = 0; + for (int i=0; i<2; ++i) + { + if ( pParty->pHirelings[i].pName ) + pTmpBuf[v6++] = i; + + } + for (int i=0; i< pNPCStats->uNumNewNPCs; ++i) + { + if ( pNPCStats->pNewNPCData[i].Hired() + && (!pParty->pHirelings[0].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[0].pName)) + && (!pParty->pHirelings[1].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[1].pName)) ) + { + pTmpBuf[v6++]=i+2; + } + } + v11 = pTmpBuf[v5]; + + if ( v11 >= 2u ) + { + *v3 = v11 - 2; + result = &pNPCStats->pNewNPCData[v11 - 2]; + } + else + { + *v3 = v11; + result = &pParty->pHirelings[v11]; + } + } + return result; +} + +//----- (00476977) -------------------------------------------------------- +void NPCStats::InitializeNPCText() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pNPCTextTXT_Raw); + pNPCTextTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctext.txt", 0); + strtok(pNPCTextTXT_Raw, "\r"); + + for (i=0; i<789; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ( decode_step == 1) + pNPCTopics[i].pText =RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + free(pNPCTopicTXT_Raw); + pNPCTopicTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctopic.txt", 0); + strtok(pNPCTopicTXT_Raw, "\r"); + + for ( i = 1; i <= 579; ++i )//NPC topics count limit + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ( decode_step == 1) + pNPCTopics[i].pTopic = RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + + free(pNPCDistTXT_Raw); + pNPCDistTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdist.txt", 0); + strtok(pNPCDistTXT_Raw, "\r"); + strtok(NULL, "\r"); + + for (i=1; i<59; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ((decode_step>0)&&(decode_step<77)) + { + pProfessionChance[decode_step].professionChancePerArea[i]=atoi(test_string); + } + else if (decode_step==0) + { + pProfessionChance[0].professionChancePerArea[i]=10; + } + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<78)&&!break_loop); + } + + for ( i = 0; i < 77; ++i ) + { + pProfessionChance[i].uTotalprofChance=0; + for ( int ii = 1; ii < 59; ++ii ) + { + pProfessionChance[i].uTotalprofChance+=pProfessionChance[i].professionChancePerArea[ii]; + } + pProfessionChance[i].professionChancePerArea[0]=0; + pProfessionChance[i].professionChancePerArea[59]=0; + } + + free(pNPCDistTXT_Raw); + pNPCDistTXT_Raw = nullptr; + } + +//----- (00476C60) -------------------------------------------------------- +void NPCStats::_476C60() + { + for (unsigned int i = 1; i < uNumNewNPCs; ++i) + pNewNPCData[i].pName = pNPCUnicNames[i - 1]; + + if (pParty->pHirelings[0].pName) + pParty->pHirelings[0].pName = pParty->pHireling1Name; + if (pParty->pHirelings[1].pName) + pParty->pHirelings[1].pName = pParty->pHireling2Name; + } + +//----- (00476CB5) -------------------------------------------------------- +void NPCStats::InitializeNPCData() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + pNPCDataTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdata.txt", 0); + strtok(pNPCDataTXT_Raw, "\r"); + strtok(NULL, "\r"); + + for (i=0; i<500; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { //i+1 + switch (decode_step) + { + case 1: + pNPCUnicNames[i] = RemoveQuotes(test_string); + pNPCData[i+1].pName=pNPCUnicNames[i]; + break; + case 2: + pNPCData[i+1].uPortraitID = atoi(test_string); + break; + case 6: + pNPCData[i+1].Location2D = atoi(test_string); + break; + case 7: + pNPCData[i+1].uProfession = atoi(test_string); + break; + case 8: + pNPCData[i+1].greet = atoi(test_string); + break; + case 9: + pNPCData[i+1].joins = (*test_string == 'y')?1:0; + break; + case 10: + pNPCData[i+1].evt_A = atoi(test_string); + break; + case 11: + pNPCData[i+1].evt_B = atoi(test_string); + break; + case 12: + pNPCData[i+1].evt_C = atoi(test_string); + break; + case 13: + pNPCData[i+1].evt_D = atoi(test_string); + break; + case 14: + pNPCData[i+1].evt_E = atoi(test_string); + break; + case 15: + pNPCData[i+1].evt_F = atoi(test_string); + break; + } + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<16)&&!break_loop); + } + uNumNewNPCs = 501; + pNPCGreetTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgreet.txt", 0); + strtok(pNPCGreetTXT_Raw, "\r"); + for ( i = 1; i <= 205; ++i ) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { //i+1 + switch (decode_step) + { + case 1: + pNPCGreetings[i].pGreetings[0] = RemoveQuotes(test_string); + break; + case 2: + pNPCGreetings[i].pGreetings[1] = RemoveQuotes(test_string); + break; + } + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<3)&&!break_loop); + } + + pNCPGroupTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgroup.txt", 0); + strtok(pNCPGroupTXT_Raw, "\r"); + + for (i=0; i<51; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { //i+1 + if (decode_step==1) + { + pGroups[i] = atoi(test_string); + } + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + + pNPCNewsTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcnews.txt", 0); + strtok(pNPCNewsTXT_Raw, "\r"); + + + for (i=0; i<51; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { //i+1 + if (decode_step==1) + pCatchPhrases[i] = RemoveQuotes(test_string); + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + } + +//----- (0047702F) -------------------------------------------------------- +void NPCStats::Initialize() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + InitializeNPCData(); + InitializeNPCText(); + InitializeQuests(); + InitializeAutonotes(); + InitializeAwards(); + InitializeTransitions(); + InitializeMerchants(); + InitializeScrolls(); + + pNPCNamesTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcnames.txt", 0); + strtok(pNPCNamesTXT_Raw, "\r"); + + uNewlNPCBufPos = 0; + + for (i=0; i<540; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + if (c=='\t') + { + if ( (decode_step == 1)&&(!uNumNPCNames[1])) + uNumNPCNames[1]=i; + } + else + { + while((c!='\n')&&(c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + + if (temp_str_len) + { + *tmp_pos = 0; + if ( decode_step == 0) + pNPCNames[i][0] =RemoveQuotes(test_string); + else if ( decode_step == 1) + pNPCNames[i][1] =RemoveQuotes(test_string); + } + else + { + if ( (decode_step == 1)&&(!uNumNPCNames[1])) + uNumNPCNames[1]=i; + } + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + uNumNPCNames[0] = i; + + pNPCProfTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcprof.txt", 0); + strtok(pNPCProfTXT_Raw, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + + for (i=1; i<59; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + //while (*test_string == '\t') // some steps are separated by multiple \t's + //++test_string; + + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + switch(decode_step) + { + case 2: + pProfessions[i].uHirePrice = atoi(test_string); + break; + case 3: + pProfessions[i].pActionText = RemoveQuotes(test_string); + break; + case 4: + pProfessions[i].pBenefits= RemoveQuotes(test_string); + break; + case 5: + pProfessions[i].pJoinText = RemoveQuotes(test_string); + break; + case 6: + pProfessions[i].pDismissText = RemoveQuotes(test_string); + } + } + else + { + if (!decode_step) + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<7)&&!break_loop); + } + uNumNPCProfessions = 59; + } + +//----- (00477266) -------------------------------------------------------- +void NPCStats::Release() + { + free(pNPCTopicTXT_Raw); + pNPCTopicTXT_Raw = nullptr; + free(pNPCTextTXT_Raw); + pNPCTextTXT_Raw = nullptr; + free(pNPCNewsTXT_Raw); + pNPCNewsTXT_Raw = nullptr; + free(pNPCProfTXT_Raw); + pNPCProfTXT_Raw = nullptr; + free(pNPCNamesTXT_Raw); + pNPCNamesTXT_Raw = nullptr; + free(pNPCDataTXT_Raw); + pNPCDataTXT_Raw = nullptr; + free(pNPCDistTXT_Raw); + pNPCDistTXT_Raw = nullptr; + free(pNPCGreetTXT_Raw); + pNPCGreetTXT_Raw = nullptr; + free(pNCPGroupTXT_Raw); + pNCPGroupTXT_Raw = nullptr; + } + +//----- (0047730C) -------------------------------------------------------- +bool CheckPortretAgainstSex(int a1, int) + { + return true; + } +// 47730C: using guessed type int __stdcall const_1(int); + +//----- (0047732C) -------------------------------------------------------- +void NPCStats::InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId) + { + int rep_gen; + int uNPCSex; // esi@1 + int uGeneratedPortret; // ecx@23 + int test_prof_summ; // ecx@37 + int gen_profession; // eax@37 + int max_prof_cap; // edx@37 +// signed int result; // eax@39 + int uRace; // [sp+Ch] [bp-Ch]@1 + bool break_gen; // [sp+10h] [bp-8h]@1 + signed int gen_attempts; // [sp+14h] [bp-4h]@1 + int uPortretMin; // [sp+24h] [bp+Ch]@1 + int uPortretMax; + + static const unsigned __int8 NPCSexGenTable[86] ={ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; + static const unsigned __int8 NPCRaceGenTable[86] ={ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0}; + + unsigned __int8 seed = (unsigned __int8)((double)(npc_uid - 1)/3.0); + uNPCSex = NPCSexGenTable[seed]; + uRace = NPCRaceGenTable[seed]; + pNPCDataBuff->uSex = uNPCSex; + pNPCDataBuff->pName = pNPCNames[rand() % uNumNPCNames[uNPCSex]][uNPCSex]; + + gen_attempts = 0; + break_gen = false; + + do + { + switch ( uRace ) + { + case 0: + if ( uNPCSex == 0 ) + { + uPortretMin = 2; + uPortretMax = 100; + } + else + { + uPortretMin = 201; + uPortretMax = 250; + } + case 1: + if ( uNPCSex == 0 ) + { + uPortretMin = 400; + uPortretMax = 430; + } + else + { + uPortretMin = 460; + uPortretMax = 490; + } + break; + case 2: + if ( uNPCSex == 0 ) + { + uPortretMin = 500; + uPortretMax = 520; + } + else + { + uPortretMin = 530; + uPortretMax = 550; + } + break; + case 3: + if ( uNPCSex == 0 ) + { + uPortretMin = 300; + uPortretMax = 330; + } + else + { + uPortretMin = 360; + uPortretMax = 387; + } + + break; + } + + uGeneratedPortret = uPortretMin + rand() % (uPortretMax - uPortretMin + 1); + if ( CheckPortretAgainstSex(uGeneratedPortret, uNPCSex)) + break_gen = true; + ++gen_attempts; + if ( gen_attempts >= 4 ) + { + uGeneratedPortret = uPortretMin; + break_gen = true; + } + } + while(!break_gen); + + pNPCDataBuff->uPortraitID = uGeneratedPortret; + pNPCDataBuff->uFlags = 0; + pNPCDataBuff->fame = 0; + //generate reputation + rep_gen = rand() % 100 + 1; + + if ( rep_gen >= 60 ) + { + if ( rep_gen >= 90 ) + { + if ( rep_gen >= 95 ) + { + if ( rep_gen >= 98 ) + pNPCDataBuff->rep = -600; + else + pNPCDataBuff->rep = 400; + } + else + pNPCDataBuff->rep = -300; + } + else + pNPCDataBuff->rep = 200; + } + else + pNPCDataBuff->rep = 0; + + max_prof_cap = rand() % pProfessionChance[uMapId].uTotalprofChance+1; + test_prof_summ = 0; + gen_profession = 0; + + if ( max_prof_cap > 0 ) + { + do + test_prof_summ += pProfessionChance[uMapId].professionChancePerArea[gen_profession++]; + while ( test_prof_summ < max_prof_cap ); + } + pNPCDataBuff->uProfession = gen_profession - 1; + pNPCDataBuff->Location2D = uLocation2D; + pNPCDataBuff->field_24 = 1; + pNPCDataBuff->joins = 1; + pNPCDataBuff->evt_A = 0; + pNPCDataBuff->evt_B = 0; + pNPCDataBuff->evt_C = 0; + pNPCDataBuff->evt_D = 0; + pNPCDataBuff->evt_E = 0; + pNPCDataBuff->evt_F = 0; + } + + +//----- (00495366) -------------------------------------------------------- +char *NPCStats::sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId) +{ + int pickedName; // edx@2 + + if ( firstLetter == dword_AE336C_LastMispronouncedNameFirstLetter) + pickedName = dword_AE3370_LastMispronouncedNameResult; + else + { + dword_AE336C_LastMispronouncedNameFirstLetter = firstLetter; + if ( this->uNumNPCNames[genderId] == 0 ) + pickedName = rand() % this->uNumNPCNames[(genderId + 1) % 2]; //originally without " + 1) % 2", but that would yield a div by zero + else + { + int rangeBottom = 0; + int rangeTop = 0; + for ( uint i = 0; i < this->uNumNPCNames[genderId]; ++i ) + { + if (tolower(this->pNPCNames[i][genderId][0])) + { + if ( rangeBottom ) + rangeTop = i; + else + rangeBottom = i; + } + } + if ( rangeTop != 0 ) + pickedName = rangeBottom + rand() % (rangeTop - rangeBottom); + else + pickedName = rand() % this->uNumNPCNames[genderId]; + } + } + dword_AE3370_LastMispronouncedNameResult = pickedName; + return this->pNPCNames[pickedName][genderId]; +} + +//----- (00476387) -------------------------------------------------------- +bool PartyHasDragon() +{ + return pNPCStats->pNewNPCData[57].Hired(); +} + +//----- (00476395) -------------------------------------------------------- +//0x26 Wizard eye at skill level 2 +bool CheckHiredNPCSpeciality(unsigned int uProfession) + { + + if ( bNoNPCHiring == 1 ) + return 0; + + for (uint i=0; i<pNPCStats->uNumNewNPCs; ++i ) + { + if ( pNPCStats->pNewNPCData[i].uProfession == uProfession && + (pNPCStats->pNewNPCData[i].uFlags & 0x80) )//Uninitialized memory access + return true; + } + if ( pParty->pHirelings[0].uProfession == uProfession || + pParty->pHirelings[1].uProfession == uProfession) + return true; + else + return false; + + } + +//----- (004763E0) -------------------------------------------------------- +void InitializeAwards() +{ + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pAwardsTXT_Raw); + pAwardsTXT_Raw = (char *)pEvents_LOD->LoadRaw("awards.txt", 0); + strtok(pAwardsTXT_Raw, "\r"); + + for (i=1; i<105; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if (decode_step==1) + pAwards[i].pText=RemoveQuotes(test_string); + else if (decode_step==2) + pAwards[i].uPriority = atoi(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<3)&&!break_loop); + } + } +// 7241C8: using guessed type int dword_7241C8; + +//----- (004764C2) -------------------------------------------------------- +void InitializeScrolls() + { + + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pScrollsTXT_Raw); + pScrollsTXT_Raw = (char *)pEvents_LOD->LoadRaw("scroll.txt", 0); + strtok(pScrollsTXT_Raw, "\r"); + for (i=0; i<82; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ( decode_step == 1) + pScrolls[i]=RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + } + +//----- (00476590) -------------------------------------------------------- +void InitializeMerchants() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pMerchantsTXT_Raw); + pMerchantsTXT_Raw = (char *)pEvents_LOD->LoadRaw("merchant.txt", 0); + strtok(pMerchantsTXT_Raw, "\r"); + + for (i=0; i<7; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + switch (decode_step) + { + case 1: + pMerchantsBuyPhrases[i]=RemoveQuotes(test_string); + break; + case 2: + pMerchantsSellPhrases[i]=RemoveQuotes(test_string); + break; + case 3: + pMerchantsRepairPhrases[i]=RemoveQuotes(test_string); + break; + case 4: + pMerchantsIdentifyPhrases[i]=RemoveQuotes(test_string); + break; + } + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<5)&&!break_loop); + } + + } + +//----- (00476682) -------------------------------------------------------- +void InitializeTransitions() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pTransitionsTXT_Raw); + pTransitionsTXT_Raw = (char *)pEvents_LOD->LoadRaw("trans.txt", 0); + strtok(pTransitionsTXT_Raw, "\r"); + + for (i=0; i<464; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ( decode_step == 1) + pTransitionStrings[i + 1]=RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + } + +//----- (00476750) -------------------------------------------------------- +void InitializeAutonotes() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pAutonoteTXT_Raw); + pAutonoteTXT_Raw = (char *)pEvents_LOD->LoadRaw("autonote.txt", 0); + strtok(pAutonoteTXT_Raw, "\r"); + + for (i=0; i<195; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + switch (decode_step) + { + case 1: + pAutonoteTxt[i+1].pText=RemoveQuotes(test_string); + break; + case 2: + { + if ( !_stricmp(test_string, "potion")) + { + pAutonoteTxt[i+1].eType = AUTONOTE_POTION_RECEPIE; + break; + } + if ( !_stricmp(test_string, "stat") ) + { + pAutonoteTxt[i+1].eType = AUTONOTE_STAT_HINT; + break; + } + if ( !_stricmp(test_string, "seer") ) + { + pAutonoteTxt[i+1].eType = AUTONOTE_SEER; + break; + } + if ( !_stricmp(test_string, "obelisk") ) + { + pAutonoteTxt[i+1].eType = AUTONOTE_OBELISK; + break; + } + if ( !_stricmp(test_string, "teacher") ) + { + pAutonoteTxt[i+1].eType = AUTONOTE_TEACHER; + break; + } + pAutonoteTxt[i+1].eType =AUTONOTE_MISC; + break; + } + } + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<3)&&!break_loop); + } + } + + +//----- (004768A9) -------------------------------------------------------- +void InitializeQuests() + { + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; + + free(pQuestsTXT_Raw); + pQuestsTXT_Raw = (char *)pEvents_LOD->LoadRaw("quests.txt", 0); + strtok(pQuestsTXT_Raw, "\r"); + memset(pQuestTable.data(),0, sizeof(pQuestTable)); + for (i=0; i<512; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if ( decode_step == 1) + pQuestTable[i+1] =RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<2)&&!break_loop); + } + } + +//----- (004B29F2) -------------------------------------------------------- +const char * ContractSelectText( int pEventCode ) +{ + static const int dialogue_base=110; + contract_approved = 0; + dword_F8B1AC_award_bit_number = pEventCode + 50; + gold_transaction_amount = price_for_membership[pEventCode]; + if ( pPlayers[uActiveCharacter]->CanAct() ) + { + if ( (unsigned __int16)_449B57_test_bit((unsigned __int8 *)pPlayers[uActiveCharacter]->_achieved_awards_bits, dword_F8B1AC_award_bit_number) ) + return pNPCTopics[dialogue_base+13].pText; + else + { + if ( (unsigned int)gold_transaction_amount <= pParty->uNumGold ) + { + contract_approved = 1; + return pNPCTopics[pEventCode + dialogue_base].pText; + } + else + return pNPCTopics[dialogue_base+14].pText; + } + } + else + return pNPCTopics[dialogue_base+12].pText; +} +//----- (004B40E6) -------------------------------------------------------- +void NPCHireableDialogPrepare() + { + signed int v0; // ebx@1 + NPCData *v1; // edi@1 + + v0 = 0; + v1 = HouseNPCData[(unsigned int)((char *)pDialogueNPCCount + -(dword_591080 != 0) )];//- 1 + pDialogueWindow->Release(); + pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 350, WINDOW_MainMenu, 0, 0); + pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 0x1BDu, 0xA9u, 0x23u, 1, 0, UIMSG_Escape, 0, 0, + pGlobalTXT_LocalizationStrings[34], //"Cancel" + pIcons_LOD->GetTexture(uExitCancelTextureId), + 0); + pDialogueWindow->CreateButton(0, 0, 0, 0, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0); + if ( pNPCStats->pProfessions[v1->uProfession].pBenefits)//*(&pNPCStats->field_13A5C + 5 * v1->uProfession) ) + { + pDialogueWindow->CreateButton( 480, 0xA0u, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Du, 0, + pGlobalTXT_LocalizationStrings[407], 0);//"More Information" + v0 = 1; + } + pDialogueWindow->CreateButton( 0x1E0u, 30 * v0 + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Cu, 0, + pGlobalTXT_LocalizationStrings[406], 0); //"Hire" + pDialogueWindow->_41D08F_set_keyboard_control_group(v0 + 1, 1, 0, 2); + dialog_menu_id = HOUSE_DIALOGUE_OTHER; +} + +//----- (004B4224) -------------------------------------------------------- +void _4B4224_UpdateNPCTopics( int _this ) + { + int num_menu_buttons; // ebx@1 + int i; // ebp@5 + // signed int v4; // ebp@9 + int v6; // eax@16 + int v8; // eax@21 + int v10; // eax@26 + int v12; // eax@31 + int v14; // eax@36 + int v16; // eax@41 + NPCData *v17; // [sp+10h] [bp-4h]@4 + + num_menu_buttons = 0; + pDialogueNPCCount = (_this + 1); + if ( _this + 1 == uNumDialogueNPCPortraits && uHouse_ExitPic ) + { + pDialogueWindow->Release(); + pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_MainMenu, 0, 0); + sprintfex(sHouseName.data(), pGlobalTXT_LocalizationStrings[LOCSTR_ENTER_S], pMapStats->pInfos[uHouse_ExitPic].pName); + pBtn_ExitCancel = pDialogueWindow->CreateButton(566, 445, 75, 33, 1, 0, UIMSG_Escape, 0, 'N', pGlobalTXT_LocalizationStrings[34], pIcons_LOD->GetTexture(uTextureID_BUTTDESC2), 0);// "Cancel" + pBtn_YES = pDialogueWindow->CreateButton(486, 445, 75, 33, 1, 0, UIMSG_BF, 1, 'Y', sHouseName.data(), pIcons_LOD->GetTexture(uTextureID_BUTTYES2), 0); + pDialogueWindow->CreateButton( pNPCPortraits_x[0][0], pNPCPortraits_y[0][0], 63u, 73u, 1, 0, UIMSG_BF, 1u, 0x20u, sHouseName.data(), 0); + pDialogueWindow->CreateButton(8, 8, 460, 344, 1, 0, UIMSG_BF, 1, 0x59u, sHouseName.data(), 0); + } + else + { + v17 = HouseNPCData[_this + 1 - ((dword_591080 != 0)?1:0 )];//+ 1 + if ( dialog_menu_id == HOUSE_DIALOGUE_OTHER ) + { + pDialogueWindow->Release(); + } + else + { + for ( i = 0; i < uNumDialogueNPCPortraits; ++i ) + HouseNPCPortraitsButtonsList[i]->Release(); + } + pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 345, WINDOW_MainMenu, 0, 0); + pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 445, 169, 35, 1, 0, UIMSG_Escape, 0, 0, + pGlobalTXT_LocalizationStrings[74],// "End Conversation" + pIcons_LOD->GetTexture(uExitCancelTextureId), 0); + pDialogueWindow->CreateButton(8, 8, 450, 320, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0); + if ( pDialogueNPCCount == 1 && dword_591080 ) + { + InitializaDialogueOptions(in_current_building_type); + } + else + { + if ( v17->joins ) + { + num_menu_buttons = 1; + pDialogueWindow->CreateButton(480u, 160u, 140u, 30, 1, 0, UIMSG_ClickNPCTopic, 0xDu, 0, "", 0); + } + if ( v17->evt_A) + { + if ( num_menu_buttons < 4 ) + { + v6 = NPC_EventProcessor(v17->evt_A); + if ( v6 == 1 || v6 == 2 ) + pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x13u, 0, "", 0); + } + } + if ( v17->evt_B ) + { + if ( num_menu_buttons < 4 ) + { + v8 = NPC_EventProcessor(v17->evt_B); + if ( v8 == 1 || v8 == 2 ) + pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x14u, 0, "", 0); + } + } + if ( v17->evt_C ) + { + if ( num_menu_buttons < 4 ) + { + v10 = NPC_EventProcessor(v17->evt_C); + if ( v10 == 1 || v10 == 2 ) + pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x15u, 0, "", 0); + } + } + + if ( v17->evt_D ) + { + if ( num_menu_buttons < 4 ) + { + v12 = NPC_EventProcessor(v17->evt_D); + if ( v12 == 1 || v12 == 2 ) + pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x16u, 0, "", 0); + } + } + if ( v17->evt_E ) + { + if ( num_menu_buttons < 4 ) + { + v14 = NPC_EventProcessor(v17->evt_E); + if ( v14 == 1 || v14 == 2 ) + pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x17u, 0, "", 0); + } + } + if ( v17->evt_F ) + { + if ( num_menu_buttons < 4 ) + { + v16 = NPC_EventProcessor(v17->evt_F); + if ( v16 == 1 || v16 == 2 ) + pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x18u, 0, "", 0); + } + } + pDialogueWindow->_41D08F_set_keyboard_control_group(num_menu_buttons, 1, 0, 2); + dword_F8B1E0 = pDialogueWindow->pNumPresenceButton; + } + dialog_menu_id = HOUSE_DIALOGUE_MAIN; + } + +} +//----- (004466C4) -------------------------------------------------------- +int NPC_EventProcessor(int npc_event_id, int entry_line) + { + signed int event_index; // ebp@1 + int evt_seq_num; // esi@3 + bool ready_to_exit; // [sp+Ch] [bp-Ch]@3 + signed int npc_activity; // [sp+10h] [bp-8h]@3 + int result; + + event_index = 0; + if ( !npc_event_id ) + return 0; + evt_seq_num = entry_line; + pSomeOtherEVT = pGlobalEVT.data(); + uSomeOtherEVT_NumEvents = uGlobalEVT_NumEvents; + memcpy(pSomeOtherEVT_Events.data(), pGlobalEVT_Index.data(), sizeof(EventIndex)*4400); + npc_activity = 1; + ready_to_exit = false; + if ( uSomeOtherEVT_NumEvents <= 0 ) + return 2; + do + { + if ( (pSomeOtherEVT_Events[event_index].uEventID == npc_event_id) && (pSomeOtherEVT_Events[event_index].event_sequence_num == evt_seq_num) ) + { + _evt_raw *_evt = (_evt_raw *)&pSomeOtherEVT[pSomeOtherEVT_Events[event_index].uEventOffsetInEVT]; + switch(_evt->_e_type) + { + case EVENT_Exit: + //exit + if ( ready_to_exit ) + result = npc_activity != 0; + else + result = 2; + return result; + break; + case EVENT_OnCanShowDialogItemCmp: + ready_to_exit = true; + //v8 = (unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + (((unsigned __int8)v7[9] + ((unsigned __int8)v7[10] << 8)) << 8)) << 8); + for(int i=0; i<4; ++i) + { + // if (pParty->pPlayers[i].CompareVariable((enum VariableType)((unsigned __int8)pSomeOtherEVT[v6 + 5] + ((unsigned __int8)pSomeOtherEVT[v6 + 6] << 8)), + // v8)) + if (pParty->pPlayers[i].CompareVariable((enum VariableType)EVT_WORD(_evt->v5), EVT_DWORD(_evt->v7))) + { + event_index = -1; + evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1; + break; + } + } + break; + case EVENT_EndCanShowDialogItem : + if ( ready_to_exit ) + result = npc_activity != 0; + else + result = 2; + return result; + break; + case EVENT_SetCanShowDialogItem : + ready_to_exit = true; + npc_activity = EVT_BYTE(_evt->v5); //(unsigned __int8)v7[5]; + break; + case EVENT_IsActorAssasinated : + // if (IsActorAlive( (unsigned __int8)v7[5], + // (unsigned __int8)v7[6] + (((unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + ((unsigned __int8)v7[9] << 8)) << 8)) << 8), + // (unsigned __int8)v7[10]) ) + if (IsActorAlive( EVT_BYTE(_evt->v5), EVT_DWORD(_evt->v6), EVT_BYTE(_evt->v10))) + { // drop linear sequense, going to new seq + event_index = -1; + evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1; + } + break; + } + ++evt_seq_num; + } + ++event_index; + } + while ( event_index < uSomeOtherEVT_NumEvents ); + if ( ready_to_exit ) + result = npc_activity != 0; + else + result = 2; + return result; +} +//----- (00445C8B) -------------------------------------------------------- +int __fastcall GetGreetType(signed int SpeakingNPC_ID) +{ + signed int v1; // ebx@1 + int v3; // edi@6 + int v4; // ecx@6 + int v5; // edx@6 + NPCData *v6; // eax@6 + char *v7; // ebp@11 + NPCData *v8; // esi@11 + + v1 = 0; + if ( SpeakingNPC_ID >= 0 ) + { + if ( SpeakingNPC_ID < 5000 ) + return 1;//QuestNPC_greet + return 2;//HiredNPC_greet + } + if ( SpeakingNPC_ID >= 5000 ) + return 2; + v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1; + v4 = 0; + v5 = 0; + v6 = pParty->pHirelings.data(); + do + { + if ( v6->pName ) + pTmpBuf[v4++] = v5; + ++v6; + ++v5; + } + while ( (signed int)v6 < (signed int)&pParty->pPickedItem ); + if ( (signed int)pNPCStats->uNumNewNPCs > 0 ) + { + v7 = &pTmpBuf[v4]; + v8 = pNPCStats->pNewNPCData; + do + { + if (v8->Hired() && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) ) + { + if ( !pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName) ) + *v7++ = v1 + 2; + } + ++v1; + ++v8; + } + while ( v1 < (signed int)pNPCStats->uNumNewNPCs ); + } + return ((unsigned __int8)pTmpBuf[v3] < 2) + 1; +} +//----- (00445308) -------------------------------------------------------- +const char *GetProfessionActionText(int a1) +{ + if ( a1 == 10 + || a1 == 11 + || a1 == 12 + || a1 == 33 + || a1 == 34 + || a1 == 39 + || a1 == 40 + || a1 == 41 + || a1 == 42 + || a1 == 43 + || a1 == 52 ) + return pNPCStats->pProfessions[a1 - 1].pActionText; + else + return pNPCTopics[407].pTopic; +} + +//----- (004BB756) -------------------------------------------------------- +int UseNPCSkill(NPCProf profession) +{ + switch (profession) + { + case Healer: + { + for (int i = 0; i < 4; ++i) + pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); + } + break; + + case ExpertHealer: + { + for (int i = 0; i < 4; ++i) + { + __debugbreak(); + pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); + + for (int j = 0; j < 14; ++j) + pParty->pPlayers[i].pConditions[j] = 0; + pParty->pPlayers[i].pConditions[Condition_Good] = 0; + } + } + break; + + case MasterHealer: + { + for (int i = 0; i < 4; ++i) + { + __debugbreak(); //Ritor1:needed cleaned(Íåîáõîäèìî ïî÷èñòèòü) + Player* player = &pParty->pPlayers[i]; + pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); + + int v5 = LODWORD(player->pConditions[19]);//*((int *)v4 - 32); + int v6 = HIDWORD(player->pConditions[19]);//*((int *)v4 - 31); + memset(&pParty->pPlayers[i].pConditions, 0, sizeof(pParty->pPlayers[i].pConditions)); + + *(int *)&player->pActiveSkills[PLAYER_SKILL_SHIELD] = v5; + *(int *)&player->pActiveSkills[PLAYER_SKILL_CHAIN] = v6; + } + } + break; + + case Cook://Ïîâàð + { + if (pParty->uNumFoodRations >= 13) + return 1; + + Party::GiveFood(1); + } + break; + + case Chef: + { + if (pParty->uNumFoodRations >= 13) + return 1; + + if (pParty->uNumFoodRations == 13) + Party::GiveFood(1); + else + Party::GiveFood(2); + } + break; + + case WindMaster: + { + if (uCurrentlyLoadedLevelType == LEVEL_Indoor) + { + ShowStatusBarString(pGlobalTXT_LocalizationStrings[494], 2);//Íåëüçÿ ïðèìåíèòü çíàíèå Ïîëåò â ïîìåùåíèè! + pAudioPlayer->PlaySound(SOUND_203, 0, 0, -1, 0, 0, 0, 0); + } + else + { + int v19 = pOtherOverlayList->_4418B1(10008, 203, 0, 65536); + pParty->pPartyBuffs[PARTY_BUFF_FLY].Apply(pParty->uTimePlayed + 60 * (256 * 2), 3, 1, v19, 0); + pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags |= 1; + pAudioPlayer->PlaySound(SOUND_11090, 0, 0, -1, 0, 0, 0, 0); + } + } + break; + + case WaterMaster: + { + int v20 = pOtherOverlayList->_4418B1(10005, 201, 0, 65536); + pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].Apply(pParty->uTimePlayed + 60 * (256 * (2 + 1)), 3, 0, v20, 0); + pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags |= 1; + pAudioPlayer->PlaySound(SOUND_12040, 0, 0, -1, 0, 0, 0, 0); + } + break; + + case GateMaster: + { + pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); + dword_50C9DC = 195; + ptr_50C9E0 = GetNPCData(sDialogue_SpeakingActorNPC_ID); + } + break; + + case Acolyte: _42777D_CastSpell_UseWand_ShootArrow(46, 0, 133, 0, 0); break; + case Piper: _42777D_CastSpell_UseWand_ShootArrow(51, 0, 133, 0, 0); break; + case FallenWizard: _42777D_CastSpell_UseWand_ShootArrow(86, 0, 133, 0, 0); break; + + case Teacher: + case Instructor: + case Armsmaster: + case Weaponsmaster: + case Apprentice: + case Mystic: + case Spellmaster: + case Trader: + case Merchant: + case Scout: + case Herbalist: + case Apothecary: + case Tinker: + case Locksmith: + case Fool: + case ChimneySweep: + case Porter: + case QuarterMaster: + case Factor: + case Banker: + case Horseman: + case Bard: + case Enchanter: + case Cartographer: + case Explorer: + case Pirate: + case Squire: + case Psychic: + case Gypsy: + case Diplomat: + case Duper: + case Burglar: + case Acolyte2: + case Initiate: + case Prelate: + case Monk: + case Sage: + case Hunter: + break; + + default: + assert(false && "Invalid enum value"); + } + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/NPC.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,216 @@ +#pragma once + +enum NPCProf +{ + Smith = 1, // GM Weapon Repair; + Armorer = 2, // GM Armor Repair; + Alchemist = 3, // GM Potion Repair; + Scholar = 4, // GM Item ID; Learning: +5 + Guide = 5, // Travel by foot: -1 day; + Tracker = 6, // Travel by foot: -2 days; + Pathfinder = 7, // Travel by foot: -3 days; + Sailor = 8, // Travel by sea: -2 days; + Navigator = 9, // Travel by sea: -3 days; + Healer = 10, + ExpertHealer = 11, + MasterHealer = 12, + Teacher = 13, // Learning: +10; + Instructor = 14, // Learning: +15; + Armsmaster = 15, // Armsmaster: +2; + Weaponsmaster = 16, // Armsmaster: +3; + Apprentice = 17, // Fire: +2; Air: +2; Water: +2; Earth: +2; + Mystic = 18, // Fire: +3; Air: +3; Water: +3; Earth: +3; + Spellmaster = 19, // Fire: +4; Air: +4; Water: +4; Earth: +4; + Trader = 20, // Merchant: +4; + Merchant = 21, // Merchant: +6; + Scout = 22, // Perception: +6; + Herbalist = 23, // Alchemy: +4; + Apothecary = 24, // Alchemy: +8; + Tinker = 25, // Traps: +4; + Locksmith = 26, // Traps: +6; + Fool = 27, // Luck: +5; + ChimneySweep = 28, // Luck: +20; + Porter = 29, // Food for rest: -1; + QuarterMaster = 30, // Food for rest: -2; + Factor = 31, // Gold finds: +10%; + Banker = 32, // Gold finds: +20%; + Cook = 33, + Chef = 34, + Horseman = 35, // Travel by foot: -2 days; + Bard = 36, + Enchanter = 37, // Resist All: +20; + Cartographer = 38, // Wizard Eye level 2; + WindMaster = 39, + WaterMaster = 40, + GateMaster = 41, + Acolyte = 42, + Piper = 43, + Explorer = 44, // Travel by foot -1 day; Travel by sea: -1 day; + Pirate = 45, // Travel by sea: -2 days; Gold finds: +10%; Reputation: +5; + Squire = 46, + Psychic = 47, // Perception: +5; Luck: +10; + Gypsy = 48, // Food for rest: -1; Merchant: +3; Reputation: +5; + Diplomat = 49, + Duper = 50, // Merchant: +8; Reputation: +5; + Burglar = 51, // Traps: +8; Stealing: +8; Reputation: +5; + FallenWizard = 52, // Reputation: +5; + Acolyte2 = 53, // Spirit: +2; Mind: +2; Body: +2; + Initiate = 54, // Spirit: +3; Mind: +3; Body: +3; + Prelate = 55, // Spirit: +4; Mind: +4; Body: +4; + Monk = 56, // Unarmed: +2; Dodge: +2; + Sage = 57, // Monster ID: +6 + Hunter = 58 // Monster ID: +6 +}; + + + +struct NPCTopic +{ + const char *pTopic; + const char *pText; +}; + +extern std::array<NPCTopic, 789> pNPCTopics; + + +/* 136 */ +#pragma pack(push, 1) +struct NPCData //4Ch +{ + inline bool Hired() {return (uFlags & 0x80) != 0;} + + char *pName; //0 + unsigned int uPortraitID; //4 + unsigned int uFlags; //8 // & 0x80 no greeting on dialogue start; looks like hired + int fame; //c + int rep; //10 + unsigned int Location2D; //14 + unsigned int uProfession; //18 + int greet; //1c + int joins; //20 + int field_24; + unsigned int evt_A; //28 + unsigned int evt_B; //2c evtb + unsigned int evt_C; // 30 evtc + unsigned int evt_D; //34 + unsigned int evt_E; //38 + unsigned int evt_F; //3c + unsigned int uSex; //40 + int bHasUsedTheAbility; //44 + int news_topic; //48 +}; +#pragma pack(pop) + + +/* 138 */ +#pragma pack(push, 1) +struct NPCProfession +{ + inline NPCProfession(): + uHirePrice(0), pBenefits(nullptr), pActionText(nullptr), pJoinText(nullptr), pDismissText(nullptr) + {} + + unsigned int uHirePrice; + char *pBenefits; + char *pActionText; + char *pJoinText; + char *pDismissText; +}; +#pragma pack(pop) + + +/* 139 */ +#pragma pack(push, 1) +struct NPCProfessionChance +{ + unsigned int uTotalprofChance; //summ + char professionChancePerArea[60]; //prof position +}; +#pragma pack(pop) + +/* 140 */ +#pragma pack(push, 1) +struct NPCGreeting +{ + union + { + struct + { + char *pGreeting1; //at first meet + char *pGreeting2; // at latest meets + }; + char *pGreetings[2]; + }; +}; +#pragma pack(pop) + + +/* 137 */ +#pragma pack(push, 1) +struct NPCStats +{ + inline NPCStats(): + pNPCTextTXT_Raw(nullptr), pNPCTopicTXT_Raw(nullptr), pNPCDistTXT_Raw(nullptr) + { + uNumNPCNames[0] = uNumNPCNames[1] = 0; + } + + void InitializeNPCText(); + void InitializeNPCData(); + void Initialize(); + void Release(); + void InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId); + void _476C60(); + char * sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId); + + + NPCData pNPCData[501]; //0 - 94BCh count from 1 + NPCData pNewNPCData[501]; //94BCh- 12978h count from 1 + char *pNPCNames[540][2]; + NPCProfession pProfessions[59]; //count from 1 + NPCData pAdditionalNPC[100]; + char *pCatchPhrases[52]; //15CA4h + char *pNPCUnicNames[500]; //from first batch + NPCProfessionChance pProfessionChance[77]; //16544h profession chance in each area + int field_17884; + int field_17888; + NPCGreeting pNPCGreetings[205]; + unsigned __int16 pGroups[51]; + unsigned __int16 pGroups_copy[51]; + unsigned int uNewlNPCBufPos; + unsigned int uNumNewNPCs; + int field_17FC8; + unsigned int uNumNPCProfessions; + unsigned int uNumNPCNames[2]; //0 male 1 female + char *pNPCDataTXT_Raw; + char *pNPCNamesTXT_Raw; + char *pNPCProfTXT_Raw; + char *pNPCNewsTXT_Raw; + char *pNPCTopicTXT_Raw; + char *pNPCTextTXT_Raw; + char *pNPCDistTXT_Raw; + char *pNPCGreetTXT_Raw; + char *pNCPGroupTXT_Raw; + + static int dword_AE336C_LastMispronouncedNameFirstLetter; + static int dword_AE3370_LastMispronouncedNameResult; +}; +#pragma pack(pop) + +extern int pDialogueNPCCount; +extern std::array<struct Texture *, 6> pDialogueNPCPortraits; +extern int uNumDialogueNPCPortraits; // weak +extern struct NPCStats *pNPCStats; + +bool PartyHasDragon(); +bool CheckHiredNPCSpeciality(unsigned int uProfession); + +int UseNPCSkill(NPCProf profession); +const char *ContractSelectText(int pEventCode); +void NPCHireableDialogPrepare(); +void _4B4224_UpdateNPCTopics(int _this); +const char *GetProfessionActionText(int a1); +struct NPCData *__fastcall GetNPCData(signed int npcid); +struct NPCData * GetNewNPCData(signed int npcid, int* npc_indx); +int __fastcall GetGreetType(signed int SpeakingNPC_ID); +int NPC_EventProcessor(int npc_event_id, int entry_line = 0);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/ObjectList.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,280 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include "ObjectList.h" +#include "mm7_data.h" +#include "Engine/Graphics/Sprites.h" +#include "FrameTableInc.h" +#include "ErrorHandling.h" + +//----- (0042EB42) -------------------------------------------------------- +__int16 ObjectList::ObjectIDByItemID(unsigned __int16 uItemID) +{ + unsigned int v2; // edx@1 + signed int v3; // eax@1 + char *v4; // ecx@2 + + v2 = this->uNumObjects; + v3 = 0; + if ( (signed int)this->uNumObjects <= 0 ) + { +LABEL_5: + LOWORD(v3) = 0; + } + else + { + v4 = (char *)&this->pObjects->uObjectID; + while ( uItemID != *(short *)v4 ) + { + ++v3; + v4 += 56; + if ( v3 >= (signed int)v2 ) + goto LABEL_5; + } + } + return v3; +} +//----- (00459064) -------------------------------------------------------- +void ObjectList::InitializeSprites() +{ + for (uint i = 0; i < uNumObjects; ++i) + pSpriteFrameTable->InitializeSprite(pObjects[i].uSpriteID); +} + +//----- (00459090) -------------------------------------------------------- +void ObjectList::ToFile() +{ + ObjectList *v1; // esi@1 + FILE *v2; // eax@1 + FILE *v3; // edi@1 + + v1 = this; + v2 = fopen("data\\dobjlist.bin", "wb"); + v3 = v2; + if ( !v2 ) + Error("Unable to save dobjlist.bin!"); + fwrite(v1, 4u, 1u, v2); + fwrite(v1->pObjects, 0x38u, v1->uNumObjects, v3); + fclose(v3); +} + +//----- (004590DC) -------------------------------------------------------- +void ObjectList::FromFile(void *data_mm6, void *data_mm7, void *data_mm8) +{ + uint num_mm6_objs = data_mm6 ? *(int *)data_mm6 : 0, + num_mm7_objs = data_mm7 ? *(int *)data_mm7 : 0, + num_mm8_objs = data_mm8 ? *(int *)data_mm8 : 0; + + uNumObjects = num_mm6_objs + num_mm7_objs + num_mm8_objs; + Assert(uNumObjects); + Assert(!num_mm8_objs); + + pObjects = (ObjectDesc *)malloc(uNumObjects * sizeof(ObjectDesc)); + memcpy(pObjects, (char *)data_mm7 + 4, num_mm7_objs * sizeof(ObjectDesc)); + for (uint i = 0; i < num_mm6_objs; ++i) + { + auto src = (ObjectDesc_mm6 *)((char *)data_mm6 + 4) + i; + ObjectDesc* dst = &pObjects[num_mm7_objs + i]; + memcpy(dst->field_0, src->field_0, sizeof(dst->field_0)); + dst->uObjectID = src->uObjectID; + dst->uRadius = src->uRadius; + dst->uHeight = src->uHeight; + dst->uFlags = src->uFlags; + dst->uSpriteID = src->uSpriteID; + dst->uLifetime = src->uLifetime; + dst->uParticleTrailColor = src->uParticleTrailColor; + dst->uSpeed = src->uSpeed; + dst->uParticleTrailColorR = src->uParticleTrailColorR; + dst->uParticleTrailColorG = src->uParticleTrailColorG; + dst->uParticleTrailColorB = src->uParticleTrailColorB; + dst->field_35_clr = src->field_35_clr; + dst->field_36_clr = 0; + dst->field_37_clr = 0; + } +} + +//----- (00459123) -------------------------------------------------------- +bool ObjectList::FromFileTxt(const char *Args) +{ + ObjectList *v2; // ebx@1 + __int32 v3; // edi@1 + FILE *v4; // eax@1 + unsigned int v5; // esi@3 + void *v6; // eax@9 + FILE *v7; // ST0C_4@11 + char *i; // eax@11 + unsigned __int16 v9; // ax@14 + const char *v10; // ST20_4@14 + __int16 v11; // ax@14 + const char *v12; // ST1C_4@14 + __int16 v13; // ax@14 + const char *v14; // ST18_4@14 + __int16 v15; // ax@14 + const char *v16; // ST14_4@14 + __int16 v17; // ax@14 + const char *v18; // ST10_4@14 + __int16 v19; // ax@14 + const char *v20; // ST0C_4@14 + int v21; // esi@16 + const char *v22; // edi@16 + int v23; // eax@17 + int v24; // eax@19 + int v25; // eax@21 + int v26; // eax@21 + int v27; // eax@21 + int v28; // eax@23 + int v29; // eax@25 + int v30; // eax@27 + int v31; // eax@29 + const char *v32; // edi@30 + const char *v33; // ST20_4@35 + int v34; // eax@35 + char v35; // al@35 + const char *v36; // ST1C_4@35 + char v37; // al@35 + const char *v38; // ST18_4@35 + FrameTableTxtLine v40; // [sp+8h] [bp-460h]@14 + FrameTableTxtLine v41; // [sp+84h] [bp-3E4h]@12 + char Dest; // [sp+100h] [bp-368h]@14 + char Buf; // [sp+178h] [bp-2F0h]@3 + FrameTableTxtLine v44; // [sp+36Ch] [bp-FCh]@4 + FrameTableTxtLine v45; // [sp+3E8h] [bp-80h]@4 + FILE *File; // [sp+464h] [bp-4h]@1 + unsigned int Argsa; // [sp+470h] [bp+8h]@3 + int Argsb; // [sp+470h] [bp+8h]@15 + + v2 = this; + free(this->pObjects); + v3 = 0; + v2->pObjects = nullptr; + v2->uNumObjects = 0; + v4 = fopen(Args, "r"); + File = v4; + if ( !v4 ) + Error("ObjectDescriptionList::load - Unable to open file: %s."); + + v5 = 0; + Argsa = 0; + if ( fgets(&Buf, 490, v4) ) + { + do + { + *strchr(&Buf, 10) = 0; + memcpy(&v45, frame_table_txt_parser(&Buf, &v44), sizeof(v45)); + if ( v45.uPropCount && *v45.pProperties[0] != '/' ) + ++Argsa; + } + while ( fgets(&Buf, 490, File) ); + v5 = Argsa; + v3 = 0; + } + v2->uNumObjects = v5; + v6 = malloc(56 * v5); + v2->pObjects = (ObjectDesc *)v6; + if ( v6 == (void *)v3 ) + Error("ObjectDescriptionList::load - Out of Memory!"); + + memset(v6, v3, 56 * v2->uNumObjects); + v7 = File; + v2->uNumObjects = v3; + fseek(v7, v3, v3); + for ( i = fgets(&Buf, 490, File); i; i = fgets(&Buf, 490, File) ) + { + *strchr(&Buf, 10) = 0; + memcpy(&v45, frame_table_txt_parser(&Buf, &v41), sizeof(v45)); + if ( v45.uPropCount && *v45.pProperties[0] != 47 ) + { + strcpy(v2->pObjects[v2->uNumObjects].field_0, v45.pProperties[0]); + v9 = pSpriteFrameTable->FastFindSprite((char *)v45.pProperties[1]); + v10 = v45.pProperties[2]; + v2->pObjects[v2->uNumObjects].uSpriteID = v9; + v11 = atoi(v10); + v12 = v45.pProperties[3]; + v2->pObjects[v2->uNumObjects].uObjectID = v11; + v13 = atoi(v12); + v14 = v45.pProperties[4]; + v2->pObjects[v2->uNumObjects].uRadius = v13; + v15 = atoi(v14); + v16 = v45.pProperties[5]; + v2->pObjects[v2->uNumObjects].uHeight = v15; + v17 = atoi(v16); + v18 = v45.pProperties[6]; + v2->pObjects[v2->uNumObjects].uLifetime = v17; + v19 = atoi(v18); + v20 = v45.pProperties[7]; + v2->pObjects[v2->uNumObjects].uSpeed = v19; + strcpy(&Dest, v20); + memcpy(&v44, frame_table_txt_parser(&Dest, &v40), sizeof(v44)); + if ( v45.uPropCount > 7 ) + { + for ( Argsb = 0; Argsb < v44.uPropCount; ++Argsb ) + { + v21 = Argsb; + v22 = v44.pProperties[Argsb]; + if ( !_stricmp(v44.pProperties[Argsb], "NoDraw") ) + { + v23 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v23 |= 1u; + } + if ( !_stricmp(v22, "Lifetime") ) + { + v24 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v24 |= 4u; + } + if ( !_stricmp(v22, "FTLifetime") ) + { + v25 = (int)&v2->pObjects[v2->uNumObjects]; + *(short *)(v25 + 42) = 8 * pSpriteFrameTable->pSpriteSFrames[*(short *)(v25 + 40)].uAnimLength; + v26 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v26 |= 8u; + v27 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v27 |= 4u; + } + if ( !_stricmp(v22, "NoPickup") ) + { + v28 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v28 |= 0x10u; + } + if ( !_stricmp(v22, "NoGravity") ) + { + v29 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v29 |= 0x20u; + } + if ( !_stricmp(v22, "FlagOnIntercept") ) + { + v30 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v30 |= 0x40u; + } + if ( !_stricmp(v22, "Bounce") ) + { + v31 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)v31 |= 0x80u; + } + v32 = v45.pProperties[v21]; + if ( !_stricmp(v45.pProperties[v21], "Fire") ) + HIBYTE(v2->pObjects[v2->uNumObjects].uFlags) |= 2u; + if ( !_stricmp(v32, "Lines") ) + HIBYTE(v2->pObjects[v2->uNumObjects].uFlags) |= 4u; + if ( !_stricmp(v44.pProperties[v21], "bits") ) + { + v33 = v44.pProperties[v21 + 1]; + v34 = (int)&v2->pObjects[v2->uNumObjects].uFlags; + *(char *)(v34 + 1) |= 1u; + v35 = atoi(v33); + v36 = v44.pProperties[v21 + 2]; + v2->pObjects[v2->uNumObjects].uParticleTrailColorR = v35; + v37 = atoi(v36); + v38 = v44.pProperties[v21 + 3]; + v2->pObjects[v2->uNumObjects].uParticleTrailColorG = v37; + v2->pObjects[v2->uNumObjects].uParticleTrailColorB = atoi(v38); + } + } + } + ++v2->uNumObjects; + } + } + fclose(File); + return 1; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/ObjectList.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,88 @@ +#pragma once + + + + +/* 324 */ +enum OBJECT_DESC_FLAGS +{ + OBJECT_DESC_NO_SPRITE = 0x1, + OBJECT_DESC_NO_COLLISION = 0x2, + OBJECT_DESC_TEMPORARY = 0x4, + OBJECT_DESC_SFT_LIFETIME = 0x8, + OBJECT_DESC_UNPICKABLE = 0x10, + OBJECT_DESC_NO_GRAVITY = 0x20, + OBJECT_DESC_INTERACTABLE = 0x40, + OBJECT_DESC_BOUNCE = 0x80, + OBJECT_DESC_TRIAL_PARTICLE = 0x100, + OBJECT_DESC_TRIAL_FIRE = 0x200, + OBJECT_DESC_TRIAL_LINE = 0x400, +}; + + + + +/* 56 */ +#pragma pack(push, 1) +struct ObjectDesc_mm6 +{ + inline bool NoSprite() const {return uFlags & OBJECT_DESC_NO_SPRITE;} + + char field_0[32]; + __int16 uObjectID; + __int16 uRadius; + __int16 uHeight; + __int16 uFlags; + unsigned __int16 uSpriteID; + __int16 uLifetime; + unsigned short uParticleTrailColor; + __int16 uSpeed; + char uParticleTrailColorR; + char uParticleTrailColorG; + char uParticleTrailColorB; + char field_35_clr; +}; + +struct ObjectDesc +{ + inline bool NoSprite() const {return uFlags & OBJECT_DESC_NO_SPRITE;} + + char field_0[32]; + __int16 uObjectID; + __int16 uRadius; + __int16 uHeight; + __int16 uFlags; + unsigned __int16 uSpriteID; + __int16 uLifetime; + unsigned int uParticleTrailColor; + __int16 uSpeed; + unsigned char uParticleTrailColorR; + unsigned char uParticleTrailColorG; + unsigned char uParticleTrailColorB; + char field_35_clr; + char field_36_clr; + char field_37_clr; +}; +#pragma pack(pop) + +/* 57 */ +#pragma pack(push, 1) +struct ObjectList +{ + inline ObjectList(): //----- (004583D5) + uNumObjects(0), pObjects(nullptr) + {} + + void ToFile(); + void FromFile(void *data_mm6, void *data_mm7, void *data_mm8); + bool FromFileTxt(const char *Args); + void InitializeSprites(); + __int16 ObjectIDByItemID(unsigned __int16 uItemID); + + + unsigned int uNumObjects; + struct ObjectDesc *pObjects; +}; +#pragma pack(pop) + +extern struct ObjectList *pObjectList; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/Player.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,8199 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include "stru6.h" + +#include "ErrorHandling.h" + +#include "Player.h" +#include "PlayerFrameTable.h" +#include "AudioPlayer.h" +#include "Party.h" +#include "LOD.h" +#include "GUIWindow.h" +#include "Engine/Graphics/Viewport.h" +#include "Actor.h" +#include "Game.h" +#include "Mouse.h" +#include "TurnEngine.h" +#include "Events.h" +#include "Events2D.h" +#include "Engine/Graphics/Outdoor.h" +#include "StorylineTextTable.h" +#include "Autonotes.h" +#include "Awards.h" +#include "texts.h" + +#include "stru123.h" +#include "stru298.h" +#include "ObjectList.h" +#include "MM7.h" +#include "SpriteObject.h" +#include "Engine/Graphics/DecalBuilder.h" +#include "CastSpellInfo.h" +#include "OurMath.h" +#include "UI\UIPartyCreation.h" + + + + +NZIArray<struct Player *, 5> pPlayers; + + +/* 381 */ +#pragma pack(push, 1) +struct PlayerCreation_AttributeProps +{ + unsigned __int8 uBaseValue; + char uMaxValue; + char uDroppedStep; + char uBaseStep; +}; +#pragma pack(pop) + + +#pragma pack(push, 1) + + + +#pragma pack(pop) +PlayerCreation_AttributeProps StatTable[4][7] = //0x4ED7B0 +{ + {{11, 25, 1, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, { 9, 25, 1, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, {9, 25, 1, 1},}, + {{ 7, 15, 2, 1}, {14, 30, 1, 2}, {11, 25, 1, 1}, { 7, 15, 2, 1}, {14, 30, 1, 2}, {11, 25, 1, 1}, {9, 20, 1, 1},}, + {{14, 30, 1, 2}, { 7, 15, 2, 1}, { 7, 15, 2, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, {14, 30, 1, 2}, {9, 20, 1, 1},}, + {{14, 30, 1, 2}, {11, 25, 1, 1}, {11, 25, 1, 1}, {14, 30, 1, 2}, { 7, 15, 2, 1}, { 7, 15, 2, 1}, {9, 20, 1, 1}} +}; + + + +std::array<int, 5> StealingMasteryBonuses = {0, 100, 200, 300, 500}; //dword_4EDEA0 //the zeroth element isn't accessed, it just helps avoid -1 indexing, originally 4 element array off by one +std::array<int, 5> StealingRandomBonuses = {-200, -100, 0, 100, 200}; //dword_4EDEB4 +std::array<int, 5> StealingEnchantmentBonusForSkill = {0, 2, 4, 6, 10}; //dword_4EDEC4 //the zeroth element isn't accessed, it just helps avoid -1 indexing, originally 4 element array off by one + + + + // available skills per class ( 9 classes X 37 skills ) + // 0 - not available + // 1 - available + // 2 - primary skill +unsigned char pSkillAvailabilityPerClass[9][37] = // byte[] @ MM7.exe::004ED820 +{ + {0, 2, 0, 1, 1, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 2, 1, 0}, + {1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0}, + {0, 1, 1, 1, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 1, 2, 0, 0, 0, 1, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, + {0, 1, 1, 2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {0, 0, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0} // some of these are started at 4ED94C, but needs to be here +}; + + +unsigned char pEquipTypeToBodyAnchor[21] = // 4E8398 +{ + 1, // EQUIP_SINGLE_HANDED + 1, // EQUIP_TWO_HANDED + 2, // EQUIP_BOW + 3, // EQUIP_ARMOUR + 0, // EQUIP_SHIELD + 4, // EQUIP_HELMET + 5, // EQUIP_BELT + 6, // EQUIP_CLOAK + 7, // EQUIP_GAUNTLETS + 8, // EQUIP_BOOTS + 10, // EQUIP_RING + 9, // EQUIP_AMULET + 1, // EQUIP_WAND + 0, // EQUIP_REAGENT + 0, // EQUIP_POTION + 0, // EQUIP_SPELL_SCROLL + 0, // EQUIP_BOOK + 0, // EQUIP_MESSAGE_SCROLL + 0, // EQUIP_GOLD + 0, // EQUIP_GEM + 0 // EQUIP_NONE +}; + + +unsigned char pBaseHealthByClass[12] = {40, 35, 35, 30, 30, 30, 25, 20, 20, 0, 0, 0}; +unsigned char pBaseManaByClass[12] = { 0, 0, 0, 5, 5, 0, 10, 10, 15, 0, 0, 0}; +unsigned char pBaseHealthPerLevelByClass[36] = {5, 7, 9, 9, 4, 6, 8, 8, 5, 6, 8, 8, 4, 5, 6, 6, 3, 4, 6, 6, 4, 5, 6, 6, 2, 3, 4, 4, 2, 3, 4, 4, 2, 3, 3, 3}; +unsigned char pBaseManaPerLevelByClass[36] = {0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 2, 3, 3, 1, 2, 3, 3, 0, 2, 3, 3, 3, 4, 5, 5, 3, 4, 5, 5, 3, 4, 6, 6}; + +unsigned char pConditionAttributeModifier[7][19] = +{{100, 100, 100, 120, 50, 200, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 100, 100}, //Might + {100, 100, 100, 50, 25, 10, 100, 100, 75, 60, 50, 30, 100, 100, 100, 100, 100, 1, 100}, //Intelligence + {100, 100, 100, 50, 25, 10, 100, 100, 75, 60, 50, 30, 100, 100, 100, 100, 100, 1, 100}, //Willpower + {100, 100, 100, 100, 50, 150, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 100, 100}, //Endurance + {100, 100, 100, 50, 10, 100, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 50, 100}, //Accuracy + {100, 100, 100, 120, 20, 120, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 50, 100}, //Speed + {100, 100, 100, 100, 200, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100}}; //Luck + +unsigned char pAgingAttributeModifier[7][4] = +{{100, 75, 40, 10}, //Might + {100, 150, 100, 10}, //Intelligence + {100, 150, 100, 10}, //Willpower + {100, 75, 40, 10}, //Endurance + {100, 100, 40, 10}, //Accuracy + {100, 100, 40, 10}, //Speed + {100, 100, 100, 100}}; //Luck + +unsigned int pAgeingTable[4] = {50, 100, 150, 0xFFFF}; + +std::array<unsigned int, 18> pConditionImportancyTable = {{16, 15, 14, 17, 13, 2, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1, 0}}; + +short param_to_bonus_table[29] = {500, 400, 350, 300, 275, 250, 225, 200, 175, + 150, 125, 100, 75, 50, 40, 35, 30, 25, 21, + 19, 17, 15, 13, 11, 9, 7, 5, 3, 0}; +signed int parameter_to_bonus_value[29] = {30, 25, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6}; + + +unsigned short base_recovery_times_per_weapon_type[12] = +{ + 100, // PLAYER_SKILL_STAFF && Unarmed withoud skill + 90, // PLAYER_SKILL_SWORD && Unarmed with skill + 60, // PLAYER_SKILL_DAGGER + 100, // PLAYER_SKILL_AXE + 80, // PLAYER_SKILL_SPEAR + 100, // PLAYER_SKILL_BOW + 80, // PLAYER_SKILL_MACE + 30, // PLAYER_SKILL_BLASTER + 10, // PLAYER_SKILL_SHIELD + 10, // PLAYER_SKILL_LEATHER + 20, // PLAYER_SKILL_CHAIN + 30 // PLAYER_SKILL_PLATE +}; + +//----- (00490913) -------------------------------------------------------- +int PlayerCreation_GetUnspentAttributePointCount() +{ + signed int v0; // edi@1 + int raceId; // ebx@2 + signed int v4; // eax@17 + int v5; // edx@18 + signed int v6; // ecx@18 + signed int remainingStatPoints; // [sp+Ch] [bp-8h]@1 + + remainingStatPoints = 50; + v0 = 50; + for (int playerNum = 0; playerNum < 4; playerNum++) + { + raceId = pParty->pPlayers[playerNum].GetRace(); + for (int statNum = 0; statNum <= 6; statNum++) + { + switch ( statNum ) + { + case 0: + v0 = pParty->pPlayers[playerNum].uMight; + break; + case 1: + v0 = pParty->pPlayers[playerNum].uIntelligence; + break; + case 2: + v0 = pParty->pPlayers[playerNum].uWillpower; + break; + case 3: + v0 = pParty->pPlayers[playerNum].uEndurance; + break; + case 4: + v0 = pParty->pPlayers[playerNum].uAccuracy; + break; + case 5: + v0 = pParty->pPlayers[playerNum].uSpeed; + break; + case 6: + v0 = pParty->pPlayers[playerNum].uLuck; + break; + } + v4 = StatTable[raceId][statNum].uBaseValue; + if ( v0 >= v4 ) + { + v5 = StatTable[raceId][statNum].uDroppedStep; + v6 = StatTable[raceId][statNum].uBaseStep; + } + else + { + v5 = StatTable[raceId][statNum].uBaseStep; + v6 = StatTable[raceId][statNum].uDroppedStep; + } + remainingStatPoints += v5 * (v4 - v0) / v6; + } + } + return remainingStatPoints; +} + +//----- (00427730) -------------------------------------------------------- +bool Player::CanCastSpell(unsigned int uRequiredMana) +{ + if (sMana >= (signed int)uRequiredMana) + { + sMana -= (signed int)uRequiredMana; + return true; + } + + pAudioPlayer->PlaySound(SOUND_PlayerCantCastSpell, 0, 0, -1, 0, 0, 0, 0); + return false; +} + +//----- (004BE2DD) -------------------------------------------------------- +void Player::SalesProcess( unsigned int inventory_idnx, int item_index, int _2devent_idx ) + { + float v6; // ST04_4@1 + signed int item_value; // eax@1 + signed int sell_price; // ebx@1 + + item_value =pOwnItems[item_index].GetValue(); + v6 = p2DEvents[ _2devent_idx - 1].fPriceMultiplier; + sell_price = GetPriceSell(item_value, v6); + if ( pOwnItems[item_index].IsBroken() ) + sell_price = 1; + if ( sell_price < 1 ) + sell_price = 1; + RemoveItemAtInventoryIndex(inventory_idnx); + Party::SetGold(pParty->uNumGold + sell_price); +} + +//----- (0043EEF3) -------------------------------------------------------- +bool Player::NothingOrJustBlastersEquipped() +{ + signed int item_idx; // esi@1 + signed int item_id; // esi@1 + for (int i = 0; i < 16; ++i) + { + item_idx = pEquipment.pIndices[i]; + if (item_idx) + { + item_id = pOwnItems[item_idx - 1].uItemID; + if ( item_id != ITEM_BLASTER && item_id != ITEM_LASER_RIFLE ) //blaster& blaster rifle + return false; + } + } + return true; +} + +//----- (004B8040) -------------------------------------------------------- +int Player::GetConditionDayOfWeek( unsigned int uCondition ) + { + return (unsigned int)(((signed __int64)((double)this->pConditions[uCondition] * 0.234375) / 60 / 60) / 24) % 7 + 1; +} + +//----- (004B807C) -------------------------------------------------------- +int Player::GetTempleHealCostModifier(float a2) +{ + unsigned int conditionIdx; // eax@1 + int conditionTimeMultiplier; // esi@1 + int v6; // eax@8 + signed int result; // qax@13 + signed int baseConditionMultiplier; // [sp+8h] [bp-8h]@4 + + conditionIdx = GetMajorConditionIdx(); + if ( conditionIdx >= 14 && conditionIdx <= 16) + { + if ( conditionIdx <= 15 ) + baseConditionMultiplier = 5; + else //if ( conditionIdx == 16 ) + baseConditionMultiplier = 10; + conditionTimeMultiplier = GetConditionDayOfWeek(conditionIdx); + } + else + { + conditionTimeMultiplier = 1; + baseConditionMultiplier = 1; + if (conditionIdx < 14) + { + for (int i = 0; i <= 13; i++) + { + v6 = GetConditionDayOfWeek(i); + if ( v6 > conditionTimeMultiplier ) + conditionTimeMultiplier = v6; + } + } + } + result = (int)((double)conditionTimeMultiplier * (double)baseConditionMultiplier * a2); + if ( result < 1 ) + result = 1; + return result; +} + +//----- (004B8102) -------------------------------------------------------- +int Player::GetPriceSell(int uRealValue, float price_multiplier) +{ + signed int v3; // esi@1 + signed int result; // eax@3 + + v3 = (signed int)((signed __int64)((double)uRealValue / (price_multiplier + 2.0)) + uRealValue * GetMerchant() / 100); + if ( v3 > uRealValue ) + v3 = uRealValue; + result = 1; + if ( v3 >= 1 ) + result = v3; + return result; +} + +//----- (004B8142) -------------------------------------------------------- +int Player::GetBuyingPrice(unsigned int uRealValue, float price_multiplier) +{ + uint price = (uint)(((100 - GetMerchant()) * (uRealValue * price_multiplier)) / 100); + + if (price < uRealValue) + price = uRealValue; + return price; +} + +//----- (004B8179) -------------------------------------------------------- +int Player::GetPriceIdentification(float a2) +{ + signed int v2; // esi@1 + int v3; // ecx@1 + signed int result; // eax@3 + + v2 = (signed int)(a2 * 50.0); + v3 = v2 * (100 - GetMerchant()) / 100; + if ( v3 < v2 / 3 ) + v3 = v2 / 3; + result = 1; + if ( v3 >= 1 ) + result = v3; + return result; +} + +//----- (004B81C3) -------------------------------------------------------- +int Player::GetPriceRepair(int a2, float a3) +{ + signed int v3; // esi@1 + int v4; // ecx@1 + signed int result; // eax@3 + + v3 = (signed int)((double)a2 / (6.0 - a3)); + v4 = v3 * (100 - GetMerchant()) / 100; + if ( v4 < v3 / 3 ) + v4 = v3 / 3; + result = 1; + if ( v4 >= 1 ) + result = v4; + return result; +} + +//----- (004B8213) -------------------------------------------------------- +int Player::GetBaseSellingPrice(int a2, float a3) +{ + signed int v3; // qax@1 + + v3 = (signed int)((double)a2 / (a3 + 2.0)); + if ( v3 < 1 ) + v3 = 1; + return v3; +} + +//----- (004B8233) -------------------------------------------------------- +int Player::GetBaseBuyingPrice(int a2, float a3) +{ + signed int v3; // qax@1 + + v3 = (signed int)((double)a2 * a3); + if ( v3 < 1 ) + v3 = 1; + return v3; +} + +//----- (004B824B) -------------------------------------------------------- +int Player::GetBaseIdentifyPrice(float a2) +{ + signed int v2; // qax@1 + + v2 = (signed int)(a2 * 50.0); + if ( v2 < 1 ) + v2 = 1; + return v2; +} + +//----- (004B8265) -------------------------------------------------------- +int Player::GetBaseRepairPrice(int a2, float a3) +{ + signed int v3; // qax@1 + + v3 = (signed int)((double)a2 / (6.0 - a3)); + if ( v3 < 1 ) + v3 = 1; + return v3; +} + +//----- (004B6FF9) -------------------------------------------------------- +bool Player::IsPlayerHealableByTemple() +{ + if (this->sHealth >= GetMaxHealth() && this->sMana >= GetMaxMana() && GetMajorConditionIdx() == Condition_Good) + return false; + else + { + if (GetMajorConditionIdx() == Condition_Zombie) + { + if (((signed int)window_SpeakInHouse->ptr_1C == 78 || (signed int)window_SpeakInHouse->ptr_1C == 81 || (signed int)window_SpeakInHouse->ptr_1C == 82)) + return false; + else + return true; + } + else + return true; + } +} + +//----- (00421E75) -------------------------------------------------------- +unsigned int Player::GetItemIDAtInventoryIndex(int *pitem_index) +{ + int item_idx; // eax@1 + int inv_index; // eax@3 + + item_idx = *pitem_index; + if ( item_idx >125 || item_idx < 0 ) + return 0; + inv_index = this->pInventoryMatrix[item_idx]; + if ( inv_index < 0 ) + { + *pitem_index = -1 - inv_index; + inv_index = this->pInventoryMatrix[-1 - inv_index]; + } + return inv_index; +} + +//----- (004160CA) -------------------------------------------------------- +void Player::ItemsEnchant( int enchant_count ) + { + int avalible_items; // ebx@1 + int i; // edx@8 + __int16 item_index_tabl[138]; // [sp+Ch] [bp-118h]@1 + + avalible_items = 0; + memset (item_index_tabl,0,sizeof(item_index_tabl)); + + for (i = 0; i < 138; ++i) + { + if (( pOwnItems[i].uItemID>0)&&(pOwnItems[i].uItemID <= 134)) + item_index_tabl[avalible_items++] = i; + } + + if ( avalible_items ) + { + if ( enchant_count ) + { + for ( i = 0; i < enchant_count; ++i ) + { + if (!(pInventoryItemList[item_index_tabl[i]].uAttributes&ITEM_HARDENED)) + pInventoryItemList[item_index_tabl[rand() % avalible_items]].uAttributes |= ITEM_HARDENED; + } + } + else + { + for ( i = 0; i < avalible_items; ++i ) + { + pInventoryItemList[item_index_tabl[i]].uAttributes |= ITEM_HARDENED; + } + } + } +} + +//----- (004948B1) -------------------------------------------------------- +void Player::PlaySound(PlayerSpeech speech, int a3) +{ + signed int speechCount = 0; // esi@4 + signed int expressionCount = 0; // esi@4 + int pickedVariant; // esi@10 + CHARACTER_EXPRESSION_ID expression; // ebx@17 + signed int pSoundID; // ecx@19 + int speechVariantArray[5]; // [sp+Ch] [bp-1Ch]@7 + int expressionVariantArray[5]; + unsigned int pickedSoundID; // [sp+30h] [bp+8h]@4 + unsigned int expressionDuration = 0; + + pickedSoundID = 0; + if (uVoicesVolumeMultiplier) + { + for (int i = 0; i < 2; i++) + { + if ( SoundSetAction[speech][i] ) + { + speechVariantArray[speechCount] = SoundSetAction[speech][i]; + speechCount++; + } + } + if ( speechCount ) + { + pickedVariant = speechVariantArray[rand() % speechCount]; + int numberOfSubvariants = byte_4ECF08[pickedVariant - 1][uVoiceID]; + if (numberOfSubvariants > 0) + { + pickedSoundID = rand() % numberOfSubvariants + 2 * (pickedVariant + 50 * uVoiceID) + 4998; + pAudioPlayer->PlaySound((SoundID)pickedSoundID, PID(OBJECT_Player, uActiveCharacter + 39), 0, -1, 0, 0, (int)(pSoundVolumeLevels[uVoicesVolumeMultiplier] * 128.0f), 0); + } + } + } + + for (int i = 0; i < 5; i++) + { + if ( SoundSetAction[speech][i + 3] ) + { + expressionVariantArray[expressionCount] = SoundSetAction[speech][i + 3]; + expressionCount++; + } + } + if ( expressionCount ) + { + expression = (CHARACTER_EXPRESSION_ID)expressionVariantArray[rand() % expressionCount]; + if (expression == CHARACTER_EXPRESSION_21 && pickedSoundID ) + { + pSoundID = 0; + if ( pSoundList->sNumSounds ) + { + for (int i = 0; i < pSoundList->sNumSounds; i++) + { + if (pSoundList->pSL_Sounds[i].uSoundID == pickedSoundID) + pSoundID = i; + } + } + if ( pSoundList->pSL_Sounds[pSoundID].pSoundData[0] ) + expressionDuration = (sLastTrackLengthMS << 7) / 1000; + } + PlayEmotion(expression, expressionDuration); + } +} +// 4948B1: using guessed type int var_1C[5]; + +//----- (00494A25) -------------------------------------------------------- +void Player::PlayEmotion(CHARACTER_EXPRESSION_ID new_expression, int a3) +{ + unsigned int v3 = expression; + if (expression == CHARACTER_EXPRESSION_DEAD || expression == CHARACTER_EXPRESSION_ERADICATED) + { + return; + } + else if (expression == CHARACTER_EXPRESSION_PERTIFIED && new_expression != CHARACTER_EXPRESSION_FALLING) + { + return; + } + else + { + if (expression != CHARACTER_EXPRESSION_SLEEP || new_expression != CHARACTER_EXPRESSION_FALLING) + { + if (v3 >= 2 && v3 <= 11 && v3 != 8 && !(new_expression == CHARACTER_EXPRESSION_DMGRECVD_MINOR || new_expression == CHARACTER_EXPRESSION_DMGRECVD_MODERATE || new_expression == CHARACTER_EXPRESSION_DMGRECVD_MAJOR)) + { + return; + } + } + } + this->uExpressionTimePassed = 0; + if ( !a3 ) + { + this->uExpressionTimeLength = 8 * pPlayerFrameTable->pFrames[a3].uAnimLength; + } + else + { + this->uExpressionTimeLength = 0; + } + expression = new_expression; + viewparams->bRedrawGameUI = 1; +} + +//----- (0049327B) -------------------------------------------------------- +bool Player::ProfessionOrGuildFlagsCorrect( unsigned int uClass, int a3 ) +{ + if ( this->classType == uClass ) + { + return true; + } + else + { + if (!a3) + { + return false; + } + switch ( uClass ) + { + case 0x1Au: + return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 65)); + case 0x1Bu: + return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 67)); + case 0x22u: + return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 77)); + case 0x23u: + return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 79)); + break; + default: + Error("Should not be able to get here (%u)", uClass); + break; + } + return false; + } +} + + +//----- (00492C0B) -------------------------------------------------------- +bool Player::CanAct() +{ + if ( this->IsAsleep() || this->IsParalyzed() || + this->IsUnconcious() || this->IsDead() || + this->IsPertified() || this->IsEradicated() ) + return false; + else + return true; +} + +//----- (00492C40) -------------------------------------------------------- +bool Player::CanSteal() +{ + return GetActualSkillLevel(PLAYER_SKILL_STEALING) != 0; +} + +//----- (00492C4E) -------------------------------------------------------- +bool Player::CanEquip_RaceAndAlignmentCheck(unsigned int uItemID) +{ + switch (uItemID) + { + case ITEM_RELIC_ETHRICS_STAFF: + case ITEM_RELIC_OLD_NICK: + case ITEM_RELIC_TWILIGHT: return pParty->IsPartyEvil(); break; + case ITEM_RELIC_TALEDONS_HELM: + case ITEM_RELIC_JUSTICE: return pParty->IsPartyGood(); break; + case ITEM_ARTIFACT_ELFBANE: return IsRaceGoblin(); break; + case ITEM_ARTIFACT_MINDS_EYE: return IsRaceHuman(); break; + case ITEM_ELVEN_CHAINMAIL: return IsRaceElf(); break; + case ITEM_FORGE_GAUNTLETS: return IsRaceDwarf(); break; + case ITEM_ARTIFACT_HEROS_BELT: return IsMale(); break; + case ITEM_ARTIFACT_LADYS_ESCORT: return IsFemale(); break; + case ITEM_WETSUIT: return NothingOrJustBlastersEquipped(); break; + default: return 1; break; + } +} + +//----- (00492D65) -------------------------------------------------------- +void Player::SetCondition( unsigned int uConditionIdx, int a3 ) +{ + signed int player_sex; // ecx@77 + signed int remainig_player; // ebx@82 + int players_before; // [sp+10h] [bp-4h]@2 + int players_after; // [sp+20h] [bp+Ch]@82 + + if ( pConditions[uConditionIdx] ) + return; + + if (!ConditionProcessor::IsPlayerAffected(this, uConditionIdx, a3)) + { + return; + } + + switch ( uConditionIdx ) + { + case Condition_Cursed: PlaySound(SPEECH_30, 0); break; + case Condition_Weak: PlaySound(SPEECH_25, 0); break; + case Condition_Sleep: break; //nosound + case Condition_Fear: PlaySound(SPEECH_26, 0); break; + case Condition_Drunk: PlaySound(SPEECH_31, 0); break; + case Condition_Insane: PlaySound(SPEECH_29, 0); break; + case Condition_Poison_Weak: + case Condition_Poison_Medium: + case Condition_Poison_Severe: PlaySound(SPEECH_27, 0); break; + case Condition_Disease_Weak: + case Condition_Disease_Medium: + case Condition_Disease_Severe: PlaySound(SPEECH_28, 0);break; + case Condition_Paralyzed: break; //nosound + case Condition_Unconcious: + PlaySound(SPEECH_32, 0); + if ( sHealth > 0 ) + sHealth = 0; + break; + case Condition_Dead: + PlaySound(SPEECH_33, 0); + if ( sHealth > 0 ) + sHealth = 0; + if ( sMana > 0 ) + sMana = 0; + break; + case Condition_Pertified: + PlaySound(SPEECH_34, 0); + break; + case Condition_Eradicated: + PlaySound(SPEECH_35, 0); + if (sHealth > 0 ) + sHealth = 0; + if ( sMana > 0 ) + sMana = 0; + break; + case Condition_Zombie: + if ( classType == PLAYER_CLASS_LICH || IsEradicated() || IsZombie() || !IsDead()) + return; + pConditions.fill(0); + sHealth = GetMaxHealth(); + sMana = 0; + player_sex = 0; + uPrevFace = uCurrentFace; + uPrevVoiceID = uVoiceID; + if (IsMale()) + { + uCurrentFace = 23; + uVoiceID = 23; + } + else + { + uCurrentFace = 24; + uVoiceID = 24; + } + PlaySound(SPEECH_99, 0); + break; + } + + players_before = 0; + for (int i = 1; i < 5; ++i) + { + if ( pPlayers[i]->CanAct() ) + ++players_before; + } + + pConditions[uConditionIdx] = pParty->uTimePlayed; + + remainig_player = 0; + players_after = 0; + for (int i = 1; i < 5; ++i) + { + if ( pPlayers[i]->CanAct() ) + { + remainig_player = i; + ++players_after; + } + } + if (( players_before == 2 ) && ( players_after == 1 )) + pPlayers[remainig_player]->PlaySound(SPEECH_107, 0);//ñêîðåå âñåãî îáíàä¸æûâàþùèé âîçãëàñ ïîñëåäíåãî + return; +} + +//----- (00492528) -------------------------------------------------------- +bool Player::CanFitItem(unsigned int uSlot, unsigned int uItemID) +{ + Texture *texture; // esi@1 + unsigned int slotWidth; // ebx@1 + unsigned int slotHeight; // [sp+1Ch] [bp+Ch]@1 + + texture = pIcons_LOD->LoadTexturePtr(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE); + slotWidth = GetSizeInInventorySlots(texture->uTextureWidth); + slotHeight = GetSizeInInventorySlots(texture->uTextureHeight); + if ( !areWeLoadingTexture ) + { + texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + Assert(slotHeight > 0 && slotWidth > 0, "Items should have nonzero dimensions"); + if ( (slotWidth + uSlot % INVETORYSLOTSWIDTH) <= INVETORYSLOTSWIDTH && (slotHeight + uSlot / INVETORYSLOTSWIDTH) <= INVETORYSLOTSHEIGHT ) + { + for (unsigned int x = 0; x < slotWidth; x++) + { + for (unsigned int y = 0; y < slotHeight; y++) + { + if (pInventoryMatrix[y * INVETORYSLOTSWIDTH + x + uSlot] != 0) + { + return false; + } + } + } + return true; + } + return false; +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (004925E6) -------------------------------------------------------- +int Player::FindFreeInventoryListSlot() +{ + for (int i = 0; i < 126; i++ ) + { + if (pInventoryItemList[i].uItemID == 0) + { + return i; + } + } + return -1; +} + +//----- (00492600) -------------------------------------------------------- +int Player::CreateItemInInventory(unsigned int uSlot, unsigned int uItemID) +{ + int result; // eax@8 + signed int freeSlot; // [sp+8h] [bp-4h]@4 + + freeSlot = FindFreeInventoryListSlot(); + if ( freeSlot == -1 ) + { + if ( uActiveCharacter ) + pPlayers[uActiveCharacter]->PlaySound(SPEECH_NoRoom, 0); + return 0; + } + else + { + PutItemArInventoryIndex(uItemID, freeSlot, uSlot); + result = freeSlot + 1; + this->pInventoryItemList[freeSlot].uItemID = uItemID; + } + return result; +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (00492700) -------------------------------------------------------- +int Player::HasSkill(unsigned int uSkillType) +{ + if ( uSkillType >= 37 || this->pActiveSkills[uSkillType] ) + { + return 1; + } + else + { + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[67], this->pName); + ShowStatusBarString(pTmpBuf.data(), 2u); + return 0; + } +} + +//----- (00492745) -------------------------------------------------------- +void Player::WearItem( unsigned int uItemID ) +{ + int item_body_anch; // edi@6 + int item_indx; + item_indx = FindFreeInventoryListSlot(); + + if ( item_indx != -1 ) + { + pInventoryItemList[item_indx].uItemID = uItemID; + item_body_anch = pEquipTypeToBodyAnchor[pItemsTable->pItems[uItemID].uEquipType]; + pEquipment.pIndices[item_body_anch] = item_indx + 1; + pInventoryItemList[item_indx].uBodyAnchor = item_body_anch + 1; + } +} + +//----- (004927A8) -------------------------------------------------------- +int Player::AddItem(int index, unsigned int uItemID) +{ + if ( index == -1 ) + { + for (int xcoord = 0; xcoord < INVETORYSLOTSWIDTH; xcoord++) + { + for (int ycoord = 0; ycoord < INVETORYSLOTSHEIGHT; ycoord++) + { + if ( CanFitItem(ycoord * INVETORYSLOTSWIDTH + xcoord, uItemID) ) + { + return CreateItemInInventory(ycoord * INVETORYSLOTSWIDTH + xcoord, uItemID); + } + } + } + return 0; + } + if ( !CanFitItem(index, uItemID) ) + { + pAudioPlayer->PlaySound(SOUND_error, 0, 0, -1, 0, 0, 0, 0); + return 0; + } + return CreateItemInInventory(index, uItemID); +} + +//----- (00492826) -------------------------------------------------------- +int Player::AddItem2(int index, ItemGen *Src) +{ + pItemsTable->SetSpecialBonus(Src); + + if ( index == -1 ) + { + for (int xcoord = 0; xcoord < INVETORYSLOTSWIDTH; xcoord++) + { + for (int ycoord = 0; ycoord < INVETORYSLOTSHEIGHT; ycoord++) //TODO: change pInventoryMatrix to 2 dimensional array. + { + if ( CanFitItem(ycoord * INVETORYSLOTSWIDTH + xcoord, Src->uItemID) ) + { + return CreateItemInInventory2(ycoord * INVETORYSLOTSWIDTH + xcoord, Src); + } + } + } + return 0; + } + if ( !CanFitItem(index, Src->uItemID) ) + return 0; + return CreateItemInInventory2(index, Src); +} + +//----- (0049289C) -------------------------------------------------------- +int Player::CreateItemInInventory2( unsigned int index, ItemGen *Src ) +{ + signed int freeSlot; // ebx@1 + int result; // eax@6 + + freeSlot = FindFreeInventoryListSlot(); + if ( freeSlot == -1 ) + { + result = 0; + } + else + { + PutItemArInventoryIndex(Src->uItemID, freeSlot, index); + memcpy(&pInventoryItemList[freeSlot], Src, sizeof(ItemGen)); + result = freeSlot + 1; + } + return result; +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (0049298B) -------------------------------------------------------- +void Player::PutItemArInventoryIndex( int uItemID, int itemListPos, int index ) //originally accepted ItemGen* but needed only its uItemID +{ + Texture *item_texture; // esi@1 + int *pInvPos; // esi@4 + unsigned int slot_width; // [sp+Ch] [bp-4h]@1 + unsigned int slot_height; // [sp+18h] [bp+8h]@1 + + item_texture = pIcons_LOD->LoadTexturePtr(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE); + slot_width = GetSizeInInventorySlots(item_texture->uTextureWidth); + slot_height = GetSizeInInventorySlots(item_texture->uTextureHeight); + if ( !areWeLoadingTexture ) + { + item_texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + if ( slot_width > 0 ) + { + pInvPos = &pInventoryMatrix[index]; + for (unsigned int i = 0; i < slot_height; i++) + { + memset32(pInvPos, -1 - index, slot_width);//TODO: try to come up with a better solution. negative values are used when drawing the inventory - nothing is drawn + pInvPos += INVETORYSLOTSWIDTH; + } + } + pInventoryMatrix[index] = itemListPos + 1; +} + +// 506128: using guessed type int areWeLoadingTexture; + +//----- (00492A36) -------------------------------------------------------- +void Player::RemoveItemAtInventoryIndex( unsigned int index ) +{ + ItemGen *item_in_slot; // ecx@1 + Texture *item_texture; // esi@1 + unsigned int slot_height; // ebp@1 + int *pInvPos; // edx@4 + unsigned int slot_width; // [sp+14h] [bp+4h]@1 + + item_in_slot = &this->pInventoryItemList[pInventoryMatrix[index]-1]; + item_texture = pIcons_LOD->LoadTexturePtr(item_in_slot->GetIconName(), TEXTURE_16BIT_PALETTE); + item_in_slot->Reset(); + slot_width = GetSizeInInventorySlots(item_texture->uTextureWidth); + slot_height = GetSizeInInventorySlots(item_texture->uTextureHeight); + if ( !areWeLoadingTexture ) + { + item_texture->Release(); + pIcons_LOD->SyncLoadedFilesCount(); + } + if ( slot_width > 0 ) + { + pInvPos = &pInventoryMatrix[index]; + for (unsigned int i = 0; i < slot_height; i++) + { + memset32(pInvPos, 0, slot_width); + pInvPos += INVETORYSLOTSWIDTH; + } + } +} +// 506128: using guessed type int areWeLoadingTexture; + +//----- (00490EEE) -------------------------------------------------------- +int Player::SelectPhrasesTransaction(ItemGen *pItem, int building_type, int BuildID_2Events, int ShopMenuType) //TODO: probably move this somewhere else, not really Player:: stuff +{ + unsigned int idemId; // edx@1 + signed int equipType; // esi@1 + float multiplier; // ST04_4@26 + int price; // edi@26 + int merchantLevel; // [sp+10h] [bp-8h]@1 + int itemValue; + + merchantLevel = GetActualSkillLevel(PLAYER_SKILL_MERCHANT); + idemId = pItem->uItemID; + equipType = pItem->GetItemEquipType(); + itemValue = pItem->GetValue(); + + switch (building_type) + { + case BuildingType_WeaponShop: + if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) + return 5; + if (equipType > EQUIP_BOW) + return 4; + break; + case BuildingType_ArmorShop: + if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) + return 5; + if ( equipType < EQUIP_ARMOUR || equipType > EQUIP_BOOTS) + return 4; + break; + case BuildingType_MagicShop: + if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) + return 5; + if ( pItemsTable->pItems[idemId].uSkillType != PLAYER_SKILL_MISC ) + return 4; + break; + case BuildingType_AlchemistShop: + if ((idemId >= ITEM_ARTIFACT_HERMES_SANDALS && idemId < ITEM_RECIPE_REJUVENATION) || idemId > ITEM_RECIPE_BODY_RESISTANCE) + return 5; + if ( !(equipType == EQUIP_REAGENT || equipType == EQUIP_POTION || equipType == EQUIP_MESSAGE_SCROLL)) + return 4; + break; + default: + Error("(%u)", building_type); + break; + } + if (pItem->IsStolen()) + return 6; + + multiplier = p2DEvents[BuildID_2Events - 1].fPriceMultiplier; + switch (ShopMenuType) + { + case 2: + price = GetBuyingPrice(itemValue, multiplier); + break; + case 3: + if (pItem->IsBroken()) + price = 1; + else + price = this->GetPriceSell(itemValue, multiplier); + break; + case 4: + price = this->GetPriceIdentification(multiplier); + break; + case 5: + price = this->GetPriceRepair(itemValue, multiplier); + break; + default: + Error("(%u)", ShopMenuType); + break; + } + if ( merchantLevel ) + { + if (price == itemValue) + { + return 3; + } + else + { + return 2; + } + } + else + { + return 1; + } +} + +//----- (0049107D) -------------------------------------------------------- +int Player::GetBodybuilding() +{ + int v1; // al@1 + + v1 = GetActualSkillLevel(PLAYER_SKILL_BODYBUILDING); + int multiplier = GetMultiplierForSkillLevel(v1, 1, 2, 3, 5); + return multiplier * (v1 & 0x3F); +} + +//----- (004910A8) -------------------------------------------------------- +int Player::GetMeditation() +{ + int v1; // al@1 + + v1 = GetActualSkillLevel(PLAYER_SKILL_MEDITATION); + int multiplier = GetMultiplierForSkillLevel(v1, 1, 2, 3, 5); + return multiplier * (v1 & 0x3F); +} + +//----- (004910D3) -------------------------------------------------------- +bool Player::CanIdentify( ItemGen *pItem ) +{ + unsigned __int16 v2; // ax@1 + int v5; // edi@7 + if (CheckHiredNPCSpeciality(Scholar)) + return true; + + v2 = GetActualSkillLevel(PLAYER_SKILL_ITEM_ID); + if ( (signed int)SkillToMastery(v2) >= 4 ) + return true; + + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + v5 = multiplier * (v2 & 0x3F); + return v5 >= pItemsTable->pItems[pItem->uItemID].uItemID_Rep_St; +} + +//----- (00491151) -------------------------------------------------------- +bool Player::CanRepair( ItemGen *pItem ) +{ + unsigned __int16 v2; // ax@1 + int v5; // edi@7 + + ITEM_EQUIP_TYPE equipType = pItem->GetItemEquipType(); + if (CheckHiredNPCSpeciality(Smith) && equipType <= 2 || + CheckHiredNPCSpeciality(Armorer) && equipType >= 3 && equipType <= 9 || + CheckHiredNPCSpeciality(Alchemist) && equipType >= 9 ) + return true; + + v2 = GetActualSkillLevel(PLAYER_SKILL_REPAIR); + if ( (signed int)SkillToMastery(v2) >= 4 ) + return true; + + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + v5 = multiplier * (v2 & 0x3F); + return v5 >= pItemsTable->pItems[pItem->uItemID].uItemID_Rep_St; +} + +//----- (004911F3) -------------------------------------------------------- +int Player::GetMerchant() +{ + unsigned __int16 v2; // ax@1 + int v5; // edi@1 + int v7; // eax@3 + + v2 = GetActualSkillLevel(PLAYER_SKILL_MERCHANT); + if ( SkillToMastery(v2) >= 4 ) + return 10000; + + v7 = pParty->GetPartyReputation(); + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + v5 = multiplier * (v2 & 0x3F); + if (v5 == 0) + { + return -v7; + } + return v5 - v7 + 7; +} + +//----- (0049125A) -------------------------------------------------------- +int Player::GetPerception() +{ + unsigned __int16 v2; // ax@1 + int v5; // edi@1 + + v2 = GetActualSkillLevel(PLAYER_SKILL_PERCEPTION); + if ( SkillToMastery(v2) >= 4 ) + return 10000; + + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + v5 = multiplier * (v2 & 0x3F); + return v5; +} + +//----- (004912B0) -------------------------------------------------------- +int Player::GetDisarmTrap() +{ + unsigned __int16 v2; // ax@1 + int v5; // edi@1 + + v2 = GetActualSkillLevel(PLAYER_SKILL_TRAP_DISARM); + if ( (signed int)SkillToMastery(v2) >= 4 ) + return 10000; + + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + if ( HasEnchantedItemEquipped(35) ) //only the real skill level is supposed to be added again, not the multiplied value + multiplier++; + v5 = multiplier * (v2 & 0x3F); + return v5; +} + +//----- (00491317) -------------------------------------------------------- +char Player::GetLearningPercent() +{ + int v2; // eax@1 + + v2 = GetActualSkillLevel(PLAYER_SKILL_LEARNING); + int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); + return multiplier * v2 + 9; +} + +//----- (0048C6AF) -------------------------------------------------------- +Player::Player() +{ + memset(&pEquipment, 0, sizeof(PlayerEquipment)); + pInventoryMatrix.fill(0); + for (uint i = 0; i < 126; ++i) + pInventoryItemList[i].Reset(); + for (uint i = 0; i < 12; ++i) + pEquippedItems[i].Reset(); + + + for (uint i = 0; i < 24; ++i) + { + pPlayerBuffs[i].uSkill = 0; + pPlayerBuffs[i].uSkill = 0; + pPlayerBuffs[i].uPower = 0; + pPlayerBuffs[i].uExpireTime = 0; + pPlayerBuffs[i].uCaster = 0; + pPlayerBuffs[i].uFlags = 0; + } + + pName[0] = 0; + uCurrentFace = 0; + uVoiceID = 0; + pConditions.fill(0); + + field_BB = 0; + + uMight = uMightBonus = 0; + uIntelligence = uIntelligenceBonus = 0; + uWillpower = uWillpowerBonus = 0; + uEndurance = uEnduranceBonus = 0; + uSpeed = uSpeedBonus = 0; + uAccuracy = uAccuracyBonus = 0; + uLuck = uLuckBonus = 0; + uLevel = sLevelModifier = 0; + sAgeModifier = 0; + sACModifier = 0; + +// memset(field_1F5, 0, 30); + pure_luck_used=0; + pure_speed_used=0; + pure_intellect_used=0; + pure_endurance_used=0; + pure_willpower_used=0; + pure_accuracy_used=0; + pure_might_used=0; + + sResFireBase = sResFireBonus = 0; + sResAirBase = sResAirBonus = 0; + sResWaterBase = sResWaterBonus = 0; + sResEarthBase = sResEarthBonus = 0; + sResMagicBase = sResMagicBonus = 0; + sResSpiritBase = sResSpiritBonus = 0; + sResMindBase = sResMindBonus = 0; + sResBodyBase = sResBodyBonus = 0; + sResLightBase = sResLightBonus = 0; + sResDarkBase = sResDarkBonus = 0; + + uTimeToRecovery = 0; + + uSkillPoints = 0; + + sHealth = 0; + uFullHealthBonus = 0; + _health_related = 0; + + sMana = 0; + uFullManaBonus = 0; + _mana_related = 0; + + uQuickSpell = 0; + memset(pInstalledBeacons.data(), 0, 5 * sizeof(LloydBeacon)); + + _some_attack_bonus = 0; + field_1A91 = 0; + _melee_dmg_bonus = 0; + field_1A93 = 0; + _ranged_atk_bonus = 0; + field_1A95 = 0; + _ranged_dmg_bonus = 0; + field_1A97 = 0; + + expression = CHARACTER_EXPRESSION_INVALID; + uExpressionTimePassed = 0; + uExpressionTimeLength = 0; + + uNumDivineInterventionCastsThisDay = 0; + uNumArmageddonCasts = 0; + uNumFireSpikeCasts = 0; + + memset(field_1988, 0, sizeof(field_1988)); + memset(playerEventBits, 0, sizeof(playerEventBits)); + + field_E0 = 0; + field_E4 = 0; + field_E8 = 0; + field_EC = 0; + field_F0 = 0; + field_F4 = 0; + field_F8 = 0; + field_FC = 0; + field_100 = 0; + field_104 = 0; + + _expression21_animtime = 0; + _expression21_frameset = 0; + + lastOpenedSpellbookPage = 0; +} + + +//----- (0048C855) -------------------------------------------------------- +int Player::GetBaseStrength() +{ + return this->uMight + GetItemsBonus(CHARACTER_ATTRIBUTE_STRENGTH); +} + +//----- (0048C86C) -------------------------------------------------------- +int Player::GetBaseIntelligence() +{ + return this->uIntelligence + GetItemsBonus(CHARACTER_ATTRIBUTE_INTELLIGENCE); +} + +//----- (0048C883) -------------------------------------------------------- +int Player::GetBaseWillpower() +{ + return this->uWillpower + GetItemsBonus(CHARACTER_ATTRIBUTE_WILLPOWER); +} + +//----- (0048C89A) -------------------------------------------------------- +int Player::GetBaseEndurance() +{ + return this->uEndurance + GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE); +} + +//----- (0048C8B1) -------------------------------------------------------- +int Player::GetBaseAccuracy() +{ + return this->uAccuracy + GetItemsBonus(CHARACTER_ATTRIBUTE_ACCURACY); +} + +//----- (0048C8C8) -------------------------------------------------------- +int Player::GetBaseSpeed() +{ + return this->uSpeed + GetItemsBonus(CHARACTER_ATTRIBUTE_SPEED); +} + +//----- (0048C8DF) -------------------------------------------------------- +int Player::GetBaseLuck() +{ + return this->uLuck + GetItemsBonus(CHARACTER_ATTRIBUTE_LUCK); +} + +//----- (0048C8F6) -------------------------------------------------------- +int Player::GetBaseLevel() +{ + return this->uLevel + GetItemsBonus(CHARACTER_ATTRIBUTE_LEVEL); +} + +//----- (0048C90D) -------------------------------------------------------- +int Player::GetActualLevel() +{ + return uLevel + sLevelModifier + + GetMagicalBonus(CHARACTER_ATTRIBUTE_LEVEL) + + GetItemsBonus(CHARACTER_ATTRIBUTE_LEVEL); +} + +//----- (0048C93C) -------------------------------------------------------- +int Player::GetActualMight() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_STRENGTH, &Player::uMight, &Player::uMightBonus); +} + +//----- (0048C9C2) -------------------------------------------------------- +int Player::GetActualIntelligence() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_INTELLIGENCE, &Player::uIntelligence, &Player::uIntelligenceBonus); +} + +//----- (0048CA3F) -------------------------------------------------------- +int Player::GetActualWillpower() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_WILLPOWER, &Player::uWillpower, &Player::uWillpowerBonus); +} + +//----- (0048CABC) -------------------------------------------------------- +int Player::GetActualEndurance() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_ENDURANCE, &Player::uEndurance, &Player::uEnduranceBonus); +} + +//----- (0048CB39) -------------------------------------------------------- +int Player::GetActualAccuracy() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_ACCURACY, &Player::uAccuracy, &Player::uAccuracyBonus); +} + +//----- (0048CBB6) -------------------------------------------------------- +int Player::GetActualSpeed() +{ + return GetActualAttribute(CHARACTER_ATTRIBUTE_SPEED, &Player::uSpeed, &Player::uSpeedBonus); +} + +//----- (0048CC33) -------------------------------------------------------- +int Player::GetActualLuck() +{ + signed int npc_luck_bonus; // [sp+10h] [bp-4h]@1 + + npc_luck_bonus = 0; + if ( CheckHiredNPCSpeciality(Fool) ) + npc_luck_bonus = 5; + if ( CheckHiredNPCSpeciality(ChimneySweep) ) + npc_luck_bonus += 20; + if ( CheckHiredNPCSpeciality(Psychic) ) + npc_luck_bonus += 10; + + return GetActualAttribute(CHARACTER_ATTRIBUTE_LUCK, &Player::uLuck, &Player::uLuckBonus) + + npc_luck_bonus; +} + +//----- (new function) -------------------------------------------------------- +int Player::GetActualAttribute( CHARACTER_ATTRIBUTE_TYPE attrId, unsigned short Player::* attrValue, unsigned short Player::* attrBonus ) +{ + uint uActualAge = this->sAgeModifier + GetBaseAge(); + uint uAgeingMultiplier = 100; + for (uint i = 0; i < 4; ++i) + { + if (uActualAge >= pAgeingTable[i]) + uAgeingMultiplier = pAgingAttributeModifier[attrId][i]; + else + break; + } + + uchar uConditionMult = pConditionAttributeModifier[attrId][GetMajorConditionIdx()]; + int magicBonus = GetMagicalBonus(attrId); + int itemBonus = GetItemsBonus(attrId); + return uConditionMult * uAgeingMultiplier * this->*attrValue / 100 / 100 + + magicBonus + + itemBonus + + this->*attrBonus; +} + +//----- (0048CCF5) -------------------------------------------------------- +int Player::GetActualAttack( bool a2 ) +{ + int v3; // eax@1 + int v4; // edi@1 + int v5; // ebx@1 + int v6; // ebp@1 + + v3 = GetActualAccuracy(); + v4 = GetParameterBonus(v3); + v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_ATTACK); + v6 = GetItemsBonus(CHARACTER_ATTRIBUTE_ATTACK, a2); + return v4 + v5 + v6 + GetMagicalBonus(CHARACTER_ATTRIBUTE_ATTACK) + this->_some_attack_bonus; +} + +//----- (0048CD45) -------------------------------------------------------- +int Player::GetMeleeDamageMinimal() +{ + int v2; // eax@1 + int v3; // esi@1 + int v4; // esi@1 + int v5; // esi@1 + signed int result; // eax@1 + + v2 = GetActualMight(); + v3 = GetParameterBonus(v2); + v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN) + v3; + v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v4; + result = _melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v5; + if ( result < 1 ) + result = 1; + return result; +} + +//----- (0048CD90) -------------------------------------------------------- +int Player::GetMeleeDamageMaximal() +{ + int v2; // eax@1 + int v3; // esi@1 + int v4; // esi@1 + int v5; // esi@1 + int v6; // esi@1 + signed int result; // eax@1 + + v2 = GetActualMight(); + v3 = GetParameterBonus(v2); + v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX) + v3; + v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v4; + v6 = this->_melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v5; + result = 1; + if ( v6 >= 1 ) + result = v6; + return result; +} + +//----- (0048CDDB) -------------------------------------------------------- +int Player::CalculateMeleeDamageTo( bool ignoreSkillBonus, bool ignoreOffhand, unsigned int uTargetActorID ) +{ + int dmgSum; // esi@62 + signed int result; // eax@64 + int mainWpnDmg; // [sp+18h] [bp-8h]@1 + int offHndWpnDmg; // [sp+1Ch] [bp-4h]@1 + + offHndWpnDmg = 0; + mainWpnDmg = 0; + if ( IsUnarmed() ) + { + mainWpnDmg = rand() % 3 + 1; + } + else + { + if ( HasItemEquipped(EQUIP_TWO_HANDED) ) + { + ItemGen *mainHandItemGen = this->GetMainHandItem(); + int itemId = mainHandItemGen->uItemID; + bool addOneDice = false; + if ( pItemsTable->pItems[itemId].uSkillType == PLAYER_SKILL_SPEAR && !this->pEquipment.uShield ) + addOneDice = true; + mainWpnDmg = CalculateMeleeDmgToEnemyWithWeapon(mainHandItemGen, uTargetActorID, addOneDice); + } + if ( !ignoreOffhand ) + { + if ( this->HasItemEquipped(EQUIP_SINGLE_HANDED) ) + { + ItemGen *offHandItemGen = (ItemGen *)&this->pInventoryItemList[this->pEquipment.uShield - 1]; + if ( offHandItemGen->GetItemEquipType() != EQUIP_SHIELD ) + { + offHndWpnDmg = CalculateMeleeDmgToEnemyWithWeapon(offHandItemGen, uTargetActorID, false); + } + } + } + } + dmgSum = mainWpnDmg + offHndWpnDmg; + if ( !ignoreSkillBonus ) + { + int might = GetActualMight(); + int mightBonus = GetParameterBonus(might); + int mightAndSkillbonus = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + mightBonus; + dmgSum += this->_melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + mightAndSkillbonus; + } + result = 1; + if ( dmgSum >= 1 ) + result = dmgSum; + return result; +} + + +int Player::CalculateMeleeDmgToEnemyWithWeapon( ItemGen * weapon, unsigned int uTargetActorID , bool addOneDice ) +{ + int itemId = weapon->uItemID; + int diceCount = pItemsTable->pItems[itemId].uDamageDice; + if (addOneDice) + { + diceCount++; + } + int diceSides = pItemsTable->pItems[itemId].uDamageRoll; + int diceResult = 0; + for (int i = 0; i < diceCount; i++) + { + diceResult += rand() % diceSides + 1; + } + int totalDmg = pItemsTable->pItems[itemId].uDamageMod + diceResult; + if ( uTargetActorID > 0) + { + int enchType = weapon->uSpecEnchantmentType; + if ( MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_UNDEAD) && (enchType == 64 || itemId == ITEM_ARTIFACT_GHOULSBANE || itemId == ITEM_ARTIFACT_GIBBET || itemId == ITEM_RELIC_JUSTICE) ) + { + totalDmg *= 2; + } + else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_KREEGAN) && ( enchType == 39 || itemId == ITEM_ARTIFACT_GIBBET)) + { + totalDmg *= 2; + } + else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_DRAGON) && ( enchType == 40 || itemId == ITEM_ARTIFACT_GIBBET)) + { + totalDmg *= 2; + } + else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_ELF) && ( enchType == 63 || itemId == ITEM_RELIC_OLD_NICK)) + { + totalDmg *= 2; + } + else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_TITAN) && ( enchType == 65 )) + { + totalDmg *= 2; + } + } + if ( (signed int)SkillToMastery(this->pActiveSkills[PLAYER_SKILL_DAGGER]) >= 3 + && pItemsTable->pItems[itemId].uSkillType == 2 + && rand() % 100 < 10 ) + totalDmg *= 3; + return totalDmg; +} + + +//----- (0048D0B9) -------------------------------------------------------- +int Player::GetRangedAttack() +{ + int v3; // edi@3 + //int v4; // eax@4 + //int v5; // edi@4 + int v6; // edi@4 + int v7; // edi@4 + + ItemGen* mainHandItem = GetMainHandItem(); + if ( mainHandItem != nullptr && ( mainHandItem->uItemID < ITEM_BLASTER || mainHandItem->uItemID > ITEM_LASER_RIFLE )) + { + //v4 = GetActualAccuracy(); + //v5 = GetParameterBonus(GetActualAccuracy()); + v6 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + GetParameterBonus(GetActualAccuracy()); + v7 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + v6; + v3 = this->_ranged_atk_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + v7; + } + else + { + v3 = GetActualAttack(true); + } + return v3; +} + +//----- (0048D124) -------------------------------------------------------- +int Player::GetRangedDamageMin() +{ + int v2; // edi@1 + int v3; // edi@1 + int v4; // edi@1 + int result; // eax@6 + + v2 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_MIN); + v3 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v2; + v4 = this->_ranged_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v3; + if ( v4 >= 1 ) + result = v4; + else + result = 0; + return result; +} + +//----- (0048D191) -------------------------------------------------------- +int Player::GetRangedDamageMax() +{ + int v2; // edi@1 + int v3; // edi@1 + int v4; // edi@1 + int result; // eax@6 + + v2 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_MAX); + v3 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v2; + v4 = this->_ranged_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v3; + if ( v4 >= 1 ) + result = v4; + else + result = 0; + return result; +} + +//----- (0048D1FE) -------------------------------------------------------- +int Player::CalculateRangedDamageTo( int a2 ) +{ + ItemGen *v4; // ebx@2 + unsigned int v5; // edi@2 + int v9; // esi@5 + int v10; // ebx@6 + signed int v15; // [sp+8h] [bp-Ch]@2 + int v17; // [sp+10h] [bp-4h]@1 + + v17 = 0; + if ( !HasItemEquipped(EQUIP_BOW) ) + return 0; + v4 = (ItemGen *)&this->pInventoryItemList[this->pEquipment.uBow-1]; + v5 = v4->uItemID; + v15 = pItemsTable->pItems[v5].uDamageRoll; + for( int i = 0; i < pItemsTable->pItems[v5].uDamageDice; i++ ) + { + int v7 = rand() % v15; + v17 += v7 + 1; + } + v9 = pItemsTable->pItems[v5].uDamageMod + v17; + if ( a2 ) + { + v10 = v4->uSpecEnchantmentType; + if ( v10 == 64 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_UNDEAD)) + { + v9 *= 2; + } + else if ( v10 == 39 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_KREEGAN)) + { + v9 *= 2; + } + else if ( v10 == 40 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_DRAGON)) + { + v9 *= 2; + } + else if ( v10 == 63 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_ELF)) + { + v9 *= 2; + } + } + return v9 + this->GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS); +} + +//----- (0048D2EA) -------------------------------------------------------- +char *Player::GetMeleeDamageString() +{ + int min_damage; // edi@3 + int max_damage; // eax@3 + + static char player__getmeleedamagestring_static_buff[40]; // idb + + ItemGen* mainHandItem = GetMainHandItem(); + + if (mainHandItem != nullptr && ( mainHandItem->uItemID >= 135 ) && ( mainHandItem->uItemID <= 159 )) + { + strcpy(player__getmeleedamagestring_static_buff, pGlobalTXT_LocalizationStrings[595]); //"Wand" + return player__getmeleedamagestring_static_buff; + } + else if (mainHandItem != nullptr && (mainHandItem->uItemID == ITEM_BLASTER || mainHandItem->uItemID == ITEM_LASER_RIFLE)) + { + min_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN, true); + max_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX, true); + } + else + { + min_damage = GetMeleeDamageMinimal(); + max_damage = GetMeleeDamageMaximal(); + } + if ( min_damage == max_damage ) + { + sprintf(player__getmeleedamagestring_static_buff, "%d", min_damage); + } + else + { + sprintf(player__getmeleedamagestring_static_buff, "%d - %d", min_damage, max_damage); + } + return player__getmeleedamagestring_static_buff; +} + +//----- (0048D396) -------------------------------------------------------- +char *Player::GetRangedDamageString() +{ + int min_damage; // edi@3 + int max_damage; // eax@3 + + static char player__getrangeddamagestring_static_buff[40]; // idb + + ItemGen* mainHandItem = GetMainHandItem(); + + if (mainHandItem != nullptr && ( mainHandItem->uItemID >= 135 ) && ( mainHandItem->uItemID <= 159 )) + { + strcpy(player__getrangeddamagestring_static_buff, pGlobalTXT_LocalizationStrings[595]); //"Wand" + return player__getrangeddamagestring_static_buff; + } + else if (mainHandItem != nullptr && (mainHandItem->uItemID == ITEM_BLASTER || mainHandItem->uItemID == ITEM_LASER_RIFLE)) + { + min_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN, true); + max_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX, true); + } + else + { + min_damage = GetRangedDamageMin(); + max_damage = GetRangedDamageMax(); + } + if ( max_damage > 0) + { + if ( min_damage == max_damage ) + { + sprintf(player__getrangeddamagestring_static_buff, "%d", min_damage); + } + else + { + sprintf(player__getrangeddamagestring_static_buff, "%d - %d", min_damage, max_damage); + } + } + else + { + strcpy(player__getrangeddamagestring_static_buff, "N/A"); + } + return player__getrangeddamagestring_static_buff; +} + +//----- (0048D45A) -------------------------------------------------------- +bool Player::CanTrainToNextLevel() +{ + int lvl = this->uLevel + 1; + int neededExp = ((lvl * (lvl - 1)) / 2 * 1000); + return this->uExperience >= neededExp; +} + +//----- (0048D498) -------------------------------------------------------- +unsigned int Player::GetExperienceDisplayColor() +{ + if ( CanTrainToNextLevel() ) + return ui_character_bonus_text_color; + else + return ui_character_default_text_color; +} + +//----- (0048D4B3) -------------------------------------------------------- +int Player::CalculateIncommingDamage( DAMAGE_TYPE dmg_type, int dmg ) +{ + int resist_value; // edi@8 + int player_luck; // eax@21 + signed int res_rand_divider; // ebx@2 + int armor_skill; // eax@29 + + if ( classType == PLAYER_CLASS_LICH && (dmg_type == CHARACTER_ATTRIBUTE_RESIST_MIND || dmg_type == CHARACTER_ATTRIBUTE_RESIST_BODY || dmg_type == CHARACTER_ATTRIBUTE_RESIST_SPIRIT )) //TODO: determine if spirit resistance should be handled by body res. modifier + return 0; + + resist_value = 0; + switch(dmg_type) + { + case DMGT_FIRE: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_FIRE); break; + case DMGT_ELECTR: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_AIR); break; + case DMGT_COLD: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_WATER); break; + case DMGT_EARTH: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_EARTH); break; + + case DMGT_SPIRIT: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_SPIRIT);break; + case DMGT_MIND: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_MIND); break; + case DMGT_BODY: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_BODY); break; + } + + player_luck = GetActualLuck(); + res_rand_divider = GetParameterBonus(player_luck) + resist_value + 30; + + if ( GetParameterBonus(player_luck) + resist_value > 0 ) + { + for (int i = 0; i < 4; i++) + { + if ( rand() % res_rand_divider >= 30 ) + dmg >>= 1; + else + break; + } + } + ItemGen* equippedArmor = GetArmorItem(); + if (( dmg_type == DMGT_PHISYCAL ) && ( equippedArmor != nullptr )) + { + if (!equippedArmor->IsBroken()) + { + armor_skill = equippedArmor->GetPlayerSkillType(); + if ( armor_skill==PLAYER_SKILL_PLATE ) + { + if ( SkillToMastery(pActiveSkills[PLAYER_SKILL_PLATE]) >= 3 ) + return dmg / 2; + } + if (armor_skill==PLAYER_SKILL_CHAIN ) + { + if (SkillToMastery(pActiveSkills[PLAYER_SKILL_CHAIN]) == 4) + return dmg * 2 / 3; + } + } + } + return dmg; +} + +//----- (0048D62C) -------------------------------------------------------- +ITEM_EQUIP_TYPE Player::GetEquippedItemEquipType(ITEM_EQUIP_TYPE uEquipSlot) +{ + return GetNthEquippedIndexItem(uEquipSlot)->GetItemEquipType(); +} + +//----- (0048D651) -------------------------------------------------------- +PLAYER_SKILL_TYPE Player::GetEquippedItemSkillType(ITEM_EQUIP_TYPE uEquipSlot) +{ + return (PLAYER_SKILL_TYPE)GetNthEquippedIndexItem(uEquipSlot)->GetPlayerSkillType(); +} + +//----- (0048D676) -------------------------------------------------------- +bool Player::IsUnarmed() +{ + return !HasItemEquipped(EQUIP_TWO_HANDED) && + (!HasItemEquipped(EQUIP_SINGLE_HANDED) || GetOffHandItem()->GetItemEquipType() == EQUIP_SHIELD); +} + +//----- (0048D6AA) -------------------------------------------------------- +bool Player::HasItemEquipped(ITEM_EQUIP_TYPE uEquipIndex) +{ + uint i = pEquipment.pIndices[uEquipIndex]; + if (i) + return !pOwnItems[i - 1].IsBroken(); + else + return false; +} + +//----- (0048D6D0) -------------------------------------------------------- +bool Player::HasEnchantedItemEquipped(int uEnchantment) +{ + for (uint i = 0; i < 16; ++i) + { + if (HasItemEquipped((ITEM_EQUIP_TYPE)i) && + GetNthEquippedIndexItem(i)->uSpecEnchantmentType == uEnchantment) + return true; + } + return false; +} + +//----- (0048D709) -------------------------------------------------------- +bool Player::WearsItem( int item_id, ITEM_EQUIP_TYPE equip_type ) +{ + return ( HasItemEquipped(equip_type) && GetNthEquippedIndexItem(equip_type)->uItemID == item_id ); +} + +bool Player::WearsItemAnyWhere(int item_id) +{ + for (int i = 0; i < 16; i++) + { + if (WearsItem(item_id, (ITEM_EQUIP_TYPE) i)) + { + return true; + } + } + return false; +} + +//----- (0048D76C) -------------------------------------------------------- +int Player::StealFromShop( ItemGen *itemToSteal, int extraStealDifficulty, int reputation, int a5, int *fineIfFailed ) //returns an int, but is the return value is compared to zero, so might change to bool +{ + unsigned __int16 v6; // cx@8 + int v7; // edi@8 + unsigned int v8; // ebx@8 + unsigned int itemvalue; // esi@8 + int v10; // eax@8 + int currMaxItemValue; // edi@12 + + if ( !itemToSteal + || this->IsEradicated() + || this->IsDead() + || this->IsPertified() + || this->IsDrunk() + || this->IsUnconcious() + || this->IsAsleep() ) + { + return 0; + } + else + { + v6 = this->pActiveSkills[PLAYER_SKILL_STEALING]; + v7 = v6 & 0x3F; + v8 = SkillToMastery(v6); + itemvalue = itemToSteal->GetValue(); + v10 = itemToSteal->GetItemEquipType(); + if ( v10 == EQUIP_SINGLE_HANDED || v10 == EQUIP_TWO_HANDED || v10 == EQUIP_BOW ) + itemvalue *= 3; + currMaxItemValue = StealingRandomBonuses[rand() % 5] + v7 * StealingMasteryBonuses[v8]; + *fineIfFailed = 100 * (reputation + extraStealDifficulty) + itemvalue; + if (a5) + { + *fineIfFailed += 500; + } + if ( rand() % 100 >= 5 ) + { + if ( *fineIfFailed > currMaxItemValue ) + if (*fineIfFailed - currMaxItemValue < 500) + { + return 1; + } + else + { + return 0; + } + else + return 2; + } + else + { + return 0; + } + } +} + +//----- (0048D88B) -------------------------------------------------------- +int Player::StealFromActor(unsigned int uActorID, int _steal_perm, int reputation) +{ + Actor *actroPtr; // edi@1 + int v7; // ebx@10 + unsigned int stealingMastery; // esi@10 + int fineIfFailed; // esi@10 + int v11; // eax@13 + bool HasFullItemSlots; // ebx@15 + unsigned __int16 carriedItemId; // si@21 + unsigned int enchBonusSum; // esi@31 + int *enchTypePtr; // eax@34 + ItemGen tempItem; // [sp+8h] [bp-34h]@15 + int currMaxItemValue; + + actroPtr = &pActors[uActorID]; + if ( !actroPtr + || this->IsEradicated() + || this->IsDead() + || this->IsPertified() + || this->IsDrunk() + || this->IsUnconcious() + || this->IsAsleep() ) + { + return 0; + } + if ( !actroPtr->ActorHasItem() ) + actroPtr->SetRandomGoldIfTheresNoItem(); + unsigned __int16 v6 = this->pActiveSkills[PLAYER_SKILL_STEALING]; + v7 = v6 & 0x3F; + stealingMastery = SkillToMastery(v6); + int v30 = StealingMasteryBonuses[stealingMastery]; + int v29 = StealingRandomBonuses[rand() % 5]; + fineIfFailed = actroPtr->pMonsterInfo.uLevel + 100 * (_steal_perm + reputation); + currMaxItemValue = v29 + v7 * v30; + if ( rand() % 100 < 5 || fineIfFailed > currMaxItemValue || actroPtr->ActorEnemy() ) + { + Actor::AggroSurroundingPeasants(uActorID, 1); + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[376], this->pName);//"%s was caught stealing!" + ShowStatusBarString(pTmpBuf2.data(), 2); + return 0; + } + else + { + v11 = rand(); + if ( v11 % 100 >= 70 ) //stealing gold + { + enchBonusSum = 0; + for (int i = 0; i < v7; i++) + enchBonusSum += rand() % StealingEnchantmentBonusForSkill[stealingMastery] + 1; + if ( actroPtr->ActorHasItems[3].GetItemEquipType() != EQUIP_GOLD ) + return 2; + enchTypePtr = &actroPtr->ActorHasItems[3].uSpecEnchantmentType; + if ( (int)enchBonusSum >= *enchTypePtr ) + { + actroPtr->ActorHasItems[3].uItemID = 0; + *enchTypePtr = 0; + } + else + *enchTypePtr -= enchBonusSum; + if ( enchBonusSum ) + { + pParty->PartyFindsGold(enchBonusSum, 2); + sprintf(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[302], this->pName, enchBonusSum); //%stole %d gold + } + else + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[377], this->pName); //%s failed to steal anything + ShowStatusBarString(pTmpBuf2.data(), 2); + return 2; + } + else if ( v11 % 100 >= 40 ) //stealing an item + { + tempItem.Reset(); + HasFullItemSlots = false; + int i; + for (i = 0; i < 4; i++) + { + if ( actroPtr->ActorHasItems[i].uItemID != 0 && actroPtr->ActorHasItems[i].GetItemEquipType() != EQUIP_GOLD ) + break; + } + if (i == 4) + HasFullItemSlots = true; + carriedItemId = actroPtr->uCarriedItemID; + if ( carriedItemId != 0 || HasFullItemSlots ) + { + tempItem.Reset(); + if ( carriedItemId != 0 ) + { + actroPtr->uCarriedItemID = 0; + tempItem.uItemID = carriedItemId; + if ( pItemsTable->pItems[carriedItemId].uEquipType == EQUIP_WAND ) + tempItem.uNumCharges = rand() % 6 + pItemsTable->pItems[carriedItemId].uDamageMod + 1; + else if ( pItemsTable->pItems[carriedItemId].uEquipType == EQUIP_POTION && carriedItemId != ITEM_POTION_BOTTLE) + tempItem.uEnchantmentType = 2 * rand() % 4 + 2; + } + else + { + ItemGen* itemToSteal = &actroPtr->ActorHasItems[rand() % 4]; + memcpy(&tempItem, itemToSteal, sizeof(tempItem)); + itemToSteal->Reset(); + carriedItemId = tempItem.uItemID; + } + if (carriedItemId != 0) // looks odd in current context, but avoids accessing zeroth element of pItemsTable->pItems + { + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + sprintf( + pTmpBuf2.data(), + pGlobalTXT_LocalizationStrings[304], // Official //TODO: add a normal "%d stole %d" message + this->pName, + pItemsTable->pItems[carriedItemId].pUnidentifiedName); + ShowStatusBarString(pTmpBuf2.data(), 2u); + pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); + memcpy(&pParty->pPickedItem, &tempItem, sizeof(ItemGen)); + pMouse->SetCursorBitmapFromItemID(carriedItemId); + return 2; + } + } + } + sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[377], this->pName); //%s failed to steal anything + ShowStatusBarString(pTmpBuf2.data(), 2); + return 2; + } +} +// 4EDEA0: using guessed type int dword_4EDEA0[]; +// 4EDEB4: using guessed type int dword_4EDEB4[]; +// 4EDEC4: using guessed type int dword_4EDEC4[]; + +//----- (0048DBB9) -------------------------------------------------------- +void Player::Heal(int amount) +{ + signed int max_health; // eax@3 + + if ( !IsEradicated() && !IsDead() ) + { + max_health = GetMaxHealth(); + if ( IsZombie() ) + max_health /= 2; + sHealth += amount; + if ( sHealth > max_health ) + sHealth = max_health; + if ( IsUnconcious() ) + { + if ( sHealth > 0 ) + { + SetUnconcious(false); + } + } + } +} + +//----- (0048DC1E) -------------------------------------------------------- +int Player::ReceiveDamage( signed int amount, DAMAGE_TYPE dmg_type ) + { + signed int recieved_dmg; // eax@1 + bool broke_armor; + + SetAsleep(false); + recieved_dmg = CalculateIncommingDamage(dmg_type, amount); + sHealth -= recieved_dmg; + broke_armor = sHealth <= -10; + if ( sHealth < 1 ) // + { + if ( (sHealth + uEndurance + GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE) >= 1) + || pPlayerBuffs[PLAYER_BUFF_PRESERVATION].uExpireTime > 0 ) + { + SetCondUnconsciousWithBlockCheck(false); + } + else + { + SetCondDeadWithBlockCheck(false); + if ( sHealth > 0 ) + sHealth = 0; + } + if (broke_armor ) + { + ItemGen* equippedArmor = GetArmorItem(); + if ( equippedArmor != nullptr ) + { + if ( !(equippedArmor->uAttributes & ITEM_HARDENED)) + { + equippedArmor->SetBroken(); + } + } + } + } + if ( recieved_dmg && CanAct() ) + PlaySound(SPEECH_24, 0); + return recieved_dmg; +} + +//----- (0048DCF6) -------------------------------------------------------- +int Player::ReceiveSpecialAttackEffect( int attType, struct Actor *pActor ) +{ + SPECIAL_ATTACK_TYPE attTypeCast = (SPECIAL_ATTACK_TYPE) attType; + signed int v3; // edi@1 + signed int v4; // ebx@1 + int v6; // eax@2 + int v8; // eax@8 + int v10; // eax@8 + int v11; // ebx@8 + ItemGen *v13; // eax@9 + int v22; // eax@49 + signed int v23; // ebx@49 + void *v27; // ecx@76 + char v46[140]; // [sp+Ch] [bp-94h]@13 + unsigned int v47; // [sp+98h] [bp-8h]@1 + ItemGen* v48; // [sp+9Ch] [bp-4h]@1 + + v4 = 0; + v47 = 0; + v48 = nullptr; + switch ( attTypeCast ) + { + case SPECIAL_ATTACK_CURSE: + v6 = GetActualWillpower(); + v11 = GetParameterBonus(v6); + break; + case SPECIAL_ATTACK_WEAK: + case SPECIAL_ATTACK_SLEEP: + case SPECIAL_ATTACK_DRUNK: + case SPECIAL_ATTACK_DISEASE_WEAK: + case SPECIAL_ATTACK_DISEASE_MEDIUM: + case SPECIAL_ATTACK_DISEASE_SEVERE: + case SPECIAL_ATTACK_UNCONSCIOUS: + case SPECIAL_ATTACK_AGING: + v6 = GetActualEndurance(); + v11 = GetParameterBonus(v6); + break; + case SPECIAL_ATTACK_INSANE: + case SPECIAL_ATTACK_PARALYZED: + case SPECIAL_ATTACK_FEAR: + v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_MIND); + break; + case SPECIAL_ATTACK_PETRIFIED: + v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_EARTH); + break; + case SPECIAL_ATTACK_POISON_WEAK: + case SPECIAL_ATTACK_POISON_MEDIUM: + case SPECIAL_ATTACK_POISON_SEVERE: + case SPECIAL_ATTACK_DEAD: + case SPECIAL_ATTACK_ERADICATED: + v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_BODY); + break; + case SPECIAL_ATTACK_MANA_DRAIN: + v8 = GetActualWillpower(); + v10 = GetActualIntelligence(); + v11 = (GetParameterBonus(v10) + GetParameterBonus(v8)) / 2; + break; + case SPECIAL_ATTACK_BREAK_ANY: + for (int i = 0; i < 138; i++) + { + v13 = &this->pInventoryItemList[i]; + if ( v13->uItemID > 0 && v13->uItemID <= 134 && !v13->IsBroken()) + v46[v4++] = i; + } + if ( !v4 ) + return 0; + v48 = &this->pInventoryItemList[v46[rand() % v4]]; + v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); + break; + case SPECIAL_ATTACK_BREAK_ARMOR: + for (int i = 0; i < 16; i++ ) + { + if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + if ( i == EQUIP_ARMOUR ) + v46[v4++] = this->pEquipment.uArmor - 1; + if ( (i == EQUIP_SINGLE_HANDED || i == EQUIP_TWO_HANDED) && GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_SHIELD ) + v46[v4++] = this->pEquipment.pIndices[i] - 1; + } + } + if ( !v4 ) + return 0; + v48 = &this->pInventoryItemList[v46[rand() % v4]]; + v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); + break; + case SPECIAL_ATTACK_BREAK_WEAPON: + for (int i = 0; i < 16; i++ ) + { + if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + if ( i == EQUIP_BOW ) + v46[v4++] = LOBYTE(this->pEquipment.uBow) - 1; + if ( (i == EQUIP_SINGLE_HANDED || i == EQUIP_TWO_HANDED) + && (GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_SINGLE_HANDED || GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_TWO_HANDED) ) + v46[v4++] = this->pEquipment.pIndices[i] - 1; + } + } + if ( !v4 ) + return 0; + v48 = &this->pInventoryItemList[v46[rand() % v4]]; + v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); + break; + case SPECIAL_ATTACK_STEAL: + for ( int i = 0; i < 126; i++ ) + { + int ItemPosInList = this->pInventoryMatrix[i]; + if (ItemPosInList > 0) + { + ItemGen* v21 = &this->pInventoryItemList[ItemPosInList - 1]; + if ( v21->uItemID > 0 && v21->uItemID <= 134 ) + { + v46[v4++] = i; + } + } + } + if ( !v4 ) + return 0; + v47 = v46[rand() % v4]; + v6 = GetActualAccuracy(); + v11 = GetParameterBonus(v6); + break; + default: + v11 = 0; + break; + } + v22 = GetActualLuck(); + v23 = GetParameterBonus(v22) + v11 + 30; + if ( rand() % v23 >= 30 ) + { + return 0; + } + else + { + for ( v3 = 0; v3 < 4; v3++ ) + { + if ( this == pPlayers[v3 + 1] ) + break; + } + + switch ( attTypeCast ) + { + case SPECIAL_ATTACK_CURSE: + SetCondition(Condition_Cursed, 1); + pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_WEAK: + SetCondition(Condition_Weak, 1); + pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_SLEEP: + SetCondition(Condition_Sleep, 1); + pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_DRUNK: + SetCondition(Condition_Drunk, 1); + pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_INSANE: + SetCondition(Condition_Insane, 1); + pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_POISON_WEAK: + SetCondition(Condition_Poison_Weak, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_POISON_MEDIUM: + SetCondition(Condition_Poison_Medium, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_POISON_SEVERE: + SetCondition(Condition_Poison_Severe, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_DISEASE_WEAK: + SetCondition(Condition_Disease_Weak, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_DISEASE_MEDIUM: + SetCondition(Condition_Disease_Medium, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_DISEASE_SEVERE: + SetCondition(Condition_Disease_Severe, 1); + pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_PARALYZED: + SetCondition(Condition_Paralyzed, 1); + pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_UNCONSCIOUS: + SetCondition(Condition_Unconcious, 1); + pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_DEAD: + SetCondition(Condition_Dead, 1); + pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_PETRIFIED: + SetCondition(Condition_Pertified, 1); + pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_ERADICATED: + SetCondition(Condition_Eradicated, 1); + pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_BREAK_ANY: + case SPECIAL_ATTACK_BREAK_ARMOR: + case SPECIAL_ATTACK_BREAK_WEAPON: + if ( !(v48->uAttributes & ITEM_HARDENED) ) + { + PlaySound(SPEECH_40, 0); + v48->SetBroken(); + pAudioPlayer->PlaySound((SoundID)47, 0, 0, -1, 0, 0, 0, 0); + } + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_STEAL: + PlaySound(SPEECH_40, 0); + v27 = pActor->ActorHasItems; + if ( pActor->ActorHasItems[0].uItemID ) + { + v27 = &pActor->ActorHasItems[1]; + if ( pActor->ActorHasItems[1].uItemID ) + { + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + } + } + memcpy(v27, &this->pInventoryItemList[this->pInventoryMatrix[v47]-1], 0x24u); + RemoveItemAtInventoryIndex(v47); + pAudioPlayer->PlaySound((SoundID)47, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_AGING: + PlaySound(SPEECH_42, 0); + ++this->sAgeModifier; + pAudioPlayer->PlaySound((SoundID)226, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_MANA_DRAIN: + PlaySound(SPEECH_41, 0); + this->sMana = 0; + pAudioPlayer->PlaySound((SoundID)226, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + case SPECIAL_ATTACK_FEAR: + SetCondition(Condition_Fear, 1); + pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); + pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); + return 1; + break; + default: + return 0; + } + } +} + +// 48DCF6: using guessed type char var_94[140]; + +//----- (0048E1A3) -------------------------------------------------------- +unsigned int Player::GetSpellSchool(unsigned int uSpellID) +{ + return pSpellStats->pInfos[uSpellID].uSchool; +} + +//----- (0048E1B5) -------------------------------------------------------- +int Player::GetAttackRecoveryTime(bool bRangedAttack) +{ + ItemGen *weapon = nullptr; + uint weapon_recovery = base_recovery_times_per_weapon_type[0]; + if (bRangedAttack) + { + if ( HasItemEquipped(EQUIP_BOW) ) + { + weapon = GetBowItem(); + weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; + } + } + else if ( IsUnarmed() == 1 && GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) + { + weapon_recovery = base_recovery_times_per_weapon_type[1]; + } + else if ( HasItemEquipped(EQUIP_TWO_HANDED) ) + { + weapon = GetMainHandItem(); + if (weapon->GetItemEquipType() == EQUIP_WAND) + { + __debugbreak(); // looks like offset in player's inventory and wand_lut much like case in 0042ECB5 + __debugbreak(); // looks like wands were two-handed weapons once, or supposed to be. should not get here now + weapon_recovery = pSpellDatas[wand_spell_ids[weapon->uItemID - ITEM_WAND_FIRE]].uExpertLevelRecovery; + } + else + weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; + } + if (HasItemEquipped(EQUIP_SINGLE_HANDED) && GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) != EQUIP_SHIELD) + // ADD: shield check because shield recovery is added later and can be accidentally doubled + { + if (base_recovery_times_per_weapon_type[GetOffHandItem()->GetPlayerSkillType()] > weapon_recovery) + { + weapon = GetOffHandItem(); + weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; + } + } + + uint armour_recovery = 0; + if ( HasItemEquipped(EQUIP_ARMOUR) ) + { + uchar armour_skill_type = GetArmorItem()->GetPlayerSkillType(); + uint base_armour_recovery = base_recovery_times_per_weapon_type[armour_skill_type]; + float multiplier; + + if (armour_skill_type == PLAYER_SKILL_LEATHER) + { + multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0, 0, 0); + } + else if (armour_skill_type == PLAYER_SKILL_CHAIN) + { + multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0.5f, 0, 0); + } + else if (armour_skill_type == PLAYER_SKILL_PLATE) + { + multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0.5f, 0.5f, 0); + } + else + { + Error("Unknown armour type"); // what kind of armour is that? + multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 1.0f, 1.0f, 1.0f); + } + + armour_recovery = (uint)(base_armour_recovery * multiplier); + } + + uint shield_recovery = 0; + if (HasItemEquipped(EQUIP_SINGLE_HANDED) && GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) == EQUIP_SHIELD) + { + uchar skill_type = GetOffHandItem()->GetPlayerSkillType(); + + uint shield_base_recovery = base_recovery_times_per_weapon_type[skill_type]; + float multiplier = GetArmorRecoveryMultiplierFromSkillLevel(skill_type, 1.0f, 0, 0, 0); + shield_recovery = (uint)(shield_base_recovery * multiplier); + } + + uint player_speed_recovery_reduction = GetParameterBonus(GetActualSpeed()), + sword_axe_bow_recovery_reduction = 0; + bool shooting_laser = false; + if (weapon != nullptr) + { + if (GetActualSkillLevel((PLAYER_SKILL_TYPE)weapon->GetPlayerSkillType()) && + (weapon->GetPlayerSkillType() == PLAYER_SKILL_SWORD || weapon->GetPlayerSkillType() == PLAYER_SKILL_AXE || weapon->GetPlayerSkillType() == PLAYER_SKILL_BOW) ) + { + if (SkillToMastery(pActiveSkills[weapon->GetPlayerSkillType()]) >= 2 ) // Expert Sword, Axe & Bow reduce recovery + sword_axe_bow_recovery_reduction = pActiveSkills[weapon->GetPlayerSkillType()] & 0x3F; + } + if (weapon->GetPlayerSkillType() == PLAYER_SKILL_BLASTER) + shooting_laser = true; + } + + uint armsmaster_recovery_reduction = 0; + if (!bRangedAttack && !shooting_laser) + { + if (uint armsmaster_level = GetActualSkillLevel(PLAYER_SKILL_ARMSMASTER)) + { + armsmaster_recovery_reduction = armsmaster_level & 0x3F; + if (SkillToMastery(armsmaster_level) >= 4) + armsmaster_recovery_reduction *= 2; + } + } + + uint hasteRecoveryReduction = 0; + if (pPlayerBuffs[PLAYER_BUFF_HASTE].uExpireTime > 0 || pParty->pPartyBuffs[PARTY_BUFF_HASTE].uExpireTime > 0 ) + hasteRecoveryReduction = 25; + + uint weapon_enchantment_recovery_reduction = 0; + if ( weapon ) + { + if (weapon->uSpecEnchantmentType == 59 || + weapon->uSpecEnchantmentType == 41 || + weapon->uSpecEnchantmentType == 500) + weapon_enchantment_recovery_reduction = 20; + } + + int recovery = weapon_recovery + + armour_recovery + + shield_recovery + - armsmaster_recovery_reduction + - weapon_enchantment_recovery_reduction + - hasteRecoveryReduction + - sword_axe_bow_recovery_reduction + - player_speed_recovery_reduction; + + if (recovery < 0) + recovery = 0; + return recovery; +} + + +//----- new -------------------------------------------------------- +float Player::GetArmorRecoveryMultiplierFromSkillLevel( unsigned char armour_skill_type, float mult1, float mult2, float mult3, float mult4 ) +{ + uint skill_mastery = SkillToMastery(pActiveSkills[armour_skill_type]); + switch (skill_mastery) + { + case 1: return mult1; break; + case 2: return mult2; break; + case 3: return mult3; break; + case 4: return mult4; break; + } + Error("Unexpected input value: %d", armour_skill_type); + return 0; +} + +//----- (0048E4F8) -------------------------------------------------------- +int Player::GetMaxHealth() +{ + int v3; // esi@1 + int v4; // esi@1 + int v6; // esi@1 + + v3 = GetParameterBonus(GetActualEndurance()); + v4 = pBaseHealthPerLevelByClass[classType] * (GetActualLevel() + v3); + v6 = uFullHealthBonus + + pBaseHealthByClass[classType / 4] + + GetSkillBonus(CHARACTER_ATTRIBUTE_HEALTH) + + GetItemsBonus(CHARACTER_ATTRIBUTE_HEALTH) + v4; + return max(1, v6); +} + +//----- (0048E565) -------------------------------------------------------- +int Player::GetMaxMana() +{ + int v2; // eax@2 + int v3; // esi@4 + int v4; // eax@5 + int v5; // esi@5 + int v6; // eax@5 + int v7; // esi@6 + int v8; // esi@6 + int v9; // esi@6 + + switch (classType) + { + case PLAYER_CLASS_ROGUE: + case PLAYER_CLASS_SPY: + case PLAYER_CLASS_ASSASSIN: + case PLAYER_CLASS_ARCHER: + case PLAYER_CLASS_WARRIOR_MAGE: + case PLAYER_CLASS_MASTER_ARCHER: + case PLAYER_CLASS_SNIPER: + case PLAYER_CLASS_SORCERER: + case PLAYER_CLASS_WIZARD: + case PLAYER_CLASS_ARCHMAGE: + case PLAYER_CLASS_LICH: + v2 = GetActualIntelligence(); + v3 = GetParameterBonus(v2); + break; + case PLAYER_CLASS_INITIATE: + case PLAYER_CLASS_MASTER: + case PLAYER_CLASS_NINJA: + case PLAYER_CLASS_PALADIN: + case PLAYER_CLASS_CRUSADER: + case PLAYER_CLASS_HERO: + case PLAYER_CLASS_VILLIAN: + case PLAYER_CLASS_CLERIC: + case PLAYER_CLASS_PRIEST: + case PLAYER_CLASS_PRIEST_OF_SUN: + case PLAYER_CLASS_PRIEST_OF_MOON: + v2 = GetActualWillpower(); + v3 = GetParameterBonus(v2); + break; + case PLAYER_CLASS_HUNTER: + case PLAYER_CLASS_RANGER_LORD: + case PLAYER_CLASS_BOUNTY_HUNTER: + case PLAYER_CLASS_DRUID: + case PLAYER_CLASS_GREAT_DRUID: + case PLAYER_CLASS_ARCH_DRUID: + case PLAYER_CLASS_WARLOCK: + v4 = GetActualWillpower(); + v5 = GetParameterBonus(v4); + v6 = GetActualIntelligence(); + v3 = GetParameterBonus(v6) + v5; + break; + default: + return 0; + break; + } + v7 = pBaseManaPerLevelByClass[classType] * (GetActualLevel() + v3); + v8 = GetItemsBonus(CHARACTER_ATTRIBUTE_MANA) + v7; + v9 = uFullManaBonus + + pBaseManaByClass[classType / 4] + + GetSkillBonus(CHARACTER_ATTRIBUTE_MANA) + + v8; + return max(0,v9); +} + +//----- (0048E656) -------------------------------------------------------- +int Player::GetBaseAC() +{ + int v2; // eax@1 + int v3; // esi@1 + int v4; // esi@1 + int v5; // esi@1 + + v2 = GetActualSpeed(); + v3 = GetParameterBonus(v2); + v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v3; + v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v4; + return max(0, v5); +} + +//----- (0048E68F) -------------------------------------------------------- +int Player::GetActualAC() +{ + int v2; // eax@1 + int v3; // esi@1 + int v4; // esi@1 + int v5; // esi@1 + int v6; // esi@1 + + v2 = GetActualSpeed(); + v3 = GetParameterBonus(v2); + v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v3; + v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v4; + v6 = this->sACModifier + GetMagicalBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v5; + return max(0, v6); +} + +//----- (0048E6DC) -------------------------------------------------------- +unsigned int Player::GetBaseAge() +{ + return (unsigned int)(((__int64)(pParty->uTimePlayed * 0.234375) / 60 / 60 / 24) / 7 / 4 / 12 - uBirthYear + game_starting_year); +} + +//----- (0048E72C) -------------------------------------------------------- +unsigned int Player::GetActualAge() +{ + return this->sAgeModifier + GetBaseAge(); +} + +//----- (0048E73F) -------------------------------------------------------- +int Player::GetBaseResistance(enum CHARACTER_ATTRIBUTE_TYPE a2) +{ + int v7; // esi@20 + int racialBonus = 0; + __int16* resStat; + int result; + + switch (a2) + { + case CHARACTER_ATTRIBUTE_RESIST_FIRE: + resStat = &sResFireBase; + if (IsRaceGoblin()) + racialBonus = 5; + break; + case CHARACTER_ATTRIBUTE_RESIST_AIR: + resStat = &sResAirBase; + if (IsRaceGoblin()) + racialBonus = 5; + break; + case CHARACTER_ATTRIBUTE_RESIST_WATER: + resStat = &sResWaterBase; + if (IsRaceDwarf()) + racialBonus = 5; + break; + case CHARACTER_ATTRIBUTE_RESIST_EARTH: + resStat = &sResEarthBase; + if (IsRaceDwarf()) + racialBonus = 5; + break; + case CHARACTER_ATTRIBUTE_RESIST_MIND: + resStat = &sResMindBase; + if (IsRaceElf()) + racialBonus = 10; + break; + case CHARACTER_ATTRIBUTE_RESIST_BODY: + case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: + resStat = &sResBodyBase; + if (IsRaceHuman()) + racialBonus = 5; + break; + default: + Error("Unknown attribute"); + } + v7 = GetItemsBonus(a2) + racialBonus; + result = v7 + *resStat; + if ( classType == PLAYER_CLASS_LICH ) + { + if ( result > 200 ) + result = 200; + } + return result; +} + +//----- (0048E7D0) -------------------------------------------------------- +int Player::GetActualResistance(enum CHARACTER_ATTRIBUTE_TYPE a2) +{ + signed int v10 = 0; // [sp+14h] [bp-4h]@1 + __int16* resStat; + int result; + int baseRes; + + int leatherArmorSkillLevel = GetActualSkillLevel(PLAYER_SKILL_LEATHER); + if ( CheckHiredNPCSpeciality(Enchanter) ) + v10 = 20; + if ( (a2 == CHARACTER_ATTRIBUTE_RESIST_FIRE + || a2 == CHARACTER_ATTRIBUTE_RESIST_AIR + || a2 == CHARACTER_ATTRIBUTE_RESIST_WATER + || a2 == CHARACTER_ATTRIBUTE_RESIST_EARTH) + && SkillToMastery(leatherArmorSkillLevel) == 4 + && HasItemEquipped(EQUIP_ARMOUR) + && GetEquippedItemSkillType(EQUIP_ARMOUR) == PLAYER_SKILL_LEATHER ) + v10 += leatherArmorSkillLevel & 0x3F; + switch (a2) + { + case CHARACTER_ATTRIBUTE_RESIST_FIRE: + resStat = &sResFireBonus; + break; + case CHARACTER_ATTRIBUTE_RESIST_AIR: + resStat = &sResAirBonus; + break; + case CHARACTER_ATTRIBUTE_RESIST_WATER: + resStat = &sResWaterBonus; + break; + case CHARACTER_ATTRIBUTE_RESIST_EARTH: + resStat = &sResEarthBonus; + break; + case CHARACTER_ATTRIBUTE_RESIST_MIND: + resStat = &sResMindBonus; + break; + case CHARACTER_ATTRIBUTE_RESIST_BODY: + case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: + resStat = &sResBodyBonus; + break; + default: Error("Unexpected attribute"); + } + baseRes = GetBaseResistance(a2); + result = v10 + GetMagicalBonus(a2) + baseRes + *(resStat); + if ( classType == PLAYER_CLASS_LICH ) + { + if ( result > 200 ) + result = 200; + } + return result; +} + +//----- (0048E8F5) -------------------------------------------------------- +bool Player::Recover(int dt) +{ + int v3; // qax@1 + + v3 = (int)(dt * GetSpecialItemBonus(17) * 0.01 + dt); + + //Log::Warning(L"Recover(dt = %u/%u - %u", dt, (uint)v3, (uint)uTimeToRecovery); + + if (uTimeToRecovery > v3) + { + uTimeToRecovery -= v3; + return true; + } + else + { + uTimeToRecovery = 0; + viewparams->bRedrawGameUI = true; + if (!uActiveCharacter) + uActiveCharacter = pParty->GetNextActiveCharacter(); + return false; + } +} + +//----- (0048E96A) -------------------------------------------------------- +void Player::SetRecoveryTime(signed int rec) +{ + Assert(rec >= 0); + + if (rec > uTimeToRecovery) + uTimeToRecovery = rec; + + if (uActiveCharacter != 0 && pPlayers[uActiveCharacter] == this && !some_active_character) + uActiveCharacter = pParty->GetNextActiveCharacter(); + + viewparams->bRedrawGameUI = true; +} +// 50C0C4: using guessed type int some_active_character; + +//----- (0048E9B7) -------------------------------------------------------- +void Player::RandomizeName() +{ + if (!uExpressionTimePassed) + strcpy(pName, pNPCStats->pNPCNames[rand() % pNPCStats->uNumNPCNames[uSex]][uSex]); +} + +//----- (0048E9F4) -------------------------------------------------------- +unsigned int Player::GetMajorConditionIdx() +{ + for (uint i = 0; i < 18; ++i) + if (pConditions[pConditionImportancyTable[i]] != 0) + return pConditionImportancyTable[i]; + + return 18; +} + +//----- (0048EA1B) -------------------------------------------------------- +int Player::GetParameterBonus( int player_parameter ) +{ + int i; // eax@1 + i = 0; + while (param_to_bonus_table[i]) + { + if (player_parameter >= param_to_bonus_table[i]) + break; + ++i; + } + return parameter_to_bonus_value[i]; +} + +//----- (0048EA46) -------------------------------------------------------- +int Player::GetSpecialItemBonus( int enchantmentId ) +{ + for (int i = EQUIP_SINGLE_HANDED; i < EQUIP_BOOK; ++i ) + { + if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + if (enchantmentId == 17) + { + if ((GetNthEquippedIndexItem(i)->uSpecEnchantmentType == 17) || (GetNthEquippedIndexItem(i)->uItemID == 533)) //Elven Chainmail+Increases rate of Recovery + return 50; + } + if (enchantmentId == 24) + { + if (GetNthEquippedIndexItem(i)->uSpecEnchantmentType == 24) //Increased Knockback. + return 5; + } + } + } + return 0; +} + +//----- (0048EAAE) -------------------------------------------------------- +int Player::GetItemsBonus( enum CHARACTER_ATTRIBUTE_TYPE attr, bool getOnlyMainHandDmg /*= false*/ ) +{ + int v5; // edi@1 + int v9; // eax@49 + int v14; // ecx@58 + int v15; // eax@58 + int v17; // eax@62 + int v22; // eax@76 + int v25; // ecx@80 + int v26; // edi@80 + int v32; // eax@98 + int v56; // eax@365 + signed int v58; // [sp-4h] [bp-20h]@10 + int v61; // [sp+10h] [bp-Ch]@1 + int v62; // [sp+14h] [bp-8h]@1 + ItemGen *currEquippedItem; // [sp+20h] [bp+4h]@101 + bool no_skills; + + v5 = 0; + v62 = 0; + v61 = 0; + + no_skills=false; + switch (attr) + { + case CHARACTER_ATTRIBUTE_SKILL_ALCHEMY: v58 = PLAYER_SKILL_ALCHEMY; break; + case CHARACTER_ATTRIBUTE_SKILL_STEALING: v58 = PLAYER_SKILL_STEALING; break; + case CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM: v58 = PLAYER_SKILL_TRAP_DISARM; break; + case CHARACTER_ATTRIBUTE_SKILL_ITEM_ID: v58 = PLAYER_SKILL_ITEM_ID; break; + case CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID: v58 = PLAYER_SKILL_MONSTER_ID; break; + case CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER: v58 = PLAYER_SKILL_ARMSMASTER; break; + case CHARACTER_ATTRIBUTE_SKILL_DODGE: v58 = PLAYER_SKILL_DODGE; break; + case CHARACTER_ATTRIBUTE_SKILL_UNARMED: v58 = PLAYER_SKILL_UNARMED; break; + case CHARACTER_ATTRIBUTE_SKILL_FIRE: v58 = PLAYER_SKILL_FIRE; break; + case CHARACTER_ATTRIBUTE_SKILL_AIR: v58 = PLAYER_SKILL_AIR; break; + case CHARACTER_ATTRIBUTE_SKILL_WATER: v58 = PLAYER_SKILL_WATER; break; + case CHARACTER_ATTRIBUTE_SKILL_EARTH: v58 = PLAYER_SKILL_EARTH; break; + case CHARACTER_ATTRIBUTE_SKILL_SPIRIT: v58 = PLAYER_SKILL_SPIRIT; break; + case CHARACTER_ATTRIBUTE_SKILL_MIND: v58 = PLAYER_SKILL_MIND; break; + case CHARACTER_ATTRIBUTE_SKILL_BODY: v58 = PLAYER_SKILL_BODY; break; + case CHARACTER_ATTRIBUTE_SKILL_LIGHT: v58 = PLAYER_SKILL_LIGHT; break; + case CHARACTER_ATTRIBUTE_SKILL_DARK: v58 = PLAYER_SKILL_DARK; break; + case CHARACTER_ATTRIBUTE_SKILL_MEDITATION: v58 = PLAYER_SKILL_MEDITATION; break; + case CHARACTER_ATTRIBUTE_SKILL_BOW: v58 = PLAYER_SKILL_BOW; break; + case CHARACTER_ATTRIBUTE_SKILL_SHIELD: v58 = PLAYER_SKILL_SHIELD; break; + case CHARACTER_ATTRIBUTE_SKILL_LEARNING: v58 = PLAYER_SKILL_LEARNING; break; + default: + no_skills=true; + } + if (!no_skills) + { + if ( !this->pActiveSkills[v58] ) + return 0; + } + + switch(attr) //TODO would be nice to move these into separate functions + { + case CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS: + case CHARACTER_ATTRIBUTE_RANGED_ATTACK: + if ( HasItemEquipped(EQUIP_BOW) ) + v5 = GetBowItem()->GetDamageMod(); + return v5; + break; + + case CHARACTER_ATTRIBUTE_RANGED_DMG_MIN: + if ( !HasItemEquipped(EQUIP_BOW) ) + return 0; + v5 = GetBowItem()->GetDamageMod(); + v56 = GetBowItem()->GetDamageDice(); + return v5 + v56; + break; + + case CHARACTER_ATTRIBUTE_RANGED_DMG_MAX: + if ( !HasItemEquipped(EQUIP_BOW) ) + return 0; + v5 = GetBowItem()->GetDamageDice() * GetBowItem()->GetDamageRoll(); + v56 = GetBowItem()->GetDamageMod(); + return v5 + v56; + + case CHARACTER_ATTRIBUTE_LEVEL: + if ( !Player::HasEnchantedItemEquipped(25) ) + return 0; + return 5; + break; + + case CHARACTER_ATTRIBUTE_MELEE_DMG_MAX: + if ( IsUnarmed() ) + { + return 3; + } + else + { + if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) + { + v22 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); + if ( v22 >= 0 && v22 <= 2) + { + ItemGen* mainHandItem = GetMainHandItem(); + v26 = mainHandItem->GetDamageRoll(); + if ( GetOffHandItem() != nullptr || mainHandItem->GetPlayerSkillType() != 4 ) + { + v25 = mainHandItem->GetDamageDice(); + } + else + { + v25 = mainHandItem->GetDamageDice() + 1; + } + v5 = mainHandItem->GetDamageMod() + v25 * v26; + } + } + if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0 || GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2)) + { + return v5; + } + else + { + ItemGen* offHandItem = GetOffHandItem(); + v15 = offHandItem->GetDamageMod(); + v14 = offHandItem->GetDamageDice() * offHandItem->GetDamageRoll(); + return v5 + v15 + v14; + } + } + break; + + case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: + case CHARACTER_ATTRIBUTE_ATTACK: + if ( IsUnarmed() ) + { + return 0; + } + if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) + { + v17 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); + if ( v17 >= 0 && v17 <= 2) + { + v5 = GetMainHandItem()->GetDamageMod(); + } + } + if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0) || this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2 ) + return v5; + else + { + v56 = GetOffHandItem()->GetDamageMod(); + return v5 + v56; + } + break; + + case CHARACTER_ATTRIBUTE_MELEE_DMG_MIN: + if ( IsUnarmed() ) + { + return 1; + } + if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) + { + v9 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); + if ( v9 >= 0 && v9 <= 2) + { + ItemGen* mainHandItem = GetMainHandItem(); + v5 = mainHandItem->GetDamageDice() + + mainHandItem->GetDamageMod(); + if ( GetOffHandItem() == nullptr && mainHandItem->GetPlayerSkillType() == 4) + { + ++v5; + } + } + } + + if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0) || this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2 ) + { + return v5; + } + else + { + ItemGen* offHandItem = GetOffHandItem(); + v14 = offHandItem->GetDamageMod(); + v15 = offHandItem->GetDamageDice(); + return v5 + v15 + v14; + } + break; + + case CHARACTER_ATTRIBUTE_STRENGTH: + case CHARACTER_ATTRIBUTE_INTELLIGENCE: + case CHARACTER_ATTRIBUTE_WILLPOWER: + case CHARACTER_ATTRIBUTE_ENDURANCE: + case CHARACTER_ATTRIBUTE_ACCURACY: + case CHARACTER_ATTRIBUTE_SPEED: + case CHARACTER_ATTRIBUTE_LUCK: + case CHARACTER_ATTRIBUTE_HEALTH: + case CHARACTER_ATTRIBUTE_MANA: + case CHARACTER_ATTRIBUTE_AC_BONUS: + + case CHARACTER_ATTRIBUTE_RESIST_FIRE: + case CHARACTER_ATTRIBUTE_RESIST_AIR: + case CHARACTER_ATTRIBUTE_RESIST_WATER: + case CHARACTER_ATTRIBUTE_RESIST_EARTH: + case CHARACTER_ATTRIBUTE_RESIST_MIND: + case CHARACTER_ATTRIBUTE_RESIST_BODY: + case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: + + case CHARACTER_ATTRIBUTE_SKILL_ALCHEMY: + case CHARACTER_ATTRIBUTE_SKILL_STEALING: + case CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM: + case CHARACTER_ATTRIBUTE_SKILL_ITEM_ID: + case CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID: + case CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER: + case CHARACTER_ATTRIBUTE_SKILL_DODGE: + case CHARACTER_ATTRIBUTE_SKILL_UNARMED: + + case CHARACTER_ATTRIBUTE_SKILL_FIRE: + case CHARACTER_ATTRIBUTE_SKILL_AIR: + case CHARACTER_ATTRIBUTE_SKILL_WATER: + case CHARACTER_ATTRIBUTE_SKILL_EARTH: + case CHARACTER_ATTRIBUTE_SKILL_SPIRIT: + case CHARACTER_ATTRIBUTE_SKILL_MIND: + case CHARACTER_ATTRIBUTE_SKILL_BODY: + case CHARACTER_ATTRIBUTE_SKILL_LIGHT: + case CHARACTER_ATTRIBUTE_SKILL_DARK: + case CHARACTER_ATTRIBUTE_SKILL_MEDITATION: + case CHARACTER_ATTRIBUTE_SKILL_BOW: + case CHARACTER_ATTRIBUTE_SKILL_SHIELD: + case CHARACTER_ATTRIBUTE_SKILL_LEARNING: + for (int i = 0; i < 16; i++) + { + if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + currEquippedItem = GetNthEquippedIndexItem(i); + if ( attr == CHARACTER_ATTRIBUTE_AC_BONUS ) + { + v32 = currEquippedItem->GetItemEquipType(); + if ( v32 >= 3 && v32 <= 11 ) + { + v5 += currEquippedItem->GetDamageDice() + currEquippedItem->GetDamageMod(); + } + } + if ( pItemsTable->IsMaterialNonCommon(currEquippedItem) + && !pItemsTable->IsMaterialSpecial(currEquippedItem) ) + { + currEquippedItem->GetItemBonusArtifact(this, attr, &v62); + } + else if ( currEquippedItem->uEnchantmentType != 0 ) + { + if (this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uEnchantmentType - 1 == attr)//if (currEquippedItem->IsRegularEnchanmentForAttribute(attr)) + { + if ( attr > CHARACTER_ATTRIBUTE_RESIST_BODY && v5 < currEquippedItem->m_enchantmentStrength )//for skills bonuses + v5 = currEquippedItem->m_enchantmentStrength; + else // for resists and attributes bonuses + v5 += currEquippedItem->m_enchantmentStrength; + } + } + else + { + currEquippedItem->GetItemBonusSpecialEnchantment(this, attr, &v5, &v61); + } + } + } + return v5 + v62 + v61; + break; + default: + return 0; + } +} + +//----- (0048F73C) -------------------------------------------------------- +int Player::GetMagicalBonus(enum CHARACTER_ATTRIBUTE_TYPE a2) +{ + int v3 = 0; // eax@4 + int v4 = 0; // ecx@5 + + switch ( a2 ) + { + case CHARACTER_ATTRIBUTE_RESIST_FIRE: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_FIRE].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_FIRE].uPower; + break; + case CHARACTER_ATTRIBUTE_RESIST_AIR: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_AIR].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_AIR].uPower; + break; + case CHARACTER_ATTRIBUTE_RESIST_BODY: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_BODY].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_BODY].uPower; + break; + case CHARACTER_ATTRIBUTE_RESIST_WATER: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_WATER].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_WATER].uPower; + break; + case CHARACTER_ATTRIBUTE_RESIST_EARTH: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_EARTH].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_EARTH].uPower; + break; + case CHARACTER_ATTRIBUTE_RESIST_MIND: + v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_MIND].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_MIND].uPower; + break; + case CHARACTER_ATTRIBUTE_ATTACK: + case CHARACTER_ATTRIBUTE_RANGED_ATTACK: + v3 = this->pPlayerBuffs[PLAYER_BUFF_BLESS].uPower; //only player effect spell in both VI and VII + break; + case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: + v3 = this->pPlayerBuffs[PLAYER_BUFF_HEROISM].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_HEROISM].uPower; + break; + case CHARACTER_ATTRIBUTE_STRENGTH: + v3 = pPlayerBuffs[PLAYER_BUFF_STRENGTH].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_INTELLIGENCE: + v3 = pPlayerBuffs[PLAYER_BUFF_INTELLIGENCE].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_WILLPOWER: + v3 = pPlayerBuffs[PLAYER_BUFF_WILLPOWER].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_ENDURANCE: + v3 = pPlayerBuffs[PLAYER_BUFF_ENDURANCE].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_ACCURACY: + v3 = pPlayerBuffs[PLAYER_BUFF_ACCURACY].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_SPEED: + v3 = pPlayerBuffs[PLAYER_BUFF_SPEED].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_LUCK: + v3 = pPlayerBuffs[PLAYER_BUFF_LUCK].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; + break; + case CHARACTER_ATTRIBUTE_AC_BONUS: + v3 = this->pPlayerBuffs[PLAYER_BUFF_STONESKIN].uPower; + v4 = pParty->pPartyBuffs[PARTY_BUFF_STONE_SKIN].uPower; + break; + } + return v3 + v4; +} + +//----- (0048F882) -------------------------------------------------------- +int Player::GetActualSkillLevel( PLAYER_SKILL_TYPE uSkillType ) +{ + signed int bonus_value; // esi@1 + unsigned __int16 skill_value; // ax@126 + int result; // al@127 + + bonus_value = 0; + switch (uSkillType) + { + case PLAYER_SKILL_MONSTER_ID: + { + if ( CheckHiredNPCSpeciality(Hunter) ) + bonus_value = 6; + if ( CheckHiredNPCSpeciality(Sage) ) + bonus_value += 6; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID); + } + break; + + case PLAYER_SKILL_ARMSMASTER: + { + if ( CheckHiredNPCSpeciality(Armsmaster) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Weaponsmaster) ) + bonus_value += 3; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER); + } + break; + + case PLAYER_SKILL_STEALING: + { + if (CheckHiredNPCSpeciality(Burglar)) + bonus_value = 8; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_STEALING); + } + break; + + + case PLAYER_SKILL_ALCHEMY: + { + if ( CheckHiredNPCSpeciality(Herbalist) ) + bonus_value = 4; + if ( CheckHiredNPCSpeciality(Apothecary) ) + bonus_value += 8; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ALCHEMY); + } + break; + + case PLAYER_SKILL_LEARNING: + { + if ( CheckHiredNPCSpeciality(Teacher) ) + bonus_value = 10; + if ( CheckHiredNPCSpeciality(Instructor) ) + bonus_value += 15; + if ( CheckHiredNPCSpeciality(Scholar) ) + bonus_value += 5; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_LEARNING); + } + break; + + case PLAYER_SKILL_UNARMED: + { + if (CheckHiredNPCSpeciality(Monk) ) + bonus_value = 2; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_UNARMED); + } + break; + + case PLAYER_SKILL_DODGE: + { + if ( CheckHiredNPCSpeciality(Monk) ) + bonus_value = 2; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_DODGE); + } + break; + + case PLAYER_SKILL_BOW: + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_BOW); + break; + case PLAYER_SKILL_SHIELD: + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_SHIELD); + break; + + case PLAYER_SKILL_EARTH: + if ( CheckHiredNPCSpeciality(Apprentice) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Mystic) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Spellmaster) ) + bonus_value += 4; + if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) + bonus_value += 3; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_EARTH); + break; + case PLAYER_SKILL_FIRE: + if ( CheckHiredNPCSpeciality(Apprentice) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Mystic) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Spellmaster) ) + bonus_value += 4; + if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) + bonus_value += 3; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_FIRE); + break; + case PLAYER_SKILL_AIR: + if ( CheckHiredNPCSpeciality(Apprentice) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Mystic) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Spellmaster) ) + bonus_value += 4; + if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) + bonus_value += 3; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_AIR); + break; + case PLAYER_SKILL_WATER: + if ( CheckHiredNPCSpeciality(Apprentice) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Mystic) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Spellmaster) ) + bonus_value += 4; + if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) + bonus_value += 3; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_WATER); + break; + case PLAYER_SKILL_SPIRIT: + if ( CheckHiredNPCSpeciality(Acolyte2) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Initiate) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Prelate) ) + bonus_value += 4; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_SPIRIT); + break; + case PLAYER_SKILL_MIND: + if ( CheckHiredNPCSpeciality(Acolyte2) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Initiate) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Prelate) ) + bonus_value += 4; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MIND); + break; + case PLAYER_SKILL_BODY: + if ( CheckHiredNPCSpeciality(Acolyte2) ) + bonus_value = 2; + if ( CheckHiredNPCSpeciality(Initiate) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Prelate) ) + bonus_value += 4; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_BODY); + break; + case PLAYER_SKILL_LIGHT: + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_LIGHT); + break; + case PLAYER_SKILL_DARK: + { + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_DARK); + } + break; + + case PLAYER_SKILL_MERCHANT: + { + if ( CheckHiredNPCSpeciality(Trader) ) + bonus_value = 4; + if ( CheckHiredNPCSpeciality(Merchant) ) + bonus_value += 6; + if ( CheckHiredNPCSpeciality(Gypsy) ) + bonus_value += 3; + if ( CheckHiredNPCSpeciality(Duper) ) + bonus_value += 8; + } + break; + + case PLAYER_SKILL_PERCEPTION: + { + if ( CheckHiredNPCSpeciality(Scout) ) + bonus_value = 6; + if ( CheckHiredNPCSpeciality(Psychic) ) + bonus_value += 5; + } + break; + + case PLAYER_SKILL_ITEM_ID: + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ITEM_ID); + break; + case PLAYER_SKILL_MEDITATION: + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MEDITATION); + break; + case PLAYER_SKILL_TRAP_DISARM: + { + if ( CheckHiredNPCSpeciality(Tinker) ) + bonus_value = 4; + if ( CheckHiredNPCSpeciality(Locksmith) ) + bonus_value += 6; + if ( CheckHiredNPCSpeciality(Burglar) ) + bonus_value += 8; + bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM); + } + break; + } + + skill_value = pActiveSkills[uSkillType]; + if ( bonus_value + (skill_value & 0x3F) < 60 ) + result = bonus_value + skill_value; + else + result = skill_value & 0xFFFC | 0x3C; //al + return result; +} + + +//----- (0048FC00) -------------------------------------------------------- +int Player::GetSkillBonus(enum CHARACTER_ATTRIBUTE_TYPE inSkill) //TODO: move the individual implementations to attribute classes once possible +{ + int armsMasterBonus; + + armsMasterBonus = 0; + int armmaster_skill = GetActualSkillLevel(PLAYER_SKILL_ARMSMASTER); + if ( armmaster_skill > 0 ) + { + int multiplier = 0; + if ( inSkill == CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS ) + { + multiplier = GetMultiplierForSkillLevel(armmaster_skill, 0, 0, 1, 2); + } + else if ( inSkill == CHARACTER_ATTRIBUTE_ATTACK ) + { + multiplier = GetMultiplierForSkillLevel(armmaster_skill, 0, 1, 1, 2); + } + armsMasterBonus = multiplier * (armmaster_skill & 0x3F); + } + + switch(inSkill) + { + case CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS: + if (HasItemEquipped(EQUIP_BOW)) + { + int bowSkillLevel = GetActualSkillLevel(PLAYER_SKILL_DODGE); + int multiplier = GetMultiplierForSkillLevel(bowSkillLevel, 0, 0, 0, 1); + return multiplier * (bowSkillLevel & 0x3F); + } + return 0; + break; + case CHARACTER_ATTRIBUTE_HEALTH: + { + int base_value = pBaseHealthPerLevelByClass[classType]; + int attrib_modif = GetBodybuilding(); + return base_value * attrib_modif; + } + break; + case CHARACTER_ATTRIBUTE_MANA: + { + int base_value = pBaseManaPerLevelByClass[classType]; + int attrib_modif = GetMeditation(); + return base_value * attrib_modif; + } + break; + case CHARACTER_ATTRIBUTE_AC_BONUS: + { + bool wearingArmor = false; + bool wearingLeather = false; + unsigned int ACSum = 0; + + for (int j = 0; j < 16; ++j) + { + ItemGen* currItem = GetNthEquippedIndexItem(j); + if (currItem != nullptr && (!currItem->IsBroken())) + { + PLAYER_SKILL_TYPE itemSkillType = (PLAYER_SKILL_TYPE)currItem->GetPlayerSkillType(); + int currArmorSkillLevel = 0; + int multiplier = 0; + switch (itemSkillType) + { + case PLAYER_SKILL_STAFF: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 0, 1, 1, 1); + break; + case PLAYER_SKILL_SWORD: + case PLAYER_SKILL_SPEAR: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 0, 0, 0, 1); + break; + case PLAYER_SKILL_SHIELD: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + wearingArmor = true; + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 2, 2); + break; + case PLAYER_SKILL_LEATHER: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + wearingLeather = true; + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 2, 2); + break; + case PLAYER_SKILL_CHAIN: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + wearingArmor = true; + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 1, 1); + break; + case PLAYER_SKILL_PLATE: + currArmorSkillLevel = GetActualSkillLevel(itemSkillType); + wearingArmor = true; + multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 1, 1); + break; + } + ACSum += multiplier * (currArmorSkillLevel & 0x3F); + } + } + + int dodgeSkillLevel = GetActualSkillLevel(PLAYER_SKILL_DODGE); + int dodgeMastery = SkillToMastery(dodgeSkillLevel); + int multiplier = GetMultiplierForSkillLevel(dodgeSkillLevel, 1, 2, 3, 3); + if ( !wearingArmor && (!wearingLeather || dodgeMastery == 4) ) + { + ACSum += multiplier * (dodgeSkillLevel & 0x3F); + } + return ACSum; + } + break; + case CHARACTER_ATTRIBUTE_ATTACK: + if ( this->IsUnarmed() ) + { + int unarmedSkill = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); + if (!unarmedSkill) + { + return 0; + } + int multiplier = GetMultiplierForSkillLevel(unarmedSkill, 0, 1, 2, 2); + return armsMasterBonus + multiplier * (unarmedSkill & 0x3F); + } + for (int i = 0; i < 16; ++i) + { + if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + ItemGen* currItem = GetNthEquippedIndexItem(i); + if ( currItem->GetItemEquipType() <= EQUIP_TWO_HANDED) + { + PLAYER_SKILL_TYPE currItemSkillType = (PLAYER_SKILL_TYPE)currItem->GetPlayerSkillType(); + int currentItemSkillLevel = this->GetActualSkillLevel(currItemSkillType); + if (currItemSkillType == PLAYER_SKILL_BLASTER) + { + int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 2, 3, 5); + return multiplier * (currentItemSkillLevel & 0x3F); + } + else if (currItemSkillType == PLAYER_SKILL_STAFF && this->GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) + { + int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); + int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 1, 2, 2); + return multiplier * (unarmedSkillLevel & 0x3F) + armsMasterBonus + (currentItemSkillLevel & 0x3F); + } + else + { + return armsMasterBonus + (currentItemSkillLevel & 0x3F); + } + } + } + } + return 0; + break; + + case CHARACTER_ATTRIBUTE_RANGED_ATTACK: + for (int i = 0; i < 16; i++) + { + if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + ItemGen* currItemPtr = GetNthEquippedIndexItem(i); + if ( currItemPtr->GetItemEquipType() == EQUIP_TWO_HANDED || currItemPtr->GetItemEquipType() == EQUIP_SINGLE_HANDED ) + { + PLAYER_SKILL_TYPE currentItemSkillType = (PLAYER_SKILL_TYPE)GetNthEquippedIndexItem(i)->GetPlayerSkillType(); + int currentItemSkillLevel = this->GetActualSkillLevel(currentItemSkillType); + if ( currentItemSkillType == PLAYER_SKILL_BOW ) + { + int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 1, 1, 1); + return multiplier * (currentItemSkillLevel & 0x3F); + } + else if ( currentItemSkillType == PLAYER_SKILL_BLASTER ) + { + int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 2, 3, 5); + return multiplier * (currentItemSkillLevel & 0x3F); + } + } + } + } + return 0; + break; + + case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: + if ( this->IsUnarmed() ) + { + int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); + if ( !unarmedSkillLevel ) + { + return 0; + } + int multiplier = GetMultiplierForSkillLevel(unarmedSkillLevel, 0, 1, 2, 2); + return multiplier * (unarmedSkillLevel & 0x3F); + } + for (int i = 0; i < 16; i++) + { + if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) + { + ItemGen* currItemPtr = GetNthEquippedIndexItem(i); + if ( currItemPtr->GetItemEquipType() == EQUIP_TWO_HANDED || currItemPtr->GetItemEquipType() == EQUIP_SINGLE_HANDED ) + { + PLAYER_SKILL_TYPE currItemSkillType = (PLAYER_SKILL_TYPE)currItemPtr->GetPlayerSkillType(); + int currItemSkillLevel = this->GetActualSkillLevel(currItemSkillType); + int baseSkillBonus; + int multiplier; + switch (currItemSkillType) + { + case PLAYER_SKILL_STAFF: + if ( SkillToMastery(currItemSkillLevel) >= 4 && this->GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) + { + int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); + int multiplier = GetMultiplierForSkillLevel(unarmedSkillLevel, 0, 1, 2, 2); + return multiplier * (unarmedSkillLevel & 0x3F); + } + else + { + return armsMasterBonus; + } + break; + + case PLAYER_SKILL_DAGGER: + multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 0, 1); + baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); + return armsMasterBonus + baseSkillBonus; + break; + case PLAYER_SKILL_SWORD: + multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 0, 0); + baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); + return armsMasterBonus + baseSkillBonus; + break; + case PLAYER_SKILL_MACE: + case PLAYER_SKILL_SPEAR: + multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 1, 1, 1); + baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); + return armsMasterBonus + baseSkillBonus; + break; + case PLAYER_SKILL_AXE: + multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 1, 1); + baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); + return armsMasterBonus + baseSkillBonus; + break; + } + } + } + } + return 0; + break; + default: + return 0; + } +} + +unsigned int Player::GetMultiplierForSkillLevel(unsigned int skillValue, int mult1, int mult2, int mult3, int mult4) +{ + int masteryLvl = SkillToMastery(skillValue); + switch (masteryLvl) + { + case 1: return mult1; + case 2: return mult2; + case 3: return mult3; + case 4: return mult4; + } + Error("(%u)", masteryLvl); + return 0; +} +//----- (00490109) -------------------------------------------------------- +// faces are: 0 1 2 3 human males +// 4 5 6 7 human females +// 8 9 elf males +// 10 11 elf females +// 12 13 dwarf males +// 14 15 dwarf females +// 16 17 goblin males +// 18 19 goblin females +// 20 lich male +// 21 lich female +// 22 underwater suits (unused) +// 23 zombie male +// 24 zombie female +enum CHARACTER_RACE Player::GetRace() +{ + if ( uCurrentFace <= 7 ) + { + return CHARACTER_RACE_HUMAN; + } + else if ( uCurrentFace <= 11 ) + { + return CHARACTER_RACE_ELF; + } + else if ( uCurrentFace <= 15 ) + { + return CHARACTER_RACE_DWARF; + } + else if ( uCurrentFace <= 19 ) + { + return CHARACTER_RACE_GOBLIN; + } + else + { + return CHARACTER_RACE_HUMAN; + } +} + +//----- (00490141) -------------------------------------------------------- +PLAYER_SEX Player::GetSexByVoice() +{ + switch ( this->uVoiceID ) + { + case 0u: + case 1u: + case 2u: + case 3u: + case 8u: + case 9u: + case 0xCu: + case 0xDu: + case 0x10u: + case 0x11u: + case 0x14u: + case 0x17u: + return SEX_MALE; + + case 4u: + case 5u: + case 6u: + case 7u: + case 0xAu: + case 0xBu: + case 0xEu: + case 0xFu: + case 0x12u: + case 0x13u: + case 0x15u: + case 0x18u: + return SEX_FEMALE; + } + Error("(%u)", this->uVoiceID); + return SEX_MALE; +} + +//----- (00490188) -------------------------------------------------------- +void Player::SetInitialStats() +{ + CHARACTER_RACE v1 = GetRace(); + uMight = StatTable[v1][0].uBaseValue; + uIntelligence = StatTable[v1][1].uBaseValue; + uWillpower = StatTable[v1][2].uBaseValue; + uEndurance = StatTable[v1][3].uBaseValue; + uAccuracy = StatTable[v1][4].uBaseValue; + uSpeed = StatTable[v1][5].uBaseValue; + uLuck = StatTable[v1][6].uBaseValue; +} + +//----- (004901FC) -------------------------------------------------------- +void Player::SetSexByVoice() +{ + switch ( this->uVoiceID) + { + case 0: + case 1: + case 2: + case 3: + case 8: + case 9: + case 0xC: + case 0xD: + case 0x10: + case 0x11: + case 0x14: + case 0x17: + this->uSex = SEX_MALE; + break; + case 4: + case 5: + case 6: + case 7: + case 0xA: + case 0xB: + case 0xE: + case 0xF: + case 0x12: + case 0x13: + case 0x15: + case 0x18: + this->uSex = SEX_FEMALE; + break; + default: + Error("(%u)", this->uVoiceID); + break; + } + +} + +//----- (0049024A) -------------------------------------------------------- +void Player::Reset(PLAYER_CLASS_TYPE cls) +{ + sLevelModifier = 0; + sAgeModifier = 0; + + classType = cls; + uLuckBonus = 0; + uSpeedBonus = 0; + uAccuracyBonus = 0; + uEnduranceBonus = 0; + uWillpowerBonus = 0; + uIntelligenceBonus = 0; + uMightBonus = 0; + uLevel = 1; + uExperience = 251 + rand() % 100; + uBirthYear = 1147 - rand() % 6; + pActiveSkills.fill(0); + memset(_achieved_awards_bits, 0, sizeof(_achieved_awards_bits)); + memset(&spellbook, 0, sizeof(spellbook)); + + for (uint i = 0; i < 37; ++i) + { + if (pSkillAvailabilityPerClass[classType / 4][i] != 2) + continue; + + pActiveSkills[i] = 1; + + switch (i) + { + case PLAYER_SKILL_FIRE: + spellbook.pFireSpellbook.bIsSpellAvailable[0] = true;//its temporary, for test spells + + extern bool all_magic; + if ( all_magic == true ) + { + pActiveSkills[PLAYER_SKILL_AIR] = 1; + pActiveSkills[PLAYER_SKILL_WATER] = 1; + pActiveSkills[PLAYER_SKILL_EARTH] = 1; + spellbook.pFireSpellbook.bIsSpellAvailable[1] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[2] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[3] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[4] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[5] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[6] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[7] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[8] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[9] = true; + spellbook.pFireSpellbook.bIsSpellAvailable[10] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[0] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[1] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[2] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[3] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[4] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[5] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[6] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[7] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[8] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[9] = true; + spellbook.pAirSpellbook.bIsSpellAvailable[10] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[1] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[2] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[3] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[4] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[5] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[6] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[7] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[8] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[9] = true; + spellbook.pWaterSpellbook.bIsSpellAvailable[10] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[1] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[2] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[3] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[4] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[5] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[6] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[7] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[8] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[9] = true; + spellbook.pEarthSpellbook.bIsSpellAvailable[10] = true; + } + break; + case PLAYER_SKILL_AIR: + spellbook.pAirSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_WATER: + spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_EARTH: + spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_SPIRIT: + spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_MIND: + spellbook.pMindSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_BODY: + spellbook.pBodySpellbook.bIsSpellAvailable[0] = true; + + if ( all_magic == true ) + { + pActiveSkills[PLAYER_SKILL_MIND] = 1; + pActiveSkills[PLAYER_SKILL_SPIRIT] = 1; + spellbook.pBodySpellbook.bIsSpellAvailable[1] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[2] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[3] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[4] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[5] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[6] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[7] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[8] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[9] = true; + spellbook.pBodySpellbook.bIsSpellAvailable[10] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[0] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[1] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[2] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[3] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[4] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[5] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[6] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[7] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[8] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[9] = true; + spellbook.pMindSpellbook.bIsSpellAvailable[10] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[1] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[2] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[3] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[4] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[5] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[6] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[7] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[8] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[9] = true; + spellbook.pSpiritSpellbook.bIsSpellAvailable[10] = true; + } + break; + case PLAYER_SKILL_LIGHT: + spellbook.pLightSpellbook.bIsSpellAvailable[0] = true; + break; + case PLAYER_SKILL_DARK: + spellbook.pDarkSpellbook.bIsSpellAvailable[0] = true; + break; + } + } + + memset(&pEquipment, 0, sizeof(PlayerEquipment)); + pInventoryMatrix.fill(0); + for (uint i = 0; i < 126; ++i) + pInventoryItemList[i].Reset(); + for (uint i = 0; i < 12; ++i) + pEquippedItems[i].Reset(); + + sHealth = GetMaxHealth(); + sMana = GetMaxMana(); +} + +//----- (004903C9) -------------------------------------------------------- +PLAYER_SKILL_TYPE Player::GetSkillIdxByOrder(signed int order) +{ + int counter; // edx@5 + bool canBeInactive; + unsigned char requiredValue; + signed int offset; + + if ( order <= 1 ) + { + canBeInactive = false; + requiredValue = 2; // 2 - primary skill + offset = 0; + } + else if ( order <= 3 ) + { + canBeInactive = false; + requiredValue = 1; // 1 - available + offset = 2; + } + else if ( order <= 12 ) + { + canBeInactive = true; + requiredValue = 1; // 1 - available + offset = 4; + } + else + { + return (PLAYER_SKILL_TYPE)37; + } + counter = 0; + for (int i = 0; i < 37; i++) + { + if ( (this->pActiveSkills[i] || canBeInactive) && pSkillAvailabilityPerClass[classType / 4][i] == requiredValue ) + { + if ( counter == order - offset ) + return (PLAYER_SKILL_TYPE)i; + ++counter; + } + } + + return (PLAYER_SKILL_TYPE)37; +} + + + +//----- (0049048D) -------------------------------------------------------- +//unsigned __int16 PartyCreation_BtnMinusClick(Player *_this, int eAttribute) +void Player::DecreaseAttribute(int eAttribute) +{ + int pBaseValue; // ecx@1 + int pDroppedStep; // ebx@1 + int pStep; // esi@1 + int uMinValue; // [sp+Ch] [bp-4h]@1 + + int raceId = GetRace(); + pBaseValue = StatTable[raceId][eAttribute].uBaseValue; + pDroppedStep = StatTable[raceId][eAttribute].uDroppedStep; + uMinValue = pBaseValue - 2; + pStep = StatTable[raceId][eAttribute].uBaseStep; + unsigned short* AttrToChange = nullptr; + switch ( eAttribute ) + { + case CHARACTER_ATTRIBUTE_STRENGTH: + AttrToChange = &this->uMight; + break; + case CHARACTER_ATTRIBUTE_INTELLIGENCE: + AttrToChange = &this->uIntelligence; + break; + case CHARACTER_ATTRIBUTE_WILLPOWER: + AttrToChange = &this->uWillpower; + break; + case CHARACTER_ATTRIBUTE_ENDURANCE: + AttrToChange = &this->uEndurance; + break; + case CHARACTER_ATTRIBUTE_ACCURACY: + AttrToChange = &this->uAccuracy; + break; + case CHARACTER_ATTRIBUTE_SPEED: + AttrToChange = &this->uSpeed; + break; + case CHARACTER_ATTRIBUTE_LUCK: + AttrToChange = &this->uLuck; + break; + } + if ( *AttrToChange <= pBaseValue ) + pStep = pDroppedStep; + if ( *AttrToChange - pStep >= uMinValue ) + *AttrToChange -= pStep; +} + +//----- (004905F5) -------------------------------------------------------- +//signed int PartyCreation_BtnPlusClick(Player *this, int eAttribute) +void Player::IncreaseAttribute( int eAttribute ) +{ + int raceId; // eax@1 + int maxValue; // ebx@1 + signed int baseStep; // edi@1 + signed int tmp; // eax@17 + signed int result; // eax@18 + int baseValue; // [sp+Ch] [bp-8h]@1 + signed int droppedStep; // [sp+10h] [bp-4h]@1 + unsigned short* statToChange; + + raceId = GetRace(); + maxValue = StatTable[raceId][eAttribute].uMaxValue; + baseStep = StatTable[raceId][eAttribute].uBaseStep; + baseValue = StatTable[raceId][eAttribute].uBaseValue; + droppedStep = StatTable[raceId][eAttribute].uDroppedStep; + PlayerCreation_GetUnspentAttributePointCount(); + switch ( eAttribute ) + { + case 0: + statToChange = &this->uMight; + break; + case 1: + statToChange = &this->uIntelligence; + break; + case 2: + statToChange = &this->uWillpower; + break; + case 3: + statToChange = &this->uEndurance; + break; + case 4: + statToChange = &this->uAccuracy; + break; + case 5: + statToChange = &this->uSpeed; + break; + case 6: + statToChange = &this->uLuck; + break; + default: + Error("(%u)", eAttribute); + break; + } + if ( *statToChange < baseValue ) + { + tmp = baseStep; + baseStep = droppedStep; + droppedStep = tmp; + } + result = PlayerCreation_GetUnspentAttributePointCount(); + if ( result >= droppedStep ) + { + if ( baseStep + *statToChange <= maxValue ) + *statToChange += baseStep; + } +} + +//----- (0049070F) -------------------------------------------------------- +void Player::Zero() +{ + this->sLevelModifier = 0; + this->sACModifier = 0; + this->uLuckBonus = 0; + this->uAccuracyBonus = 0; + this->uSpeedBonus = 0; + this->uEnduranceBonus = 0; + this->uWillpowerBonus = 0; + this->uIntelligenceBonus = 0; + this->uMightBonus = 0; + this->field_100 = 0; + this->field_FC = 0; + this->field_F8 = 0; + this->field_F4 = 0; + this->field_F0 = 0; + this->field_EC = 0; + this->field_E8 = 0; + this->field_E4 = 0; + this->field_E0 = 0; + memset(&this->sResFireBonus, 0, 0x16u); + this->field_1A97 = 0; + this->_ranged_dmg_bonus = 0; + this->field_1A95 = 0; + this->_ranged_atk_bonus = 0; + this->field_1A93 = 0; + this->_melee_dmg_bonus = 0; + this->field_1A91 = 0; + this->_some_attack_bonus = 0; + this->_mana_related = 0; + this->uFullManaBonus = 0; + this->_health_related = 0; + this->uFullHealthBonus = 0; +} + +//----- (004907E7) -------------------------------------------------------- +unsigned int Player::GetStatColor(int uStat) +{ + int attribute_value; // edx@1 + + int base_attribute_value = StatTable[GetRace()][uStat].uBaseValue; + switch (uStat) + { + case 0: attribute_value = uMight; break; + case 1: attribute_value = uIntelligence; break; + case 2: attribute_value = uWillpower; break; + case 3: attribute_value = uEndurance; break; + case 4: attribute_value = uAccuracy; break; + case 5: attribute_value = uSpeed; break; + case 6: attribute_value = uLuck; break; + default: Error("Unexpected attribute"); + }; + + if (attribute_value == base_attribute_value) + return ui_character_stat_default_color; + else if (attribute_value > base_attribute_value) + return ui_character_stat_buffed_color; + else + return ui_character_stat_debuffed_color; +} + +//----- (004908A8) -------------------------------------------------------- +bool Player::DiscardConditionIfLastsLongerThan(unsigned int uCondition, signed __int64 uTime) +{ + if ( pConditions[uCondition] && (uTime < (signed long long)pConditions[uCondition]) ) + { + pConditions[uCondition] = 0i64; + return true; + } + else + return false; +} + +//----- (004680ED) -------------------------------------------------------- +void Player::UseItem_DrinkPotion_etc(signed int player_num, int a3) +{ + Player *playerAffected; // esi@1 + signed int v5; // eax@17 + int v8; // edx@39 + const char *v13; // eax@45 + signed int v15; // edi@68 + int v16; // edx@73 + unsigned __int16 v17; // edi@73 + unsigned int v18; // eax@73 + const char *v22; // eax@84 + int scroll_id; // esi@96 + int v25; // eax@109 + int v26; // eax@113 + int new_mana_val; // edi@114 + signed __int64 v28; // qax@120 + __int64 v30; // edi@137 + __int64 v32; // ST3C_4@137 + __int64 v34; // ST34_4@137 + unsigned __int16 v50; // [sp-Ch] [bp-38h]@120 + const char *v66; // [sp-4h] [bp-30h]@69 + signed int v67; // [sp-4h] [bp-30h]@77 + const char *v68; // [sp-4h] [bp-30h]@89 + char v72; // [sp+20h] [bp-Ch]@68 + signed int v73; // [sp+24h] [bp-8h]@1 + const char* v74; // [sp+24h] [bp-8h]@23 + //Player *thisb; // [sp+28h] [bp-4h]@1 + unsigned int thisa; // [sp+28h] [bp-4h]@22 + + //thisb = this; + playerAffected = &pParty->pPlayers[player_num-1]; + v73 = 1; + if ( pParty->bTurnBasedModeOn == true && (pTurnEngine->turn_stage == TE_WAIT || pTurnEngine->turn_stage == TE_MOVEMENT) ) + return; + if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_REAGENT ) + { + if ( pParty->pPickedItem.uItemID == 160 ) + { + playerAffected->SetCondition(Condition_Poison_Weak, 1); + } + else if ( pParty->pPickedItem.uItemID == 161 ) + { + new_mana_val = playerAffected->sMana; + new_mana_val += 2; + if ( new_mana_val > playerAffected->GetMaxMana() ) + new_mana_val = playerAffected->GetMaxMana(); + playerAffected->PlaySound(SPEECH_36, 0); + } + else if ( pParty->pPickedItem.uItemID == 162 ) + { + playerAffected->Heal(2); + playerAffected->PlaySound(SPEECH_36, 0); + } + else + { + v68 = pParty->pPickedItem.GetDisplayName(); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36], v68);//"%s can not be used that way" + ShowStatusBarString(pTmpBuf.data(), 2); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + pAudioPlayer->PlaySound((SoundID)211, 0, 0, -1, 0, 0, 0, 0); + + if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) + { + pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); + } + if ( v73 ) + { + if ( pParty->bTurnBasedModeOn ) + { + pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; + this->SetRecoveryTime(100); + pTurnEngine->ApplyPlayerAction(); + } + else + { + this->SetRecoveryTime((int)(flt_6BE3A4_debug_recmod1 * 213.3333333333333)); + } + } + pMouse->RemoveHoldingItem(); + return; + } + + if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_POTION ) + { + switch ( pParty->pPickedItem.uItemID ) + { + case 221: //Catalyst + playerAffected->SetCondition(Condition_Poison_Weak, 1); + break; + case 222: //Cure Wounds + v25 = pParty->pPickedItem.uEnchantmentType + 10; + playerAffected->Heal(v25); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 223: //Magic Potion + v26 = pParty->pPickedItem.uEnchantmentType + 10; + new_mana_val = playerAffected->sMana; + new_mana_val += v26; + if ( new_mana_val > playerAffected->GetMaxMana() ) + new_mana_val = playerAffected->GetMaxMana(); + playerAffected->PlaySound(SPEECH_36, 0); + playerAffected->sMana = new_mana_val; + break; + case 224: //Cure Weakness + playerAffected->pConditions[Condition_Weak] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 225: //Cure Disease + playerAffected->pConditions[Condition_Disease_Severe] = 0i64; + playerAffected->pConditions[Condition_Disease_Medium] = 0i64; + playerAffected->pConditions[Condition_Disease_Weak] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 226: //Cure Poison + playerAffected->pConditions[Condition_Poison_Severe] = 0i64; + playerAffected->pConditions[Condition_Poison_Medium] = 0i64; + playerAffected->pConditions[Condition_Poison_Weak] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 227: //Awaken + playerAffected->pConditions[Condition_Sleep] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 228: //Haste + if ( !playerAffected->pConditions[Condition_Weak] ) + { + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_HASTE].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + } + break; + case 229: //Heroism + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_HEROISM].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 230: //Bless + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_BLESS].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 231: //Preservation + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_PRESERVATION].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 232: //Shield + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_SHIELD].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 234: //Stoneskin + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_STONESKIN].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 235: //Water Breathing + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335), + playerAffected->pPlayerBuffs[PLAYER_BUFF_WATER_WALK].Apply(pParty->uTimePlayed +v28, 3, 5, 0, 0); + break; + case 237: //Remove Fear + playerAffected->pConditions[Condition_Fear] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 238: //Remove Curse + playerAffected->pConditions[Condition_Cursed] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 239: //Cure Insanity + playerAffected->pConditions[Condition_Insane] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 240: //Might Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_STRENGTH].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 241: //Intellect Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_INTELLIGENCE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 242: //Personality Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_WILLPOWER].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 243://Endurance Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_ENDURANCE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 244: //Speed Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_SPEED].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 245: //Accuracy Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_ACCURACY].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 251: //Cure Paralysis + playerAffected->pConditions[Condition_Paralyzed] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 252://Divine Restoration + v30 = playerAffected->pConditions[Condition_Dead]; + v32 = playerAffected->pConditions[Condition_Pertified]; + v34 = playerAffected->pConditions[Condition_Eradicated]; + pConditions.fill(0); + playerAffected->pConditions[Condition_Dead] = v30; + playerAffected->pConditions[Condition_Pertified] = v32; + playerAffected->pConditions[Condition_Eradicated] = v34; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 253: //Divine Cure + v25 = 5 * pParty->pPickedItem.uEnchantmentType; + playerAffected->Heal(v25); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 254: //Divine Power + v26 = 5 * pParty->pPickedItem.uEnchantmentType; + new_mana_val = playerAffected->sMana; + new_mana_val += v26; + if ( new_mana_val > playerAffected->GetMaxMana() ) + new_mana_val = playerAffected->GetMaxMana(); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 255: //Luck Boost + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_LUCK].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 256: //Fire Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_FIRE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 257: //Air Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_AIR].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 258: //Water Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_WATER].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 259: //Earth Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_EARTH].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 260: //Mind Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_MIND].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 261: //Body Resistance + v50 = 3 * pParty->pPickedItem.uEnchantmentType; + v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); + playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_BODY].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 262: //Stone to Flesh + playerAffected->pConditions[Condition_Pertified] = 0i64; + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 264: //Pure Luck + if ( !playerAffected->pure_luck_used ) + { + playerAffected->uLuck += 50; + playerAffected->pure_luck_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 265: //Pure Speed + if ( !playerAffected->pure_speed_used ) + { + playerAffected->uSpeed += 50; + playerAffected->pure_speed_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 266: //Pure Intellect + if ( !playerAffected->pure_intellect_used ) + { + playerAffected->uIntelligence += 50; + playerAffected->pure_intellect_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 267: //Pure Endurance + if ( !playerAffected->pure_endurance_used ) + { + playerAffected->uEndurance += 50; + playerAffected->pure_endurance_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 268: //Pure Personality + if ( !playerAffected->pure_willpower_used ) + { + playerAffected->uWillpower += 50; + playerAffected->pure_willpower_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 269: //Pure Accuracy + if ( !playerAffected->pure_accuracy_used ) + { + playerAffected->uAccuracy += 50; + playerAffected->pure_accuracy_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 270: //Pure Might + if ( !playerAffected->pure_might_used ) + { + playerAffected->uMight += 50; + playerAffected->pure_might_used = 1; + } + playerAffected->PlaySound(SPEECH_36, 0); + break; + case 271: //Rejuvenation + playerAffected->sAgeModifier = 0; + playerAffected->PlaySound(SPEECH_36, 0); + break; + + default: + v68 = pParty->pPickedItem.GetDisplayName(); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36], v68);//"%s can not be used that way" + ShowStatusBarString(pTmpBuf.data(), 2u); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + pAudioPlayer->PlaySound((SoundID)210, 0, 0, -1, 0, 0, 0, 0); + if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) + { +// if ( !v73 ) v73 is always 1 at this point +// { +// pMouse->RemoveHoldingItem(); +// return; +// } + pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); + } + if ( v73 ) + { + if ( pParty->bTurnBasedModeOn ) + { + pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; + this->SetRecoveryTime(100); + pTurnEngine->ApplyPlayerAction(); + } + else + { + this->SetRecoveryTime((int)(flt_6BE3A4_debug_recmod1 * 213.3333333333333)); + } + } + pMouse->RemoveHoldingItem(); + return; + } + + + if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_SPELL_SCROLL ) + { + if ( pCurrentScreen == SCREEN_CASTING ) + return; + if ( !playerAffected->CanAct() ) + { + + v68 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v68); + ShowStatusBarString(pTmpBuf.data(), 2u); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + if ( bUnderwater == 1 ) + { + ShowStatusBarString(pGlobalTXT_LocalizationStrings[652], 2u);//"You can not do that while you are underwater!" + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + + scroll_id = pParty->pPickedItem.uItemID - 299; + if ( scroll_id == 30 || scroll_id == 4 || scroll_id == 91 || scroll_id == 28 ) //Enchant Item scroll, Vampiric Weapon scroll ,Recharge Item ,Fire Aura + { + pMouse->RemoveHoldingItem(); + pGUIWindow_CurrentMenu->Release(); + pIcons_LOD->RemoveTexturesPackFromTextureList(); + pCurrentScreen = SCREEN_GAME; + viewparams->bRedrawGameUI = 1; + _42777D_CastSpell_UseWand_ShootArrow(scroll_id, player_num - 1, 0x85u, 1, 0); + } + else + { + pMouse->RemoveHoldingItem(); + pMessageQueue_50C9E8->AddGUIMessage(UIMSG_SpellScrollUse, scroll_id, player_num - 1); + if ( pCurrentScreen && pGUIWindow_CurrentMenu + && (pGUIWindow_CurrentMenu->eWindowType != WINDOW_null)) + { + pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); + } + } + return; + } + + if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_BOOK ) + { + v15 = pParty->pPickedItem.uItemID - 400; + v72 = playerAffected->spellbook.bHaveSpell[pParty->pPickedItem.uItemID-400];//(char *)&v3->pConditions[0] + pParty->pPickedItem.uItemID + 2; + if ( v72 ) + { + v66 = pParty->pPickedItem.GetDisplayName(); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[380], v66);//"You already know the %s spell" + ShowStatusBarString(pTmpBuf.data(), 2u); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + if ( !playerAffected->CanAct() ) + { + v66 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v66);//"That player is %s" + ShowStatusBarString(pTmpBuf.data(), 2); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + v16 = v15 % 11 + 1; + v17 = playerAffected->pActiveSkills[v15 / 11 + 12]; + v18 = SkillToMastery(v17) - 1; + switch (v18) + { + case 0: v67 = 4; break; + case 1: v67 = 7; break; + case 2: v67 = 10; break; + case 3: v67 = 11; break; + default: + v67 = player_num; + } + + if ( v16 > v67 || !v17 ) + { + v22 = pParty->pPickedItem.GetDisplayName(); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[381], v22); //"You don't have the skill to learn %s" + ShowStatusBarString(pTmpBuf.data(), 2); + playerAffected->PlaySound((PlayerSpeech)20, 0); + return; + } + playerAffected->spellbook.bHaveSpell[pParty->pPickedItem.uItemID-400] = 1; + playerAffected->PlaySound(SPEECH_21, 0); + v73 = 0; + + + if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) + { + if ( !v73 ) + { + pMouse->RemoveHoldingItem(); + return; + } + pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); + } +// if ( v73 ) v73 is always 0 at this point +// { +// if ( pParty->bTurnBasedModeOn ) +// { +// pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; +// thisb->SetRecoveryTime(100); +// pTurnEngine->ApplyPlayerAction(); +// } +// else +// { +// thisb->SetRecoveryTime(flt_6BE3A4_debug_recmod1 * 213.3333333333333); +// } +// } + pMouse->RemoveHoldingItem(); + return; + } + + if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_MESSAGE_SCROLL ) + { + if ( playerAffected->CanAct() ) + { + CreateMsgScrollWindow(pParty->pPickedItem.uItemID); + playerAffected->PlaySound(SPEECH_37, 0); + return; + } + v68 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v68);//That player is %s + ShowStatusBarString(pTmpBuf.data(), 2); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + else + { + if (pParty->pPickedItem.uItemID == 616) //Genie Lamp + { + thisa = pParty->uCurrentMonthWeek + 1; + if ( pParty->uCurrentMonth >= 7 ) + v74 = nullptr; + else + v74 = aAttributeNames[pParty->uCurrentMonth]; + switch ( pParty->uCurrentMonth ) + { + case 0: + playerAffected->uMight += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 1: + playerAffected->uIntelligence += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 2: + playerAffected->uWillpower += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 3: + playerAffected->uEndurance += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 4: + playerAffected->uAccuracy += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 5: + playerAffected->uSpeed += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 6: + playerAffected->uLuck += thisa; + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" + break; + case 7: + pParty->PartyFindsGold(1000 * thisa, 0); + sprintf(pTmpBuf.data(), "+%u %s", 1000 * thisa, pGlobalTXT_LocalizationStrings[97]);//"Gold" + break; + case 8: + Party::GiveFood(5 * thisa); + sprintf(pTmpBuf.data(), "+%u %s",5 * thisa , pGlobalTXT_LocalizationStrings[653]);//"Food" + break; + case 9u: + playerAffected->uSkillPoints += 2 * thisa; + sprintf(pTmpBuf.data(), "+%u %s", 2 * thisa, pGlobalTXT_LocalizationStrings[LOCSTR_SKILL_POINTS]); + break; + case 10: + playerAffected->uExperience += 2500 * thisa; + sprintf(pTmpBuf.data(), "+%u %s", 2500 * thisa, pGlobalTXT_LocalizationStrings[LOCSTR_EXPIRIENCE]); + break; + case 11: + v8 = rand() % 6; + switch (v8) + { + case 0: + playerAffected->sResFireBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[87];//Fire + break; + case 1: + playerAffected->sResAirBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[6];//Air + break; + case 2: + playerAffected->sResWaterBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[240];//Water + break; + case 3: + playerAffected->sResEarthBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[70];//Earth + break; + case 4: + playerAffected->sResMindBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[142];//Mind + break; + case 5: + playerAffected->sResBodyBase += thisa; + v13 = pGlobalTXT_LocalizationStrings[29];//Body + break; + default: ("Unexpected attribute"); + return; + } + sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v13, pGlobalTXT_LocalizationStrings[121]);//Permanent + break; + + } + ShowStatusBarString(pTmpBuf.data(), 2u); + pMouse->RemoveHoldingItem(); + pGame->pStru6Instance->SetPlayerBuffAnim(SPELL_QUEST_COMPLETED, player_num - 1); + playerAffected->PlaySound(SPEECH_93, 0); + pAudioPlayer->PlaySound((SoundID)219, 0, 0, -1, 0, 0, 0, 0); + if ( pParty->uDaysPlayed == 6 || pParty->uDaysPlayed == 20 ) + { + playerAffected->SetCondition(Condition_Eradicated, 0); + pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); + } + else if ( pParty->uDaysPlayed == 12 || pParty->uDaysPlayed == 26 ) + { + playerAffected->SetCondition(Condition_Dead, 0); + pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); + } + else if ( pParty->uDaysPlayed == 4 || pParty->uDaysPlayed == 25 ) + { + playerAffected->SetCondition(Condition_Pertified, 0); + pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); + } + return; + } + else if ( pParty->pPickedItem.uItemID == 630 ) //Red Apple + { + Party::GiveFood(1u); + pAudioPlayer->PlaySound(SOUND_EatApple, 0, 0, -1, 0, 0, 0, 0); + } + else if ( pParty->pPickedItem.uItemID == 632 ) //Lute + { + pAudioPlayer->PlaySound(SOUND_PlayLute, 0, 0, -1, 0, 0, 0, 0); + return; + } + else if ( pParty->pPickedItem.uItemID == 633 ) //Faerie Pipes + { + pAudioPlayer->PlaySound(SOUND_PlayFaeriePipes, 0, 0, -1, 0, 0, 0, 0); + return; + } + else if ( pParty->pPickedItem.uItemID == 634 ) //Gryphonheart's Trumpet + { + pAudioPlayer->PlaySound(SOUND_PlayGryphonheartsTrumpet, 0, 0, -1, 0, 0, 0, 0); + return; + } + else if ( pParty->pPickedItem.uItemID == 646 ) //Horseshoe + { + pGame->pStru6Instance->SetPlayerBuffAnim(SPELL_QUEST_COMPLETED, player_num - 1); + v5 = PID(OBJECT_Player, player_num + 49); + pAudioPlayer->PlaySound(SOUND_20001, v5, 0, -1, 0, 0, 0, 0); + playerAffected->AddVariable(VAR_NumSkillPoints, 2); + } + else if ( pParty->pPickedItem.uItemID == 650 ) //Temple in a Bottle + { + TeleportToNWCDungeon(); + return; + } + else + { + v68 = pParty->pPickedItem.GetDisplayName(); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36],v68);//"%s can not be used that way" + ShowStatusBarString(pTmpBuf.data(), 2u); + pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); + return; + } + + pMouse->RemoveHoldingItem(); + return; + } +} + +bool CmpSkillValue(int valToCompare, int skillValue) +{ + int v4; + if ( valToCompare <= 63 ) + v4 = skillValue & 0x3F; + else + v4 = skillValue & skillValue; + return v4 >= valToCompare; +} + +//----- (00449BB4) -------------------------------------------------------- +bool Player::CompareVariable( enum VariableType VarNum, signed int pValue ) // in some cases this calls only calls v4 >= pValue, which i've changed to return false, since these values are supposed to be positive and v4 was -1 by default +{ + Assert(pValue >= 0, "Compare variable shouldn't have negative arguments"); + + signed int v4; // edi@1 + unsigned __int8 test_bit_value; // eax@25 + unsigned __int8 byteWithRequestedBit; // cl@25 + DDM_DLV_Header *v19; // eax@122 + DDM_DLV_Header *v21; // eax@126 + int actStat; // ebx@161 + int baseStat; // eax@161 + + + if ( (signed int)VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_74 ) + return (unsigned __int8)stru_5E4C90_MapPersistVars.field_0[VarNum - VAR_MapPersistentVariable_0] > 0; // originally (unsigned __int8)byte_5E4C15[VarNum]; + if ( (signed int)VarNum >= VAR_MapPersistentVariable_75 && VarNum <= VAR_MapPersistentVariable_99 ) + return (unsigned __int8)stru_5E4C90_MapPersistVars._decor_events[VarNum - VAR_MapPersistentVariable_75] > 0; //not really sure whether the number gets up to 99, but can't ignore the possibility + + switch ( VarNum ) + { + case VAR_Sex: + return ( pValue == this->uSex ); + case VAR_Class: + return ( pValue == this->classType ); + case VAR_Race: + return pValue == GetRace(); + case VAR_CurrentHP: + return this->sHealth >= pValue; + case VAR_MaxHP: + return (this->sHealth >= GetMaxHealth()); + case VAR_CurrentSP: + return this->sMana >= pValue; + case VAR_MaxSP: + return (this->sMana >= GetMaxMana()); + case VAR_ActualAC: + return GetActualAC() >= pValue; + case VAR_ACModifier: + return this->sACModifier >= pValue; + case VAR_BaseLevel: + return this->uLevel >= pValue; + case VAR_LevelModifier: + return this->sLevelModifier >= pValue; + case VAR_Age: + return GetActualAge() >= (unsigned int)pValue; + case VAR_Award: + return _449B57_test_bit(this->_achieved_awards_bits, pValue); + case VAR_Experience: + return this->uExperience >= pValue; //TODO change pValue to long long + case VAR_QBits_QuestsDone: + return _449B57_test_bit(pParty->_quest_bits, pValue); + case VAR_PlayerItemInHands: + //for (int i = 0; i < 138; i++) + for (int i = 0; i < 126; i++) + { + if (pInventoryItemList[i].uItemID == pValue) + { + return true; + } + } + return pParty->pPickedItem.uItemID == pValue; + case VAR_Hour: + if ( (long long)(pParty->uTimePlayed * 0.234375) / 60 / 60 % 24 == pValue ) + return true; + return false; + case VAR_DayOfYear: + if (((long long)(pParty->uTimePlayed * 0.234375) / 60 / 60) / 24 % 336 + 1 == pValue) + return true; + return false; + case VAR_DayOfWeek: + if (((long long)(pParty->uTimePlayed * 0.234375) / 60 / 60) / 24 % 7) + return true; + return false; + case VAR_FixedGold: + return pParty->uNumGold >= (unsigned int)pValue; + case VAR_FixedFood: + return pParty->uNumFoodRations >= (unsigned int)pValue; + case VAR_MightBonus: + return this->uMightBonus >= pValue; + case VAR_IntellectBonus: + return this->uIntelligenceBonus >= pValue; + case VAR_PersonalityBonus: + return this->uWillpowerBonus >= pValue; + case VAR_EnduranceBonus: + return this->uEnduranceBonus >= pValue; + case VAR_SpeedBonus: + return this->uSpeedBonus >= pValue; + case VAR_AccuracyBonus: + return this->uAccuracyBonus >= pValue; + case VAR_LuckBonus: + return this->uLuckBonus >= pValue; + case VAR_BaseMight: + return this->uMight >= pValue; + case VAR_BaseIntellect: + return this->uIntelligence >= pValue; + case VAR_BasePersonality: + return this->uWillpower >= pValue; + case VAR_BaseEndurance: + return this->uEndurance >= pValue; + case VAR_BaseSpeed: + return this->uSpeed >= pValue; + case VAR_BaseAccuracy: + return this->uAccuracy >= pValue; + case VAR_BaseLuck: + return this->uLuck >= pValue; + case VAR_ActualMight: + return GetActualMight() >= pValue; + case VAR_ActualIntellect: + return GetActualIntelligence() >= pValue; + case VAR_ActualPersonality: + return GetActualWillpower() >= pValue; + case VAR_ActualEndurance: + return GetActualEndurance() >= pValue; + case VAR_ActualSpeed: + return GetActualSpeed() >= pValue; + case VAR_ActualAccuracy: + return GetActualAccuracy() >= pValue; + case VAR_ActualLuck: + return GetActualLuck() >= pValue; + case VAR_FireResistance: + return this->sResFireBase >= pValue; + case VAR_AirResistance: + return this->sResAirBase >= pValue; + case VAR_WaterResistance: + return this->sResWaterBase >= pValue; + case VAR_EarthResistance: + return this->sResEarthBase >= pValue; + case VAR_SpiritResistance: + return this->sResSpiritBase >= pValue; + case VAR_MindResistance: + return this->sResMindBase >= pValue; + case VAR_BodyResistance: + return this->sResBodyBase >= pValue; + case VAR_LightResistance: + return this->sResLightBase >= pValue; + case VAR_DarkResistance: + return this->sResDarkBase >= pValue; + case VAR_PhysicalResistance: + Error("Physical resistance isn't used in events"); + return false; + case VAR_MagicResistance: + return this->sResMagicBase >= pValue; + case VAR_FireResistanceBonus: + return this->sResFireBonus >= pValue; + case VAR_AirResistanceBonus: + return this->sResAirBonus >= pValue; + case VAR_WaterResistanceBonus: + return this->sResWaterBonus >= pValue; + case VAR_EarthResistanceBonus: + return this->sResEarthBonus >= pValue; + case VAR_SpiritResistanceBonus: + return this->sResSpiritBonus >= pValue; + case VAR_MindResistanceBonus: + return this->sResMindBonus >= pValue; + case VAR_BodyResistanceBonus: + return this->sResBodyBonus >= pValue; + case VAR_LightResistanceBonus: + return this->sResLightBonus >= pValue; + case VAR_DarkResistanceBonus: + return this->sResDarkBonus >= pValue; + case VAR_MagicResistanceBonus: + return this->sResMagicBonus >= pValue; + case VAR_StaffSkill: + return CmpSkillValue(pValue, this->skillStaff); + case VAR_SwordSkill: + return CmpSkillValue(pValue, this->skillSword); + case VAR_DaggerSkill: + return CmpSkillValue(pValue, this->skillDagger); + case VAR_AxeSkill: + return CmpSkillValue(pValue, this->skillAxe); + case VAR_SpearSkill: + return CmpSkillValue(pValue, this->skillSpear); + case VAR_BowSkill: + return CmpSkillValue(pValue, this->skillBow); + case VAR_MaceSkill: + return CmpSkillValue(pValue, this->skillMace); + case VAR_BlasterSkill: + return CmpSkillValue(pValue, this->skillBlaster); + case VAR_ShieldSkill: + return CmpSkillValue(pValue, this->skillShield); + case VAR_LeatherSkill: + return CmpSkillValue(pValue, this->skillLeather); + case VAR_SkillChain: + return CmpSkillValue(pValue, this->skillChain); + case VAR_PlateSkill: + return CmpSkillValue(pValue, this->skillPlate); + case VAR_FireSkill: + return CmpSkillValue(pValue, this->skillFire); + case VAR_AirSkill: + return CmpSkillValue(pValue, this->skillAir); + case VAR_WaterSkill: + return CmpSkillValue(pValue, this->skillWater); + case VAR_EarthSkill: + return CmpSkillValue(pValue, this->skillEarth); + case VAR_SpiritSkill: + return CmpSkillValue(pValue, this->skillSpirit); + case VAR_MindSkill: + return CmpSkillValue(pValue, this->skillMind); + case VAR_BodySkill: + return CmpSkillValue(pValue, this->skillBody); + case VAR_LightSkill: + return CmpSkillValue(pValue, this->skillLight); + case VAR_DarkSkill: + return CmpSkillValue(pValue, this->skillDark); + case VAR_IdentifyItemSkill: + return CmpSkillValue(pValue, this->skillItemId); + case VAR_MerchantSkill: + return CmpSkillValue(pValue, this->skillMerchant); + case VAR_RepairSkill: + return CmpSkillValue(pValue, this->skillRepair); + case VAR_BodybuildingSkill: + return CmpSkillValue(pValue, this->skillBodybuilding); + case VAR_MeditationSkill: + return CmpSkillValue(pValue, this->skillMeditation); + case VAR_PerceptionSkill: + return CmpSkillValue(pValue, this->skillPerception); + case VAR_DiplomacySkill: + return CmpSkillValue(pValue, this->skillDiplomacy); + case VAR_ThieverySkill: + Error("Thievery isn't used in events"); + return false; + case VAR_DisarmTrapSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillDisarmTrap); + case VAR_DodgeSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillDodge); + case VAR_UnarmedSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillUnarmed); + case VAR_IdentifyMonsterSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillMonsterId); + case VAR_ArmsmasterSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillArmsmaster); + case VAR_StealingSkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillStealing); + case VAR_AlchemySkill: //wasn't in the original + return CmpSkillValue(pValue, this->skillAlchemy); + case VAR_LearningSkill: + return CmpSkillValue(pValue, this->skillLearning); + case VAR_Cursed: + return pConditions[Condition_Cursed] > 0; + case VAR_Weak: + return pConditions[Condition_Weak] > 0; + case VAR_Asleep: + return pConditions[Condition_Sleep] > 0; + case VAR_Afraid: + return pConditions[Condition_Fear] > 0; + case VAR_Drunk: + return pConditions[Condition_Drunk] > 0; + case VAR_Insane: + return pConditions[Condition_Insane] > 0; + case VAR_PoisonedGreen: + return pConditions[Condition_Poison_Weak] > 0; + case VAR_DiseasedGreen: + return pConditions[Condition_Disease_Weak] > 0; + case VAR_PoisonedYellow: + return pConditions[Condition_Poison_Medium] > 0; + case VAR_DiseasedYellow: + return pConditions[Condition_Disease_Medium] > 0; + case VAR_PoisonedRed: + return pConditions[Condition_Poison_Severe] > 0; + case VAR_DiseasedRed: + return pConditions[Condition_Disease_Severe] > 0; + case VAR_Paralyzed: + return pConditions[Condition_Paralyzed] > 0; + case VAR_Unconsious: + return pConditions[Condition_Unconcious] > 0; + case VAR_Dead: + return pConditions[Condition_Dead] > 0; + case VAR_Stoned: + return pConditions[Condition_Pertified] > 0; + case VAR_Eradicated: + return pConditions[Condition_Eradicated] > 0; + case VAR_MajorCondition: + v4 = GetMajorConditionIdx(); + if ( v4 != 18 ) + { + return v4 >= pValue; + } + return true; + case VAR_AutoNotes : //TODO: find out why the double subtraction. or whether this is even used + test_bit_value = 0x80u >> (pValue - 2) % 8; + byteWithRequestedBit = pParty->_autonote_bits[(pValue - 2) /8]; + return (test_bit_value & byteWithRequestedBit) != 0; + case VAR_IsMightMoreThanBase: + actStat = GetActualMight(); + baseStat = GetBaseStrength(); + return (actStat >= baseStat); + case VAR_IsIntellectMoreThanBase: + actStat = GetActualIntelligence(); + baseStat = GetBaseIntelligence(); + return (actStat >= baseStat); + case VAR_IsPersonalityMoreThanBase: + actStat = GetActualWillpower(); + baseStat = GetBaseWillpower(); + return (actStat >= baseStat); + case VAR_IsEnduranceMoreThanBase: + actStat = GetActualEndurance(); + baseStat = GetBaseEndurance(); + return (actStat >= baseStat); + case VAR_IsSpeedMoreThanBase: + actStat = GetActualSpeed(); + baseStat = GetBaseSpeed(); + return (actStat >= baseStat); + case VAR_IsAccuracyMoreThanBase: + actStat = GetActualAccuracy(); + baseStat = GetBaseAccuracy(); + return (actStat >= baseStat); + case VAR_IsLuckMoreThanBase: + actStat = GetActualLuck(); + baseStat = GetBaseLuck(); + return (actStat >= baseStat); + case VAR_PlayerBits: + test_bit_value = 0x80u >> ((signed __int16)pValue - 1) % 8; + byteWithRequestedBit = this->playerEventBits[((signed __int16)pValue - 1)/8]; + return ( test_bit_value & byteWithRequestedBit ) != 0; + case VAR_NPCs2: + return pNPCStats->pNewNPCData[pValue].Hired(); + case VAR_IsFlying: + if ( pParty->bFlying + && (pParty->pPartyBuffs[PARTY_BUFF_FLY].uExpireTime> 0) ) + return true; + return false; + case VAR_HiredNPCHasSpeciality: + return CheckHiredNPCSpeciality(pValue); + case VAR_CircusPrises: //isn't used in MM6 since 0x1D6u is a book of regeneration + v4 = 0; + for (int playerNum = 0; playerNum < 4; playerNum++) + { + for (int invPos = 0; invPos < 138; invPos++) + { + int itemId = pParty->pPlayers[playerNum].pInventoryItemList[invPos].uItemID; + switch ( itemId ) + { + case 0x1D6u: + ++v4; + break; + case 0x1D7u: + v4 += 3; + break; + case 0x1DDu: + v4 += 5; + break; + } + } + } + return v4 >= pValue; + case VAR_NumSkillPoints: + return this->uSkillPoints >= (unsigned int)pValue; + case VAR_MonthIs: + return (pParty->uCurrentMonth == (unsigned int)pValue); + case VAR_Counter1: + case VAR_Counter2: + case VAR_Counter3: + case VAR_Counter4: + case VAR_Counter5: + case VAR_Counter6: + case VAR_Counter7: + case VAR_Counter8: + case VAR_Counter9: + case VAR_Counter10: + if (pParty->PartyTimes.CounterEventValues[VarNum - VAR_Counter1]) //originally (signed __int64)(__PAIR__(*(int *)&stru_AA1058[3].pSounds[8 * VarNum + 44304], *(int *)&stru_AA1058[3].pSounds[8 * VarNum + 44300]) + { + return (pParty->PartyTimes.CounterEventValues[VarNum - VAR_Counter1] + 460800 * pValue * 0.033333335) <= pParty->uTimePlayed ; + } + case VAR_ReputationInCurrentLocation: + v19 = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) + v19 = &pIndoor->dlv; + return (v19->uReputation >= pValue); + case VAR_Unknown1: + v21 = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) + v21 = &pIndoor->dlv; + return (v21->field_C_alert == pValue); //yes, equality, not >= + case VAR_GoldInBank: + return pParty->uNumGoldInBank >= (unsigned int)pValue; + case VAR_NumDeaths: + return pParty->uNumDeaths >= (unsigned int)pValue; + case VAR_NumBounties: + return pParty->uNumBountiesCollected >= (unsigned int)pValue; + case VAR_PrisonTerms: + return pParty->uNumPrisonTerms >= pValue; + case VAR_ArenaWinsPage: + return (unsigned __int8)pParty->uNumArenaPageWins >= pValue; + case VAR_ArenaWinsSquire: + return (unsigned __int8)pParty->uNumArenaSquireWins >= pValue; + case VAR_ArenaWinsKnight: + return (unsigned __int8)pParty->uNumArenaKnightWins >= pValue; + case VAR_ArenaWinsLord: + return pParty->uNumArenaLordWins >= pValue; + case VAR_Invisible: + return ( pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime > 0 ); + case VAR_ItemEquipped: + for (int i = 0; i < 16; i++) + { + if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) && GetNthEquippedIndexItem(i)->uItemID == pValue ) + { + return true; + } + } + return false; + } + + return false; +} + + +//----- (0044A5CB) -------------------------------------------------------- +void Player::SetVariable(enum VariableType var_type, signed int var_value) +{ + unsigned int v6; // esi@13 + unsigned int v7; // esi@14 + signed int v11; // eax@30 + DDM_DLV_Header *v24; // ecx@148 + ItemGen item; // [sp+Ch] [bp-28h]@52 + + + if ( var_type >= VAR_History_0 && var_type <= VAR_History_28) + { + if (!pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0]) + { + pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0] = pParty->uTimePlayed; + if (pStorylineText->StoreLine[var_type - VAR_History_0].pText) + { + bFlashHistoryBook = 1; + PlayAwardSound(); + } + } + return; + } + + if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_99 ) + { + if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_74 ) + stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] = (char)var_value; // originally (unsigned __int8)byte_5E4C15[VarNum]; + if ( var_type >= VAR_MapPersistentVariable_75 && var_type <= VAR_MapPersistentVariable_99 ) + stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] = (unsigned char)var_value; //not really sure whether the number gets up to 99, but can't ignore the possibility + return; + } + + if ( var_type >= VAR_UnknownTimeEvent0 && var_type <= VAR_UnknownTimeEvent19 ) + { + pParty->PartyTimes._s_times[var_type - VAR_UnknownTimeEvent0] = pParty->uTimePlayed; //*(int *)&stru_AA1058[3].pSounds[8 * var_type + 44532] = LODWORD(pParty->uTimePlayed);, *(int *)&stru_AA1058[3].pSounds[8 * var_type + 44536] = HIDWORD(pParty->uTimePlayed + PlayAwardSound(); + return; + } + + switch ( var_type ) + { + case VAR_Sex: + this->uSex = (PLAYER_SEX)var_value; + PlayAwardSound_Anim(); + return; + case VAR_Class: + this->classType = (PLAYER_CLASS_TYPE)var_value; + if ( (PLAYER_CLASS_TYPE)var_value == PLAYER_CLASS_LICH ) + { + for (int i = 0; i < 138; i++) + { + if (this->pOwnItems[i].uItemID == ITEM_LICH_JAR_EMPTY) + { + this->pOwnItems[i].uItemID = ITEM_LICH_JAR_FULL; + this->pOwnItems[i].uHolderPlayer = GetPlayerIndex() + 1; + } + } + if ( this->sResFireBase < 20 ) + this->sResFireBase = 20; + if ( this->sResAirBase < 20 ) + this->sResAirBase = 20; + if ( this->sResWaterBase < 20 ) + this->sResWaterBase = 20; + if ( this->sResEarthBase < 20 ) + this->sResEarthBase = 20; + this->sResMindBase = 200; + this->sResBodyBase = 200; + v11 = this->GetSexByVoice(); + this->uPrevVoiceID = this->uVoiceID; + this->uPrevFace = this->uCurrentFace; + if ( v11 ) + { + this->uCurrentFace = 21; + this->uVoiceID = 21; + } + else + { + this->uCurrentFace = 20; + this->uVoiceID = 20; + } + ReloadPlayerPortraits(GetPlayerIndex(), this->uCurrentFace); + } + PlayAwardSound_Anim(); + return; + case VAR_CurrentHP: + this->sHealth = var_value; + PlayAwardSound_Anim(); + return; + case VAR_MaxHP: + this->sHealth = GetMaxHealth(); + return; + case VAR_CurrentSP: + this->sMana = var_value; + PlayAwardSound_Anim(); + return; + case VAR_MaxSP: + this->sMana = GetMaxMana(); + return; + case VAR_ACModifier: + this->sACModifier = (unsigned __int8)var_value; + PlayAwardSound_Anim(); + return; + case VAR_BaseLevel: + this->uLevel = (unsigned __int8)var_value; + PlayAwardSound_Anim(); + return; + case VAR_LevelModifier: + this->sLevelModifier = (unsigned __int8)var_value; + PlayAwardSound_Anim(); + return; + case VAR_Age: + this->sAgeModifier = var_value; + return; + case VAR_Award: + if ( !_449B57_test_bit(this->_achieved_awards_bits, var_value) && pAwards[var_value].pText ) + { + PlayAwardSound_Anim(); + this->PlaySound(SPEECH_96, 0); + } + _449B7E_toggle_bit(this->_achieved_awards_bits, var_value, 1u); + return; + case VAR_Experience: + this->uExperience = var_value; + PlayAwardSound_Anim(); + return; + case VAR_QBits_QuestsDone: + if ( !_449B57_test_bit(pParty->_quest_bits, var_value) && pQuestTable[var_value-1] ) + { + bFlashQuestBook = 1; + pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, GetPlayerIndex()); + PlayAwardSound(); + this->PlaySound(SPEECH_93, 0); + } + _449B7E_toggle_bit(pParty->_quest_bits, var_value, 1u); + return; + case VAR_PlayerItemInHands: + item.Reset(); + item.uItemID = var_value; + item.uAttributes = 1; + pParty->SetHoldingItem(&item); + if ( var_value >= ITEM_ARTIFACT_PUCK && var_value <= ITEM_RELIC_MEKORIGS_HAMMER ) + pParty->pIsArtifactFound[var_value-500] = 1; + return; + case VAR_FixedGold: + Party::SetGold(var_value); + return; + case VAR_RandomGold: + v6 = rand() % var_value + 1; + Party::SetGold(v6); + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[500], v6);// You have %lu gold + ShowStatusBarString(pTmpBuf.data(), 2u); + GameUI_DrawFoodAndGold(); + return; + case VAR_FixedFood: + Party::SetFood(var_value); + PlayAwardSound_Anim(); + return; + case VAR_RandomFood: + v7 = rand() % var_value + 1; + Party::SetFood(v7); + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[501], v7);// You have %lu food + ShowStatusBarString(pTmpBuf.data(), 2u); + GameUI_DrawFoodAndGold(); + PlayAwardSound_Anim(); + return; + case VAR_BaseMight: + this->uMight = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BaseIntellect: + this->uIntelligence = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BasePersonality: + this->uWillpower = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BaseEndurance: + this->uEndurance = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BaseSpeed: + this->uSpeed = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BaseAccuracy: + this->uAccuracy = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BaseLuck: + this->uLuck = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_MightBonus: + case VAR_ActualMight: + this->uMightBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_IntellectBonus: + case VAR_ActualIntellect: + this->uIntelligenceBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_PersonalityBonus: + case VAR_ActualPersonality: + this->uWillpowerBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_EnduranceBonus: + case VAR_ActualEndurance: + this->uEnduranceBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_SpeedBonus: + case VAR_ActualSpeed: + this->uSpeedBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_AccuracyBonus: + case VAR_ActualAccuracy: + this->uAccuracyBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_LuckBonus: + case VAR_ActualLuck: + this->uLuckBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_FireResistance: + this->sResFireBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_AirResistance: + this->sResAirBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_WaterResistance: + this->sResWaterBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_EarthResistance: + this->sResEarthBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_SpiritResistance: + this->sResSpiritBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_MindResistance: + this->sResMindBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_BodyResistance: + this->sResBodyBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_LightResistance: + this->sResLightBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_DarkResistance: + this->sResDarkBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_MagicResistance: + this->sResMagicBase = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_92); + return; + case VAR_FireResistanceBonus: + this->sResFireBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_AirResistanceBonus: + this->sResAirBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_WaterResistanceBonus: + this->sResWaterBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_EarthResistanceBonus: + this->sResEarthBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_SpiritResistanceBonus: + this->sResSpiritBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_MindResistanceBonus: + this->sResMindBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_BodyResistanceBonus: + this->sResBodyBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_LightResistanceBonus: + this->sResLightBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_DarkResistanceBonus: + this->sResDarkBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_PhysicalResistanceBonus: + Error("Physical res. bonus not used"); + return; + case VAR_MagicResistanceBonus: + this->sResMagicBonus = (unsigned __int8)var_value; + PlayAwardSound_Anim_Face(SPEECH_91); + return; + case VAR_Cursed: + this->SetCondition(Condition_Cursed, 1); + PlayAwardSound_Anim(); + return; + case VAR_Weak: + this->SetCondition(Condition_Weak, 1); + PlayAwardSound_Anim(); + return; + case VAR_Asleep: + this->SetCondition(Condition_Sleep, 1); + PlayAwardSound_Anim(); + return; + case VAR_Afraid: + this->SetCondition(Condition_Fear, 1); + PlayAwardSound_Anim(); + return; + case VAR_Drunk: + this->SetCondition(Condition_Drunk, 1); + PlayAwardSound_Anim(); + return; + case VAR_Insane: + this->SetCondition(Condition_Insane, 1); + PlayAwardSound_Anim(); + return; + case VAR_PoisonedGreen: + this->SetCondition(Condition_Poison_Weak, 1); + PlayAwardSound_Anim(); + return; + case VAR_DiseasedGreen: + this->SetCondition(Condition_Disease_Weak, 1); + PlayAwardSound_Anim(); + return; + case VAR_PoisonedYellow: + this->SetCondition(Condition_Poison_Medium, 1); + PlayAwardSound_Anim(); + return; + case VAR_DiseasedYellow: + this->SetCondition(Condition_Disease_Medium, 1); + PlayAwardSound_Anim(); + return; + case VAR_PoisonedRed: + this->SetCondition(Condition_Poison_Severe, 1); + PlayAwardSound_Anim(); + return; + case VAR_DiseasedRed: + this->SetCondition(Condition_Disease_Severe, 1); + PlayAwardSound_Anim(); + return; + case VAR_Paralyzed: + this->SetCondition(Condition_Paralyzed, 1); + PlayAwardSound_Anim(); + return; + case VAR_Unconsious: + this->SetCondition(Condition_Unconcious, 1); + PlayAwardSound_Anim(); + return; + case VAR_Dead: + this->SetCondition(Condition_Dead, 1); + PlayAwardSound_Anim(); + return; + case VAR_Stoned: + this->SetCondition(Condition_Pertified, 1); + PlayAwardSound_Anim(); + return; + case VAR_Eradicated: + this->SetCondition(Condition_Eradicated, 1); + PlayAwardSound_Anim(); + return; + case VAR_MajorCondition: + pConditions.fill(0); + PlayAwardSound_Anim(); + return; + case VAR_AutoNotes: + if ( !_449B57_test_bit(pParty->_autonote_bits, var_value) && pAutonoteTxt[var_value-1].pText ) + { + pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, GetPlayerIndex()); + this->PlaySound(SPEECH_96, 0); + bFlashAutonotesBook = 1; + _506568_autonote_type = pAutonoteTxt[var_value-1].eType;// dword_72371C[2 * a3]; + } + _449B7E_toggle_bit(pParty->_autonote_bits, var_value, 1u); + PlayAwardSound(); + return; + case VAR_PlayerBits: + _449B7E_toggle_bit((unsigned char *)playerEventBits, var_value, 1u); + return; + case VAR_NPCs2: + pParty->hirelingScrollPosition = 0; + LOBYTE(pNPCStats->pNewNPCData[var_value].uFlags) |= 0x80u; + pParty->CountHirelings(); + viewparams->bRedrawGameUI = true; + return; + case VAR_NumSkillPoints: + this->uSkillPoints = var_value; + return; + case VAR_Counter1: + case VAR_Counter2: + case VAR_Counter3: + case VAR_Counter4: + case VAR_Counter5: + case VAR_Counter6: + case VAR_Counter7: + case VAR_Counter8: + case VAR_Counter9: + case VAR_Counter10: + pParty->PartyTimes.CounterEventValues[var_type - VAR_Counter1] = pParty->uTimePlayed; // *(int *)&stru_AA1058[3].pSounds[8 * var_type + 44300] = LODWORD(pParty->uTimePlayed);*(int *)&stru_AA1058[3].pSounds[8 * var_type + 44304] = HIDWORD(pParty->uTimePlayed); + return; + case VAR_ReputationInCurrentLocation: + v24 = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) + v24 = &pIndoor->dlv; + v24->uReputation = var_value; + if ( var_value > 10000 ) + v24->uReputation = 10000; + return; + case VAR_GoldInBank: + pParty->uNumGoldInBank = var_value; + return; + case VAR_NumDeaths: + pParty->uNumDeaths = var_value; + return; + case VAR_NumBounties: + pParty->uNumBountiesCollected = var_value; + return; + case VAR_PrisonTerms: + pParty->uNumPrisonTerms = var_value; + return; + case VAR_ArenaWinsPage: + pParty->uNumArenaPageWins = var_value; + return; + case VAR_ArenaWinsSquire: + pParty->uNumArenaSquireWins = var_value; + return; + case VAR_ArenaWinsKnight: + pParty->uNumArenaKnightWins = var_value; + return; + case VAR_ArenaWinsLord: + pParty->uNumArenaLordWins = var_value; + return; + case VAR_StaffSkill: + SetSkillByEvent(&Player::skillStaff, var_value); + return; + case VAR_SwordSkill: + SetSkillByEvent(&Player::skillSword, var_value); + return; + case VAR_DaggerSkill: + SetSkillByEvent(&Player::skillDagger, var_value); + return; + case VAR_AxeSkill: + SetSkillByEvent(&Player::skillAxe, var_value); + return; + case VAR_SpearSkill: + SetSkillByEvent(&Player::skillSpear, var_value); + return; + case VAR_BowSkill: + SetSkillByEvent(&Player::skillBow, var_value); + return; + case VAR_MaceSkill: + SetSkillByEvent(&Player::skillMace, var_value); + return; + case VAR_BlasterSkill: + SetSkillByEvent(&Player::skillBlaster, var_value); + return; + case VAR_ShieldSkill: + SetSkillByEvent(&Player::skillShield, var_value); + return; + case VAR_LeatherSkill: + SetSkillByEvent(&Player::skillLeather, var_value); + return; + case VAR_SkillChain: + SetSkillByEvent(&Player::skillChain, var_value); + return; + case VAR_PlateSkill: + SetSkillByEvent(&Player::skillPlate, var_value); + return; + case VAR_FireSkill: + SetSkillByEvent(&Player::skillFire, var_value); + return; + case VAR_AirSkill: + SetSkillByEvent(&Player::skillAir, var_value); + return; + case VAR_WaterSkill: + SetSkillByEvent(&Player::skillWater, var_value); + return; + case VAR_EarthSkill: + SetSkillByEvent(&Player::skillEarth, var_value); + return; + case VAR_SpiritSkill: + SetSkillByEvent(&Player::skillSpirit, var_value); + return; + case VAR_MindSkill: + SetSkillByEvent(&Player::skillMind, var_value); + return; + case VAR_BodySkill: + SetSkillByEvent(&Player::skillBody, var_value); + return; + case VAR_LightSkill: + SetSkillByEvent(&Player::skillLight, var_value); + return; + case VAR_DarkSkill: + SetSkillByEvent(&Player::skillDark, var_value); + return; + case VAR_IdentifyItemSkill: + SetSkillByEvent(&Player::skillItemId, var_value); + return; + case VAR_MerchantSkill: + SetSkillByEvent(&Player::skillMerchant, var_value); + return; + case VAR_RepairSkill: + SetSkillByEvent(&Player::skillRepair, var_value); + return; + case VAR_BodybuildingSkill: + SetSkillByEvent(&Player::skillBodybuilding, var_value); + return; + case VAR_MeditationSkill: + SetSkillByEvent(&Player::skillMeditation, var_value); + return; + case VAR_PerceptionSkill: + SetSkillByEvent(&Player::skillPerception, var_value); + return; + case VAR_DiplomacySkill: + SetSkillByEvent(&Player::skillDiplomacy, var_value); + return; + case VAR_ThieverySkill: + Error ("Thieving unsupported"); + return; + case VAR_DisarmTrapSkill: + SetSkillByEvent(&Player::skillDisarmTrap, var_value); + return; + case VAR_DodgeSkill: + SetSkillByEvent(&Player::skillDodge, var_value); + return; + case VAR_UnarmedSkill: + SetSkillByEvent(&Player::skillUnarmed, var_value); + return; + case VAR_IdentifyMonsterSkill: + SetSkillByEvent(&Player::skillMonsterId, var_value); + return; + case VAR_ArmsmasterSkill: + SetSkillByEvent(&Player::skillArmsmaster, var_value); + return; + case VAR_StealingSkill: + SetSkillByEvent(&Player::skillStealing, var_value); + return; + case VAR_AlchemySkill: + SetSkillByEvent(&Player::skillAlchemy, var_value); + return; + case VAR_LearningSkill: + SetSkillByEvent(&Player::skillLearning, var_value); + return; + } +} + + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound() +{ + int playerIndex = GetPlayerIndex(); + signed int v25 = 8 * playerIndex + 400; + LOBYTE(v25) = PID(OBJECT_Player,playerIndex - 112); + pAudioPlayer->PlaySound(SOUND_20001, v25, 0, -1, 0, 0, 0, 0); +} + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim() +{ + int playerIndex = GetPlayerIndex(); + pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, playerIndex); + PlayAwardSound(); +} + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim_Face( PlayerSpeech speech ) +{ + this->PlaySound(speech, 0); + PlayAwardSound_Anim(); +} + +//----- (new function) -------------------------------------------------------- +void Player::SetSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 skillValue ) +{ + unsigned __int16 currSkillValue = this->*skillToSet; + if ( skillValue > 63 ) //the original had the condition reversed which was probably wrong + { + this->*skillToSet = skillValue | currSkillValue & 63; + } + else + { + this->*skillToSet = skillValue | currSkillValue & 0xC0; + } + int playerIndex = GetPlayerIndex(); + pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, playerIndex); + PlayAwardSound(); +} + +//----- (0044AFFB) -------------------------------------------------------- +void Player::AddVariable(enum VariableType var_type, signed int val) +{ + int v6; // eax@15 + unsigned int v7; // esi@18 + DDM_DLV_Header *v27; // eax@153 + ItemGen item; // [sp+Ch] [bp-2Ch]@45 + + if ( var_type >= VAR_Counter1 && var_type <= VAR_Counter10) + { + pParty->PartyTimes.CounterEventValues[var_type - VAR_Counter1] = pParty->uTimePlayed; + return; + } + + if ( var_type >= VAR_UnknownTimeEvent0 && var_type <= VAR_UnknownTimeEvent19 ) + { + pParty->PartyTimes._s_times[var_type - VAR_UnknownTimeEvent0] = pParty->uTimePlayed; + PlayAwardSound(); + return; + } + + if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_99 ) + { + + if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_74 ) + { + if (255 - val > stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0]) + stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] += val; + else + stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] = 255; + } + if ( (signed int)var_type >= VAR_MapPersistentVariable_75 && var_type <= VAR_MapPersistentVariable_99 ) + { + if (255 - val > stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75]) + stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] += val; + else + stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] = 255; + } + return; + } + + if ( var_type >= VAR_History_0 && var_type <= VAR_History_28) + { + if (!pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0]) + { + pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0] = pParty->uTimePlayed; + if (pStorylineText->StoreLine[var_type - VAR_History_0].pText = 0) + { + bFlashHistoryBook = 1; + PlayAwardSound(); + } + } + return; + } + + switch ( var_type ) + { + case VAR_RandomGold: + if ( val == 0 ) + val = 1; + v6 = rand(); + pParty->PartyFindsGold(v6 % val + 1, 1); + GameUI_DrawFoodAndGold(); + return; + case VAR_RandomFood: + if ( val == 0 ) + val = 1; + v7 = rand() % val + 1; + Party::GiveFood(v7); + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[502], v7);// You find %lu food + ShowStatusBarString(pTmpBuf.data(), 2u); + GameUI_DrawFoodAndGold(); + PlayAwardSound(); + return; + case VAR_Sex: + this->uSex = (PLAYER_SEX)val; + PlayAwardSound_Anim97(); + return; + case VAR_Class: + this->classType = (PLAYER_CLASS_TYPE)val; + PlayAwardSound_Anim97(); + return; + case VAR_CurrentHP: + this->sHealth = min(this->sHealth + val, this->GetMaxHealth() ); + PlayAwardSound_Anim97(); + return; + case VAR_MaxHP: + this->_health_related = 0; + this->uFullHealthBonus = 0; + this->sHealth = this->GetMaxHealth(); + return; + case VAR_CurrentSP: + this->sMana = min(this->sMana + val, this->GetMaxMana() ); + PlayAwardSound_Anim97(); + return; + case VAR_MaxSP: + this->_mana_related = 0; + this->uFullManaBonus = 0; + this->sMana = GetMaxMana(); + return; + case VAR_ACModifier: + this->sACModifier = min(this->sACModifier + val, 255); + PlayAwardSound_Anim97(); + return; + case VAR_BaseLevel: + this->uLevel = min(this->uLevel + val, 255); + PlayAwardSound_Anim97(); + return; + case VAR_LevelModifier: + this->sLevelModifier = min(this->sLevelModifier + val, 255); + PlayAwardSound_Anim97(); + return; + case VAR_Age: + this->sAgeModifier += val; + return; + case VAR_Award: + if (_449B57_test_bit(this->_achieved_awards_bits, val) && pAwards[val].pText ) + { + PlayAwardSound_Anim97_Face(SPEECH_96); + } + _449B7E_toggle_bit(this->_achieved_awards_bits, val, 1); + return; + case VAR_Experience: + this->uExperience = min(this->uExperience + val, 4000000000i64); + PlayAwardSound_Anim97(); + return; + case VAR_QBits_QuestsDone: + if ( !_449B57_test_bit(pParty->_quest_bits, val) && pQuestTable[val] ) + { + bFlashQuestBook = 1; + PlayAwardSound_Anim97_Face(SPEECH_93); + } + _449B7E_toggle_bit(pParty->_quest_bits, val, 1); + return; + case VAR_PlayerItemInHands: + item.Reset(); + item.uAttributes = 1; + item.uItemID = val; + if ( val >= ITEM_ARTIFACT_PUCK && val <= ITEM_RELIC_MEKORIGS_HAMMER ) + pParty->pIsArtifactFound[val-500] = 1; + else if ( val >= ITEM_WAND_FIRE && val <= ITEM_WAND_INCENERATION ) + { + item.uNumCharges = rand() % 6 + item.GetDamageMod() + 1; + item.uMaxCharges = LOBYTE(item.uNumCharges); + } + pParty->SetHoldingItem(&item); + return; + case VAR_FixedGold: + pParty->PartyFindsGold(val, 1); + return; + case VAR_BaseMight: + this->uMight = min(this->uMight + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BaseIntellect: + this->uIntelligence = min(this->uIntelligence + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BasePersonality: + this->uWillpower = min(this->uWillpower + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BaseEndurance: + this->uEndurance = min(this->uEndurance + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BaseSpeed: + this->uSpeed = min(this->uSpeed + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BaseAccuracy: + this->uAccuracy = min(this->uAccuracy + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BaseLuck: + this->uLuck = min(this->uLuck + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_FixedFood: + Party::GiveFood(val); + sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[502], val); + ShowStatusBarString(pTmpBuf.data(), 2u); + if ( pParty->uNumFoodRations > 0xFFFF ) + Party::SetFood(0xFFFFu); + PlayAwardSound(); + return; + case VAR_MightBonus: + case VAR_ActualMight: + this->uMightBonus = min(this->uMightBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_IntellectBonus: + case VAR_ActualIntellect: + this->uIntelligenceBonus = min(this->uIntelligenceBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_PersonalityBonus: + case VAR_ActualPersonality: + this->uWillpowerBonus = min(this->uWillpowerBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_EnduranceBonus: + case VAR_ActualEndurance: + this->uEnduranceBonus = min(this->uEnduranceBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_SpeedBonus: + case VAR_ActualSpeed: + this->uSpeedBonus = min(this->uSpeedBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_AccuracyBonus: + case VAR_ActualAccuracy: + this->uAccuracyBonus = min(this->uAccuracyBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_LuckBonus: + case VAR_ActualLuck: + this->uLuckBonus = min(this->uLuckBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_FireResistance: + this->sResFireBase = min(this->sResFireBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_AirResistance: + this->sResAirBase = min(this->sResAirBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_WaterResistance: + this->sResWaterBase = min(this->sResWaterBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_EarthResistance: + this->sResEarthBase = min(this->sResEarthBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_SpiritResistance: + this->sResSpiritBase = min(this->sResSpiritBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_MindResistance: + this->sResMindBase = min(this->sResMindBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_BodyResistance: + this->sResBodyBase = min(this->sResBodyBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_LightResistance: + this->sResLightBase = min(this->sResLightBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_DarkResistance: + this->sResDarkBase = min(this->sResDarkBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_MagicResistance: + this->sResMagicBase = min(this->sResMagicBase + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_92); + return; + case VAR_FireResistanceBonus: + this->sResFireBonus = min(this->sResFireBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_AirResistanceBonus: + this->sResAirBonus = min(this->sResAirBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_WaterResistanceBonus: + this->sResWaterBonus = min(this->sResWaterBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_EarthResistanceBonus: + this->sResEarthBonus = min(this->sResEarthBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_SpiritResistanceBonus: + this->sResSpiritBonus = min(this->sResSpiritBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_MindResistanceBonus: + this->sResMindBonus = min(this->sResMindBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_BodyResistanceBonus: + this->sResBodyBonus = min(this->sResBodyBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_LightResistanceBonus: + this->sResLightBonus = min(this->sResLightBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_DarkResistanceBonus: + this->sResDarkBonus = min(this->sResDarkBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_MagicResistanceBonus: + this->sResMagicBonus = min(this->sResMagicBonus + val, 255); + PlayAwardSound_Anim97_Face(SPEECH_91); + return; + case VAR_Cursed: + this->SetCondition(Condition_Cursed, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Weak: + this->SetCondition(Condition_Weak, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Asleep: + this->SetCondition(Condition_Sleep, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Afraid: + this->SetCondition(Condition_Fear, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Drunk: + this->SetCondition(Condition_Drunk, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Insane: + this->SetCondition(Condition_Insane, 1); + PlayAwardSound_Anim97(); + return; + case VAR_PoisonedGreen: + this->SetCondition(Condition_Poison_Weak, 1); + PlayAwardSound_Anim97(); + return; + case VAR_DiseasedGreen: + this->SetCondition(Condition_Disease_Weak, 1); + PlayAwardSound_Anim97(); + return; + case VAR_PoisonedYellow: + this->SetCondition(Condition_Poison_Medium, 1); + PlayAwardSound_Anim97(); + return; + case VAR_DiseasedYellow: + this->SetCondition(Condition_Disease_Medium, 1); + PlayAwardSound_Anim97(); + return; + case VAR_PoisonedRed: + this->SetCondition(Condition_Poison_Severe, 1); + PlayAwardSound_Anim97(); + return; + case VAR_DiseasedRed: + this->SetCondition(Condition_Disease_Severe, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Paralyzed: + this->SetCondition(Condition_Paralyzed, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Unconsious: + this->SetCondition(Condition_Unconcious, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Dead: + this->SetCondition(Condition_Dead, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Stoned: + this->SetCondition(Condition_Pertified, 1); + PlayAwardSound_Anim97(); + return; + case VAR_Eradicated: + this->SetCondition(Condition_Eradicated, 1); + PlayAwardSound_Anim97(); + return; + case VAR_MajorCondition : + pConditions.fill(0); + PlayAwardSound_Anim97(); + return; + case VAR_AutoNotes: + if ( !_449B57_test_bit(pParty->_autonote_bits, val) && pAutonoteTxt[val].pText ) + { + this->PlaySound(SPEECH_96, 0); + bFlashAutonotesBook = 1; + _506568_autonote_type = pAutonoteTxt[val].eType; + pGame->pStru6Instance->SetPlayerBuffAnim(0x97u, GetPlayerIndex()); + } + _449B7E_toggle_bit(pParty->_autonote_bits, val, 1); + PlayAwardSound(); + return; + case VAR_PlayerBits: + _449B7E_toggle_bit((unsigned char *)this->playerEventBits, val, 1u); + return; + case VAR_NPCs2: + pParty->hirelingScrollPosition = 0; + LOBYTE(pNPCStats->pNewNPCData[val].uFlags) |= 0x80u; + pParty->CountHirelings(); + viewparams->bRedrawGameUI = true; + return; + case VAR_NumSkillPoints: + this->uSkillPoints += val; + return; + case VAR_ReputationInCurrentLocation: + v27 = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) + v27 = &pIndoor->dlv; + v27->uReputation += val; + if ( v27->uReputation > 10000 ) + v27->uReputation = 10000; + return; + case VAR_GoldInBank: + pParty->uNumGoldInBank += val; + return; + case VAR_NumDeaths: + pParty->uNumDeaths += val; + return; + case VAR_NumBounties: + pParty->uNumBountiesCollected += val; + return; + case VAR_PrisonTerms: + pParty->uNumPrisonTerms += val; + return; + case VAR_ArenaWinsPage: + pParty->uNumArenaPageWins += val; + return; + case VAR_ArenaWinsSquire: + pParty->uNumArenaSquireWins += val; + return; + case VAR_ArenaWinsKnight: + pParty->uNumArenaKnightWins += val; + return; + case VAR_ArenaWinsLord: + pParty->uNumArenaLordWins += val; + return; + case VAR_StaffSkill: + AddSkillByEvent(&Player::skillStaff, val); + return; + case VAR_SwordSkill: + AddSkillByEvent(&Player::skillSword, val); + return; + case VAR_DaggerSkill: + AddSkillByEvent(&Player::skillDagger, val); + return; + case VAR_AxeSkill: + AddSkillByEvent(&Player::skillAxe, val); + return; + case VAR_SpearSkill: + AddSkillByEvent(&Player::skillSpear, val); + return; + case VAR_BowSkill: + AddSkillByEvent(&Player::skillBow, val); + return; + case VAR_MaceSkill: + AddSkillByEvent(&Player::skillMace, val); + return; + case VAR_BlasterSkill: + AddSkillByEvent(&Player::skillBlaster, val); + return; + case VAR_ShieldSkill: + AddSkillByEvent(&Player::skillShield, val); + return; + case VAR_LeatherSkill: + AddSkillByEvent(&Player::skillLeather, val); + return; + case VAR_SkillChain: + AddSkillByEvent(&Player::skillChain, val); + return; + case VAR_PlateSkill: + AddSkillByEvent(&Player::skillPlate, val); + return; + case VAR_FireSkill: + AddSkillByEvent(&Player::skillFire, val); + return; + case VAR_AirSkill: + AddSkillByEvent(&Player::skillAir, val); + return; + case VAR_WaterSkill: + AddSkillByEvent(&Player::skillWater, val); + return; + case VAR_EarthSkill: + AddSkillByEvent(&Player::skillEarth, val); + return; + case VAR_SpiritSkill: + AddSkillByEvent(&Player::skillSpirit, val); + return; + case VAR_MindSkill: + AddSkillByEvent(&Player::skillMind, val); + return; + case VAR_BodySkill: + AddSkillByEvent(&Player::skillBody, val); + return; + case VAR_LightSkill: + AddSkillByEvent(&Player::skillLight, val); + return; + case VAR_DarkSkill: + AddSkillByEvent(&Player::skillDark, val); + return; + case VAR_IdentifyItemSkill: + AddSkillByEvent(&Player::skillItemId, val); + return; + case VAR_MerchantSkill: + AddSkillByEvent(&Player::skillMerchant, val); + return; + case VAR_RepairSkill: + AddSkillByEvent(&Player::skillRepair, val); + return; + case VAR_BodybuildingSkill: + AddSkillByEvent(&Player::skillBodybuilding, val); + return; + case VAR_MeditationSkill: + AddSkillByEvent(&Player::skillMeditation, val); + return; + case VAR_PerceptionSkill: + AddSkillByEvent(&Player::skillPerception, val); + return; + case VAR_DiplomacySkill: + AddSkillByEvent(&Player::skillDiplomacy, val); + return; + case VAR_ThieverySkill: + Error ("Thieving unsupported"); + return; + case VAR_DisarmTrapSkill: + AddSkillByEvent(&Player::skillDisarmTrap, val); + return; + case VAR_DodgeSkill: + AddSkillByEvent(&Player::skillDodge, val); + return; + case VAR_UnarmedSkill: + AddSkillByEvent(&Player::skillUnarmed, val); + return; + case VAR_IdentifyMonsterSkill: + AddSkillByEvent(&Player::skillMonsterId, val); + return; + case VAR_ArmsmasterSkill: + AddSkillByEvent(&Player::skillArmsmaster, val); + return; + case VAR_StealingSkill: + AddSkillByEvent(&Player::skillStealing, val); + return; + case VAR_AlchemySkill: + AddSkillByEvent(&Player::skillAlchemy, val); + return; + case VAR_LearningSkill: + AddSkillByEvent(&Player::skillLearning, val); + return; + default: + return; + } +} + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim97() +{ + int playerIndex = GetPlayerIndex(); + pGame->pStru6Instance->SetPlayerBuffAnim(0x97u, playerIndex); + PlayAwardSound(); +} + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim97_Face( PlayerSpeech speech ) +{ + this->PlaySound(speech, 0); + PlayAwardSound_Anim97(); +} + +//----- (new function) -------------------------------------------------------- +void Player::AddSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 addSkillValue ) +{ + if ( addSkillValue > 63 ) + { + this->*skillToSet = (unsigned __int8)addSkillValue | this->*skillToSet & 63; + } + else + { + this->*skillToSet = min(this->*skillToSet + addSkillValue, 60) | this->*skillToSet & 0xC0; + } + PlayAwardSound_Anim97(); + return; +} + +//----- (0044B9C4) -------------------------------------------------------- +void Player::SubtractVariable( enum VariableType VarNum, signed int pValue ) +{ + DDM_DLV_Header *locationHeader; // eax@90 + int randGold; + int randFood; + int npcIndex; + + if ( VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_99 ) + { + if ( VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_74 ) + { + stru_5E4C90_MapPersistVars.field_0[VarNum - VAR_MapPersistentVariable_0] -= pValue; + } + if ( (signed int)VarNum >= VAR_MapPersistentVariable_75 && VarNum <= VAR_MapPersistentVariable_99 ) + { + stru_5E4C90_MapPersistVars._decor_events[VarNum - VAR_MapPersistentVariable_75] -= pValue; + } + return; + } + + switch (VarNum) + { + case VAR_CurrentHP: + ReceiveDamage((signed int)pValue, DMGT_PHISYCAL); + PlayAwardSound_Anim98(); + return; + case VAR_CurrentSP: + this->sMana = max(this->sMana - pValue, 0); + PlayAwardSound_Anim98(); + return; + case VAR_ACModifier: + this->sACModifier -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_BaseLevel: + this->uLevel -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_LevelModifier: + this->sLevelModifier -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_Age: + this->sAgeModifier -= (signed __int16)pValue; + return; + case VAR_Award: + _449B7E_toggle_bit(this->_achieved_awards_bits, (signed __int16)pValue, 0); + return; + case VAR_Experience: + this->uExperience -= pValue; + PlayAwardSound_Anim98(); + return; + case VAR_QBits_QuestsDone: + _449B7E_toggle_bit(pParty->_quest_bits, (__int16)pValue, 0); + this->PlaySound(SPEECH_96, 0); + return; + case VAR_PlayerItemInHands: + for ( uint i = 0; i < 16; ++i ) + { + int id_ = this->pEquipment.pIndices[i]; + if ( id_ > 0 ) + { + if ( this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uItemID == pValue ) + { + this->pEquipment.pIndices[i] = 0; + } + } + } + for (int i = 0; i < 126; i++) + { + int id_ = this->pInventoryMatrix[i]; + if ( id_ > 0 ) + { + if ( this->pInventoryItemList[id_ - 1].uItemID == pValue ) + { + RemoveItemAtInventoryIndex(i); + return; + } + } + } + if ( pParty->pPickedItem.uItemID == pValue ) + { + pMouse->RemoveHoldingItem(); + return; + } + return; + case VAR_FixedGold: + if ( (unsigned int)pValue > pParty->uNumGold ) + { + dword_5B65C4_cancelEventProcessing = 1; + return; + } + Party::TakeGold((unsigned int)pValue); + return; + case VAR_RandomGold: + randGold = rand() % (signed int)pValue + 1; + if ( (unsigned int)randGold > pParty->uNumGold ) + randGold = pParty->uNumGold; + Party::TakeGold(randGold); + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[503], randGold); + ShowStatusBarString(pTmpBuf.data(), 2); + GameUI_DrawFoodAndGold(); + return; + case VAR_FixedFood: + Party::TakeFood((unsigned int)pValue); + PlayAwardSound_Anim98(); + return; + case VAR_RandomFood: + randFood = rand() % (signed int)pValue + 1; + if ( (unsigned int)randFood > pParty->uNumFoodRations ) + randFood = pParty->uNumFoodRations; + Party::TakeFood(randFood); + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[504], randFood); + ShowStatusBarString(pTmpBuf.data(), 2u); + GameUI_DrawFoodAndGold(); + PlayAwardSound_Anim98(); + return; + case VAR_MightBonus: + case VAR_ActualMight: + this->uMightBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_IntellectBonus: + case VAR_ActualIntellect: + this->uIntelligenceBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_PersonalityBonus: + case VAR_ActualPersonality: + this->uWillpowerBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_EnduranceBonus: + case VAR_ActualEndurance: + this->uEnduranceBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_SpeedBonus: + case VAR_ActualSpeed: + this->uSpeedBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_AccuracyBonus: + case VAR_ActualAccuracy: + this->uAccuracyBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_LuckBonus: + case VAR_ActualLuck: + this->uLuckBonus -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_BaseMight: + this->uMight -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BaseIntellect: + this->uIntelligence -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BasePersonality: + this->uWillpower -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BaseEndurance: + this->uEndurance -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BaseSpeed: + this->uSpeed -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BaseAccuracy: + this->uAccuracy -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BaseLuck: + this->uLuck -= (unsigned __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_FireResistance: + this->sResFireBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_AirResistance: + this->sResAirBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_WaterResistance: + this->sResWaterBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_EarthResistance: + this->sResEarthBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_SpiritResistance: + this->sResSpiritBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_MindResistance: + this->sResMindBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_BodyResistance: + this->sResBodyBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_LightResistance: + this->sResLightBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_DarkResistance: + this->sResDarkBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_MagicResistance: + this->sResMagicBase -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_FireResistanceBonus: + this->sResFireBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_AirResistanceBonus: + this->sResAirBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_92); + return; + case VAR_WaterResistanceBonus: + this->sResWaterBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_EarthResistanceBonus: + this->sResEarthBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_SpiritResistanceBonus: + this->sResSpiritBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_MindResistanceBonus: + this->sResMindBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_BodyResistanceBonus: + this->sResBodyBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_LightResistanceBonus: + this->sResLightBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_DarkResistanceBonus: + this->sResDarkBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_MagicResistanceBonus: + this->sResMagicBonus -= (signed __int16)pValue; + this->PlayAwardSound_Anim98_Face(SPEECH_91); + return; + case VAR_StaffSkill: + this->skillStaff -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_SwordSkill: + this->skillSword -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_DaggerSkill: + this->skillDagger -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_AxeSkill: + this->skillAxe -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_SpearSkill: + this->skillSpear -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_BowSkill: + this->skillBow -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_MaceSkill: + this->skillMace -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_BlasterSkill: + this->skillBlaster -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_ShieldSkill: + this->skillShield -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_LeatherSkill: + this->skillLearning -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_SkillChain: + this->skillChain -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_PlateSkill: + this->skillPlate -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_FireSkill: + this->skillFire -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_AirSkill: + this->skillAir -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_WaterSkill: + this->skillWater -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_EarthSkill: + this->skillEarth -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_SpiritSkill: + this->skillSpirit -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_MindSkill: + this->skillMind -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_BodySkill: + this->skillBody -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_LightSkill: + this->skillLight -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_DarkSkill: + this->skillDark -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_IdentifyItemSkill: + this->skillItemId -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_MerchantSkill: + this->skillMerchant -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_RepairSkill: + this->skillRepair -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_BodybuildingSkill: + this->skillBodybuilding -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_MeditationSkill: + this->skillMeditation -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_PerceptionSkill: + this->skillPerception -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_DiplomacySkill: + this->skillDiplomacy -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_ThieverySkill: + Error ("Thieving unsupported"); + return; + case VAR_DisarmTrapSkill: + this->skillDisarmTrap -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_DodgeSkill: + this->skillDodge -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_UnarmedSkill: + this->skillUnarmed -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_IdentifyMonsterSkill: + this->skillMonsterId -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_ArmsmasterSkill: + this->skillArmsmaster -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_StealingSkill: + this->skillStealing -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_AlchemySkill: + this->skillAlchemy -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_LearningSkill: + this->skillLearning -= (unsigned __int8)pValue; + PlayAwardSound_Anim98(); + return; + case VAR_Cursed: + this->pConditions[Condition_Cursed] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Weak: + this->pConditions[Condition_Weak] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Asleep: + this->pConditions[Condition_Sleep] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Afraid: + this->pConditions[Condition_Fear] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Drunk: + this->pConditions[Condition_Drunk] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Insane: + this->pConditions[Condition_Insane] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_PoisonedGreen: + this->pConditions[Condition_Poison_Weak] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_DiseasedGreen: + this->pConditions[Condition_Disease_Weak] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_PoisonedYellow: + this->pConditions[Condition_Poison_Medium] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_DiseasedYellow: + this->pConditions[Condition_Disease_Medium] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_PoisonedRed: + this->pConditions[Condition_Poison_Severe] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_DiseasedRed: + this->pConditions[Condition_Disease_Severe] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Paralyzed: + this->pConditions[Condition_Paralyzed] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Unconsious: + this->pConditions[Condition_Unconcious] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Dead: + this->pConditions[Condition_Dead] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Stoned: + this->pConditions[Condition_Pertified] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_Eradicated: + this->pConditions[Condition_Eradicated] = 0; + PlayAwardSound_Anim98(); + return; + case VAR_AutoNotes: + _449B7E_toggle_bit(pParty->_autonote_bits, pValue - 1, 0); + return; + case VAR_NPCs2: + npcIndex = 0; + GetNewNPCData(sDialogue_SpeakingActorNPC_ID, &npcIndex); + if ( npcIndex == pValue ) + { + npcIdToDismissAfterDialogue = pValue; + } + else + { + npcIdToDismissAfterDialogue = 0; + pParty->hirelingScrollPosition = 0; + LOBYTE(pNPCStats->pNewNPCData[(int)pValue].uFlags) &= 0x7Fu; + pParty->CountHirelings(); + viewparams->bRedrawGameUI = true; + } + return; + case VAR_HiredNPCHasSpeciality: + for (unsigned int i = 0; i < pNPCStats->uNumNewNPCs; i++) + { + if (pNPCStats->pNewNPCData[i].uProfession == pValue) + { + LOBYTE(pNPCStats->pNewNPCData[(int)pValue].uFlags) &= 0x7Fu; + } + } + if ( pParty->pHirelings[0].uProfession == pValue ) + memset(&pParty->pHirelings[0], 0, sizeof(NPCData)); + if ( pParty->pHirelings[1].uProfession == pValue ) + memset(&pParty->pHirelings[1], 0, sizeof(NPCData)); + pParty->hirelingScrollPosition = 0; + pParty->CountHirelings(); + return; + case VAR_NumSkillPoints: + if ((unsigned int)pValue <= this->uSkillPoints) + { + this->uSkillPoints -= pValue; + } + else + { + this->uSkillPoints = 0; + } + return; + case VAR_ReputationInCurrentLocation: + locationHeader = &pOutdoor->ddm; + if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) + locationHeader = &pIndoor->dlv; + locationHeader->uReputation -= pValue; + if (locationHeader->uReputation < -10000) + locationHeader->uReputation = -10000; + return; + case VAR_GoldInBank: + if ( (unsigned int)pValue <= pParty->uNumGoldInBank ) + { + pParty->uNumGoldInBank -= (unsigned int)pValue; + } + else + { + dword_5B65C4_cancelEventProcessing = 1; + } + return; + case VAR_NumDeaths: + pParty->uNumDeaths -= (unsigned int)pValue; + return; + case VAR_NumBounties: + pParty->uNumBountiesCollected -= (unsigned int)pValue; + return; + case VAR_PrisonTerms: + pParty->uNumPrisonTerms -= (int)pValue; + return; + case VAR_ArenaWinsPage: + pParty->uNumArenaPageWins -= (char)pValue; + return; + case VAR_ArenaWinsSquire: + pParty->uNumArenaSquireWins -= (char)pValue; + return; + case VAR_ArenaWinsKnight: + pParty->uNumArenaKnightWins -= (char)pValue; + return; + case VAR_ArenaWinsLord: + pParty->uNumArenaLordWins -= (char)pValue; + return; + } +} +// 5B65C4: using guessed type int dword_5B65C4; +// 5B65CC: using guessed type int dword_5B65CC; + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim98() +{ + int playerIndex = GetPlayerIndex(); + pGame->pStru6Instance->SetPlayerBuffAnim(0x98u, playerIndex); + PlayAwardSound(); +} + +//----- (new function) -------------------------------------------------------- +void Player::PlayAwardSound_Anim98_Face( PlayerSpeech speech ) +{ + this->PlaySound(speech, 0); + PlayAwardSound_Anim98(); +} + +//----- (00467E7F) -------------------------------------------------------- +void Player::EquipBody(ITEM_EQUIP_TYPE uEquipType) +{ + int itemAnchor; // ebx@1 + int itemInvLocation; // edx@1 + int freeSlot; // eax@3 + ItemGen tempPickedItem; // [sp+Ch] [bp-30h]@1 + + tempPickedItem.Reset(); + itemAnchor = pEquipTypeToBodyAnchor[uEquipType]; + itemInvLocation = pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor]; + if ( itemInvLocation )//ïåðåîäåòüñÿ â äðóãóþ âåùü + { + memcpy(&tempPickedItem, &pParty->pPickedItem, sizeof(tempPickedItem)); + pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1].uBodyAnchor = 0; + pParty->pPickedItem.Reset(); + pParty->SetHoldingItem(&pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1]); + tempPickedItem.uBodyAnchor = itemAnchor + 1; + memcpy(&pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1], &tempPickedItem, sizeof(ItemGen)); + pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor] = itemInvLocation; + } + else//îäåòü âåùü + { + freeSlot = pPlayers[uActiveCharacter]->FindFreeInventoryListSlot(); + if (freeSlot >= 0) + { + pParty->pPickedItem.uBodyAnchor = itemAnchor + 1; + memcpy(&pPlayers[uActiveCharacter]->pInventoryItemList[freeSlot], &pParty->pPickedItem, sizeof(ItemGen)); + pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor] = freeSlot + 1; + pMouse->RemoveHoldingItem(); + } + } +} + +//----- (0049387A) -------------------------------------------------------- +int CycleCharacter(bool backwards) +{ + const int PARTYSIZE = 4; + int valToAdd = backwards ? (PARTYSIZE - 2) : 0; + int mult = backwards ? -1 : 1; + + for (int i = 0; i < (PARTYSIZE - 1); i++) + { + int currCharId = ((uActiveCharacter + mult * i + valToAdd) % PARTYSIZE) + 1; + if ( pPlayers[currCharId]->uTimeToRecovery == 0 ) + { + return currCharId; + } + } + return uActiveCharacter; +} + +//----- (0043EE77) -------------------------------------------------------- +bool Player::HasUnderwaterSuitEquipped() //the original function took the player number as a parameter. if it was 0, the whole party was checked. calls with the parameter 0 have been changed to calls to this for every player +{ + if (GetArmorItem() == nullptr || GetArmorItem()->uItemID != 604) + { + return false; + } + return true; +} + +//----- (0043EE15) -------------------------------------------------------- +bool Player::HasItem( unsigned int uItemID, bool checkHeldItem ) +{ + if ( !checkHeldItem || pParty->pPickedItem.uItemID != uItemID ) + { + for ( uint i = 0; i < 126; ++i ) + { + if ( this->pInventoryMatrix[i] > 0 ) + { + if ( (unsigned int)this->pInventoryItemList[this->pInventoryMatrix[i] - 1].uItemID == uItemID ) + return true; + } + } + for ( uint i = 0; i < 16; ++i ) + { + if ( this->pEquipment.pIndices[i] ) + { + if ( (unsigned int)this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uItemID == uItemID ) + return true; + } + } + return false; + } + else + { + return true; + } +} +//----- (0043EDB9) -------------------------------------------------------- +bool ShouldLoadTexturesForRaceAndGender(unsigned int _this) +{ + CHARACTER_RACE race; // edi@2 + PLAYER_SEX sex; // eax@2 + + for (int i = 1; i <= 4; i++) + { + race = pPlayers[i]->GetRace(); + sex = pPlayers[i]->GetSexByVoice(); + switch(_this) + { + case 0: + if (( race == CHARACTER_RACE_HUMAN || race == CHARACTER_RACE_ELF || race == CHARACTER_RACE_GOBLIN ) && sex == SEX_MALE ) + return true; + break; + case 1: + if (( race == CHARACTER_RACE_HUMAN || race == CHARACTER_RACE_ELF || race == CHARACTER_RACE_GOBLIN ) && sex == SEX_FEMALE ) + return true; + break; + case 2: + if ( race == CHARACTER_RACE_DWARF && sex == SEX_MALE ) + return true; + break; + case 3: + if ( race == CHARACTER_RACE_DWARF && sex == SEX_FEMALE ) + return true; + break; + } + } + return false; +} + +//----- (0043ED6F) -------------------------------------------------------- +bool IsDwarfPresentInParty(bool a1) +{ + for (uint i = 0; i < 4; ++i) + { + CHARACTER_RACE race = pParty->pPlayers[i].GetRace(); + + if (race == CHARACTER_RACE_DWARF && a1) + return true; + else if (race != CHARACTER_RACE_DWARF && !a1) + return true; + } + return false; +} + +//----- (00439FCB) -------------------------------------------------------- +void __fastcall DamagePlayerFromMonster(unsigned int uObjID, int dmgSource, Vec3_int_ *pPos, signed int a4) +{ + Player *playerPtr; // ebx@3 + Actor *actorPtr; // esi@3 + int spellId; // eax@38 + signed int recvdMagicDmg; // eax@139 + int v72[4]; // [sp+30h] [bp-24h]@164 + int healthBeforeRecvdDamage; // [sp+48h] [bp-Ch]@3 + unsigned int uActorID; // [sp+4Ch] [bp-8h]@1 + + uActorID = PID_ID(uObjID); + if ( PID_TYPE(uObjID) != 2) + { + playerPtr = &pParty->pPlayers[a4]; + actorPtr = &pActors[uActorID]; + healthBeforeRecvdDamage = playerPtr->sHealth; + if ( PID_TYPE(uObjID) != 3 || !actorPtr->ActorHitOrMiss(playerPtr) ) + return; + ItemGen* equippedArmor = playerPtr->GetArmorItem(); + SoundID soundToPlay; + if ( !equippedArmor + || equippedArmor->IsBroken() + || + (equippedArmor->GetPlayerSkillType() != PLAYER_SKILL_CHAIN + && equippedArmor->GetPlayerSkillType() != PLAYER_SKILL_PLATE + ) + ) + { + int randVal = rand() % 4; + switch (randVal) + { + case 0 : soundToPlay = (SoundID)108; break; + case 1 : soundToPlay = (SoundID)109; break; + case 2 : soundToPlay = (SoundID)110; break; + case 3 : soundToPlay = (SoundID)44; break; + default: Error("Unexpected sound value"); + } + } + else + { + int randVal = rand() % 4; + switch (randVal) + { + case 0 : soundToPlay = (SoundID)105; break; + case 1 : soundToPlay = (SoundID)106; break; + case 2 : soundToPlay = (SoundID)107; break; + case 3 : soundToPlay = (SoundID)45; break; + default: Error("Unexpected sound value"); + } + } + pAudioPlayer->PlaySound(soundToPlay, PID(OBJECT_Player,a4 + 80), 0, -1, 0, 0, 0, 0); + int dmgToReceive = actorPtr->_43B3E0_CalcDamage(dmgSource); + if ( actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime > 0 ) + { + __int16 spellPower = actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uPower; + if ( spellPower ) + dmgToReceive /= (signed int)spellPower; + } + int damageType; + switch (dmgSource) + { + case 0: damageType = actorPtr->pMonsterInfo.uAttack1Type; + break; + case 1: damageType = actorPtr->pMonsterInfo.uAttack2Type; + break; + case 2: spellId = actorPtr->pMonsterInfo.uSpell1ID; + damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); + break; + case 3: spellId = actorPtr->pMonsterInfo.uSpell2ID; + damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); + break; + case 4: damageType = actorPtr->pMonsterInfo.field_3C_some_special_attack; + break; + default: + case 5: damageType = 4; //yes, the original just assigned the value 4 + break; + } + if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) ) + { + dmgToReceive = playerPtr->ReceiveDamage(dmgToReceive, (DAMAGE_TYPE)damageType); + if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_PAIN_REFLECTION].uExpireTime > 0 ) + { + int actorState = actorPtr->uAIState; + if ( actorState != Dying && actorState != Dead) + { + int reflectedDamage = actorPtr->CalcMagicalDamageToActor((DAMAGE_TYPE)damageType, dmgToReceive); + actorPtr->sCurrentHP -= reflectedDamage; + if ( reflectedDamage >= 0 ) + { + if ( actorPtr->sCurrentHP >= 1 ) + { + Actor::AI_Stun(uActorID, PID(OBJECT_Player,a4), 0); //todo extract this branch to a function once Actor::functions are changed to nonstatic actor functions + Actor::AggroSurroundingPeasants(uActorID, 1); + } + else + { + if ( pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].bQuestMonster & 1 && pGame->uFlags2 & GAME_FLAGS_2_DRAW_BLOODSPLATS) + { + int splatRadius = byte_4D864C && BYTE2(pGame->uFlags) & 8 ? 10 * actorPtr->uActorRadius : actorPtr->uActorRadius; + pDecalBuilder->AddBloodsplat(actorPtr->vPosition.x, actorPtr->vPosition.y, actorPtr->vPosition.z, 1.0, 0.0, 0.0, (float)splatRadius, 0, 0); + } + Actor::Die(uActorID); + Actor::ApplyFineForKillingPeasant(uActorID); + Actor::AggroSurroundingPeasants(uActorID, 1); + if ( actorPtr->pMonsterInfo.uExp ) + pParty->GivePartyExp(pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].uExp); + int speechToPlay = SPEECH_51; + if ( rand() % 100 < 20 ) + speechToPlay = actorPtr->pMonsterInfo.uHP >= 100 ? 2 : 1; + playerPtr->PlaySound((PlayerSpeech)speechToPlay, 0); + } + } + } + } + if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) + && actorPtr->pMonsterInfo.uSpecialAttackType + && rand() % 100 < actorPtr->pMonsterInfo.uLevel * actorPtr->pMonsterInfo.uSpecialAttackLevel ) + { + playerPtr->ReceiveSpecialAttackEffect(actorPtr->pMonsterInfo.uSpecialAttackType, actorPtr); + } + } + if ( !pParty->bTurnBasedModeOn ) + { + int actEndurance = playerPtr->GetActualEndurance(); + int recoveryTime = (int)((20 - playerPtr->GetParameterBonus(actEndurance)) * flt_6BE3A4_debug_recmod1 * 2.133333333333333); + playerPtr->SetRecoveryTime(recoveryTime); + } + int yellThreshold = playerPtr->GetMaxHealth() / 4; + if ( yellThreshold < playerPtr->sHealth && yellThreshold >= healthBeforeRecvdDamage && playerPtr->sHealth > 0 ) + { + playerPtr->PlaySound(SPEECH_48, 0); + } + viewparams->bRedrawGameUI = 1; + return; + } + else + { + SpriteObject* v37 = &pSpriteObjects[uActorID]; + int uActorType = PID_TYPE(v37->spell_caster_pid); + int uActorID = PID_ID(v37->spell_caster_pid); + if ( uActorType == 2 ) + { + Player *playerPtr; // eax@81 + if ( a4 != -1 ) + { + playerPtr = &pParty->pPlayers[a4]; + } + else + { + int activePlayerCounter = 0; + for (int i = 1; i <= 4; i++) + { + if (pPlayers[i]->CanAct()) + { + v72[activePlayerCounter] = i; + activePlayerCounter++; + } + } + if ( activePlayerCounter ) + { + playerPtr = &pParty->pPlayers[v72[rand() % activePlayerCounter] - 1];//&stru_AA1058[3].pSounds[6972 * *(&v72 + rand() % v74) + 40552]; + } + } + int v68; + int v69; + if ( uActorType != OBJECT_Player || v37->spell_id != SPELL_BOW_ARROW) + { + int playerMaxHp = playerPtr->GetMaxHealth(); + v68 = _43AFE3_calc_spell_damage(v37->spell_id, v37->spell_level, v37->spell_skill, playerMaxHp); + v69 = LOBYTE(pSpellStats->pInfos[v37->spell_id].uSchool); + } + else + { + v68 = pParty->pPlayers[uActorID].CalculateRangedDamageTo(0); + v69 = 0; + } + playerPtr->ReceiveDamage(v68, (DAMAGE_TYPE)v69); + if ( uActorType == OBJECT_Player && !_A750D8_player_speech_timer ) + { + _A750D8_player_speech_timer = 256i64; + PlayerSpeechID = SPEECH_44; + uSpeakingCharacter = uActorID + 1; + } + return; + } + else if ( uActorType == 3 ) + { + Actor *actorPtr = &pActors[uActorID]; + if ( a4 == -1 ) + a4 = stru_50C198.which_player_to_attack(actorPtr); + Player *playerPtr = &pParty->pPlayers[a4]; + int dmgToReceive = actorPtr->_43B3E0_CalcDamage(dmgSource); + unsigned __int16 spriteType = v37->uType; + if ( v37->uType == 545 ) + { + __int16 skillLevel = playerPtr->GetActualSkillLevel(PLAYER_SKILL_UNARMED); + if ( SkillToMastery(skillLevel) >= 4 && rand() % 100 < (skillLevel & 0x3F) ) + { + sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[637], playerPtr->pName); + ShowStatusBarString(pTmpBuf.data(), 2u); + playerPtr->PlaySound(SPEECH_6, 0); + return; + } + } + else if ( spriteType == 555 + || spriteType == 510 + || spriteType == 500 + || spriteType == 515 + || spriteType == 505 + || spriteType == 530 + || spriteType == 525 + || spriteType == 520 + || spriteType == 535 + || spriteType == 540 ) + { + if ( !actorPtr->ActorHitOrMiss(playerPtr) ) + return; + if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_SHIELD].uExpireTime > 0 ) + dmgToReceive >>= 1; + if ( playerPtr->HasEnchantedItemEquipped(36) ) + dmgToReceive >>= 1; + if ( playerPtr->HasEnchantedItemEquipped(69) ) + dmgToReceive >>= 1; + if ( playerPtr->HasItemEquipped(EQUIP_ARMOUR) + && playerPtr->GetArmorItem()->uItemID == ITEM_ARTIFACT_GOVERNORS_ARMOR ) + dmgToReceive >>= 1; + if ( playerPtr->HasItemEquipped(EQUIP_TWO_HANDED)) + { + ItemGen* mainHandItem = playerPtr->GetMainHandItem(); + if ( mainHandItem->uItemID == ITEM_RELIC_KELEBRIM || mainHandItem->uItemID == ITEM_ARTIFACT_ELFBANE || (mainHandItem->GetItemEquipType() == EQUIP_SHIELD && SkillToMastery(playerPtr->pActiveSkills[PLAYER_SKILL_SHIELD]) == 4)) + dmgToReceive >>= 1; + } + if ( playerPtr->HasItemEquipped(EQUIP_SINGLE_HANDED)) + { + ItemGen* offHandItem = playerPtr->GetOffHandItem(); + if ( offHandItem->uItemID == ITEM_RELIC_KELEBRIM || offHandItem->uItemID == ITEM_ARTIFACT_ELFBANE || (offHandItem->GetItemEquipType() == EQUIP_SHIELD && SkillToMastery(playerPtr->pActiveSkills[PLAYER_SKILL_SHIELD]) == 4)) + dmgToReceive >>= 1; + } + } + if ( actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime > 0 ) + { + int spellPower = actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uPower; + if ( spellPower ) + dmgToReceive /= (signed int)spellPower; + } + int damageType; + switch(dmgSource) + { + case 0: + damageType = actorPtr->pMonsterInfo.uAttack1Type; + break; + case 1: + damageType = actorPtr->pMonsterInfo.uAttack2Type; + break; + case 2: + spellId = actorPtr->pMonsterInfo.uSpell1ID; + damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); + break; + case 3: + spellId = actorPtr->pMonsterInfo.uSpell2ID; + damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); + break; + case 4: + damageType = actorPtr->pMonsterInfo.field_3C_some_special_attack; + break; + case 5: + damageType = 4; + break; + } + if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) ) + { + int reflectedDmg = playerPtr->ReceiveDamage(dmgToReceive, (DAMAGE_TYPE)damageType); + if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_PAIN_REFLECTION].uExpireTime > 0 ) + { + unsigned __int16 actorState = actorPtr->uAIState; + if ( actorState != Dying && actorState != Dead) + { + recvdMagicDmg = actorPtr->CalcMagicalDamageToActor((DAMAGE_TYPE)damageType, reflectedDmg); + actorPtr->sCurrentHP -= recvdMagicDmg; + if ( recvdMagicDmg >= 0 ) + { + if ( actorPtr->sCurrentHP >= 1 ) + { + Actor::AI_Stun(uActorID, PID(OBJECT_Player,a4), 0); + Actor::AggroSurroundingPeasants(uActorID, 1); + } + else + { + if ( pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].bQuestMonster & 1 && pGame->uFlags2 & GAME_FLAGS_2_DRAW_BLOODSPLATS ) + { + int splatRadius = byte_4D864C && BYTE2(pGame->uFlags) & 8 ? 10 * actorPtr->uActorRadius : actorPtr->uActorRadius; + pDecalBuilder->AddBloodsplat(actorPtr->vPosition.x, actorPtr->vPosition.y, actorPtr->vPosition.z, 1.0, 0.0, 0.0, (float)splatRadius, 0, 0); + } + Actor::Die(uActorID); + Actor::ApplyFineForKillingPeasant(uActorID); + Actor::AggroSurroundingPeasants(uActorID, 1); + if ( actorPtr->pMonsterInfo.uExp ) + pParty->GivePartyExp(pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].uExp); + int speechToPlay = SPEECH_51; + if ( rand() % 100 < 20 ) + speechToPlay = actorPtr->pMonsterInfo.uHP >= 100 ? 2 : 1; + playerPtr->PlaySound((PlayerSpeech)speechToPlay, 0); + } + } + } + } + } + if ( !dmgSource + && !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) + && actorPtr->pMonsterInfo.uSpecialAttackType + && rand() % 100 < actorPtr->pMonsterInfo.uLevel * actorPtr->pMonsterInfo.uSpecialAttackLevel ) + { + playerPtr->ReceiveSpecialAttackEffect(actorPtr->pMonsterInfo.uSpecialAttackType, actorPtr); + } + if ( !pParty->bTurnBasedModeOn ) + { + int actEnd = playerPtr->GetActualEndurance(); + int recTime = (int)((20 - playerPtr->GetParameterBonus(actEnd)) + * flt_6BE3A4_debug_recmod1 + * 2.133333333333333); + playerPtr->SetRecoveryTime(recTime); + } + return; + } + else + { + return; + } + } +} +//----- (00421EA6) -------------------------------------------------------- +void Player::OnInventoryLeftClick() +{ + signed int inventoryXCoord; // ecx@2 + int inventoryYCoord; // eax@2 + int invMatrixIndex; // eax@2 + unsigned int enchantedItemPos; // eax@7 + unsigned int pickedItemId; // esi@12 + unsigned int invItemIndex; // eax@12 + unsigned int itemPos; // eax@18 + ItemGen tmpItem; // [sp+Ch] [bp-3Ch]@1 + unsigned int pY; // [sp+3Ch] [bp-Ch]@2 + unsigned int pX; // [sp+40h] [bp-8h]@2 + CastSpellInfo *pSpellInfo; + + if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 103 ) + { + pMouse->GetClickPos(&pX, &pY); + inventoryYCoord = (pY - 17) / 32; + inventoryXCoord = (pX - 14) / 32; + invMatrixIndex = inventoryXCoord + (INVETORYSLOTSWIDTH * inventoryYCoord); + if ( inventoryYCoord >= 0 && inventoryYCoord < INVETORYSLOTSHEIGHT && inventoryXCoord >= 0 && inventoryXCoord < INVETORYSLOTSWIDTH) + { + if ( _50C9A0_IsEnchantingInProgress ) + { + enchantedItemPos = this->GetItemIDAtInventoryIndex(&invMatrixIndex); + if ( enchantedItemPos ) + { + /* *((char *)pGUIWindow_Settings->ptr_1C + 8) &= 0x7Fu; + *((short *)pGUIWindow_Settings->ptr_1C + 2) = uActiveCharacter - 1; + *((int *)pGUIWindow_Settings->ptr_1C + 3) = enchantedItemPos - 1; + *((short *)pGUIWindow_Settings->ptr_1C + 3) = invMatrixIndex;*/ + pSpellInfo = (CastSpellInfo *)pGUIWindow_Settings->ptr_1C; + pSpellInfo->uFlags &= 0x7F; + pSpellInfo->uPlayerID_2 = uActiveCharacter - 1; + pSpellInfo->spell_target_pid = enchantedItemPos - 1; + pSpellInfo->field_6 = invMatrixIndex; + ptr_50C9A4_ItemToEnchant = &this->pInventoryItemList[enchantedItemPos-1]; + _50C9A0_IsEnchantingInProgress = 0; + if ( pMessageQueue_50CBD0->uNumMessages ) + pMessageQueue_50CBD0->uNumMessages = pMessageQueue_50CBD0->pMessages[0].field_8 != 0; + pMouse->SetCursorBitmap("MICON1"); + _50C9D0_AfterEnchClickEventId = 113; + _50C9D4_AfterEnchClickEventSecondParam = 0; + _50C9D8_AfterEnchClickEventTimeout = 256; + } + return; + } + if ( ptr_50C9A4_ItemToEnchant ) + return; + pickedItemId = pParty->pPickedItem.uItemID; + invItemIndex = this->GetItemIDAtInventoryIndex(&invMatrixIndex); + if (!pickedItemId) + { + if ( !invItemIndex ) + return; + else + { + memcpy(&pParty->pPickedItem, &this->pInventoryItemList[invItemIndex-1], sizeof(pParty->pPickedItem)); + this->RemoveItemAtInventoryIndex(invMatrixIndex); + pickedItemId = pParty->pPickedItem.uItemID; + pMouse->SetCursorBitmap(pItemsTable->pItems[pickedItemId].pIconName); + return; + } + } + else + { + if ( invItemIndex ) + { + ItemGen* invItemPtr = &this->pInventoryItemList[invItemIndex-1]; + memcpy(&tmpItem, invItemPtr, sizeof(tmpItem)); + this->RemoveItemAtInventoryIndex(invMatrixIndex); + int emptyIndex = this->AddItem2(invMatrixIndex, &pParty->pPickedItem); + if ( !emptyIndex ) + { + emptyIndex = this->AddItem2(-1, &pParty->pPickedItem); + if ( !emptyIndex ) + { + this->PutItemArInventoryIndex(tmpItem.uItemID, invItemIndex - 1, invMatrixIndex); + memcpy(invItemPtr, &tmpItem, sizeof(ItemGen)); + return; + } + } + memcpy(&pParty->pPickedItem, &tmpItem, sizeof(ItemGen)); + pMouse->SetCursorBitmap(pParty->pPickedItem.GetIconName()); + return; + } + else + { + itemPos = this->AddItem(invMatrixIndex, pickedItemId); + if ( itemPos ) + { + memcpy(&this->pInventoryItemList[itemPos-1], &pParty->pPickedItem, sizeof(ItemGen)); + pMouse->RemoveHoldingItem(); + return; + } + itemPos = this->AddItem(-1, pickedItemId); + if ( itemPos ) + { + memcpy(&this->pInventoryItemList[itemPos-1], &pParty->pPickedItem, sizeof(ItemGen)); + pMouse->RemoveHoldingItem(); + return; + } + } + } + } + } +} + + +bool Player::IsWeak() +{ + return pConditions[Condition_Weak] != 0; +} + +bool Player::IsDead() +{ + return pConditions[Condition_Dead] != 0; +} + +bool Player::IsEradicated() +{ + return pConditions[Condition_Eradicated] != 0; +} + +bool Player::IsZombie() +{ + return pConditions[Condition_Zombie] != 0; +} + +bool Player::IsCursed() +{ + return pConditions[Condition_Cursed] != 0; +} + +bool Player::IsPertified() +{ + return pConditions[Condition_Pertified] != 0; +} + +bool Player::IsUnconcious() +{ + return pConditions[Condition_Unconcious] != 0; +} + +bool Player::IsAsleep() +{ + return pConditions[Condition_Sleep] != 0; +} + +bool Player::IsParalyzed() +{ + return pConditions[Condition_Paralyzed] != 0; +} + +bool Player::IsDrunk() +{ + return pConditions[Condition_Drunk] != 0; +} + +void Player::SetCursed( unsigned long long state ) +{ + pConditions[Condition_Cursed] = state; +} + +void Player::SetWeak( unsigned long long state ) +{ + pConditions[Condition_Weak] = state; +} + +void Player::SetAsleep( unsigned long long state ) +{ + pConditions[Condition_Sleep] = state; +} + +void Player::SetAfraid( unsigned long long state ) +{ + pConditions[Condition_Fear] = state; +} + +void Player::SetDrunk( unsigned long long state ) +{ + pConditions[Condition_Drunk] = state; +} + +void Player::SetInsane( unsigned long long state ) +{ + pConditions[Condition_Insane] = state; +} + +void Player::SetPoisonWeak( unsigned long long state ) +{ + pConditions[Condition_Poison_Weak] = state; +} + +void Player::SetDiseaseWeak( unsigned long long state ) +{ + pConditions[Condition_Disease_Weak] = state; +} + +void Player::SetPoisonMedium( unsigned long long state ) +{ + pConditions[Condition_Poison_Medium] = state; +} + +void Player::SetDiseaseMedium( unsigned long long state ) +{ + pConditions[Condition_Disease_Medium] = state; +} + +void Player::SetPoisonSevere( unsigned long long state ) +{ + pConditions[Condition_Poison_Severe] = state; +} + +void Player::SetDiseaseSevere( unsigned long long state ) +{ + pConditions[Condition_Disease_Severe] = state; +} + +void Player::SetParalyzed( unsigned long long state ) +{ + pConditions[Condition_Paralyzed] = state; +} + +void Player::SetUnconcious( unsigned long long state ) +{ + pConditions[Condition_Unconcious] = state; +} + +void Player::SetDead( unsigned long long state ) +{ + pConditions[Condition_Dead] = state; +} + +void Player::SetPertified( unsigned long long state ) +{ + pConditions[Condition_Pertified] = state; +} + +void Player::SetEradicated( unsigned long long state ) +{ + pConditions[Condition_Eradicated] = state; +} + +void Player::SetZombie( unsigned long long state ) +{ + pConditions[Condition_Zombie] = state; +} + +void Player::SetCondWeakWithBlockCheck( int blockable ) +{ + SetCondition(Condition_Weak, blockable); +} + +void Player::SetCondInsaneWithBlockCheck( int blockable ) +{ + SetCondition(Condition_Insane, blockable); +} + +void Player::SetCondDeadWithBlockCheck( int blockable ) +{ + SetCondition(Condition_Dead, blockable); +} + +void Player::SetCondUnconsciousWithBlockCheck( int blockable ) +{ + SetCondition(Condition_Dead, blockable); +} + +ItemGen* Player::GetOffHandItem() +{ + return GetItem(&PlayerEquipment::uShield); +} + +ItemGen* Player::GetMainHandItem() +{ + return GetItem(&PlayerEquipment::uMainHand); +} + +ItemGen* Player::GetBowItem() +{ + return GetItem(&PlayerEquipment::uBow); +} + +ItemGen* Player::GetArmorItem() +{ + return GetItem(&PlayerEquipment::uArmor); +} + +ItemGen* Player::GetHelmItem() +{ + return GetItem(&PlayerEquipment::uHelm); +} + +ItemGen* Player::GetBeltItem() +{ + return GetItem(&PlayerEquipment::uBelt); +} + +ItemGen* Player::GetCloakItem() +{ + return GetItem(&PlayerEquipment::uCloak); +} + +ItemGen* Player::GetGloveItem() +{ + return GetItem(&PlayerEquipment::uGlove); +} + +ItemGen* Player::GetBootItem() +{ + return GetItem(&PlayerEquipment::uBoot); +} + +ItemGen* Player::GetAmuletItem() +{ + return GetItem(&PlayerEquipment::uAmulet); +} + +ItemGen* Player::GetNthRingItem(int ringNum) +{ + return GetNthEquippedIndexItem(ringNum + 10); +} + +ItemGen* Player::GetNthEquippedIndexItem(int index) +{ + if (this->pEquipment.pIndices[index] == 0) + { + return nullptr; + } + return &this->pInventoryItemList[this->pEquipment.pIndices[index] - 1]; +} + +ItemGen* Player::GetItem(unsigned int PlayerEquipment::* itemPos) +{ + if (this->pEquipment.*itemPos == 0) + { + return nullptr; + } + return &this->pInventoryItemList[this->pEquipment.*itemPos - 1]; +} + +int Player::GetPlayerIndex() +{ + int uPlayerIdx = 0; + if ( this == pPlayers[1] ) + uPlayerIdx = 0; + else if( this == pPlayers[2] ) + uPlayerIdx = 1; + else if ( this == pPlayers[3] ) + uPlayerIdx = 2; + else if ( this == pPlayers[4] ) + uPlayerIdx = 3; + else + Error("Unexpected player pointer"); + return uPlayerIdx; +} + +//----- (004272F5) -------------------------------------------------------- +bool Player::PlayerHitOrMiss(Actor *pActor, int a3, int a4) +{ + signed int naturalArmor; // esi@1 + signed int armorBuff; // edi@1 + int effectiveActorArmor; // esi@8 + int attBonus; // eax@9 + int v9; // edx@11 +// unsigned __int8 v12; // sf@13 +// unsigned __int8 v13; // of@13 + int attPositiveMod; // edx@14 + int attNegativeMod; // eax@14 +// signed int result; // eax@17 + + naturalArmor = pActor->pMonsterInfo.uAC; + armorBuff = 0; + if ( pActor->pActorBuffs[ACTOR_BUFF_SOMETHING_THAT_HALVES_AC].uExpireTime > 0 ) + naturalArmor /= 2; + if ( pActor->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) + armorBuff = pActor->pActorBuffs[ACTOR_BUFF_SHIELD].uPower; + if ( pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uExpireTime > 0 && pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower > armorBuff ) + armorBuff = pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower; + effectiveActorArmor = armorBuff + naturalArmor; + if ( a3 ) + attBonus = this->GetRangedAttack(); + else + attBonus = this->GetActualAttack(false); + v9 = rand() % (effectiveActorArmor + 2 * attBonus + 30); + attPositiveMod = a4 + v9; + if ( a3 == 2 ) + { + attNegativeMod = ((effectiveActorArmor + 15) / 2) + effectiveActorArmor + 15; + } + else if ( a3 == 3 ) + { + attNegativeMod = 2 * effectiveActorArmor + 30; + } + else + { + attNegativeMod = effectiveActorArmor + 15; + } + return (attPositiveMod > attNegativeMod); +} + + +//----- (0042ECB5) -------------------------------------------------------- +void Player::_42ECB5_PlayerAttacksActor() +{ +// char *v5; // eax@8 +// unsigned int v9; // ecx@21 +// char *v11; // eax@26 +// unsigned int v12; // eax@47 +// SoundID v24; // [sp-4h] [bp-40h]@58 + + //result = pParty->pPlayers[uActiveCharacter-1].CanAct(); + Player* player = &pParty->pPlayers[uActiveCharacter - 1]; + if (!player->CanAct()) + return; + + CastSpellInfoHelpers::_427D48(); + //v3 = 0; + if (pParty->Invisible()) + pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset(); + + //v31 = player->pEquipment.uBow; + int bow_idx = player->pEquipment.uBow; + if (bow_idx && player->pInventoryItemList[bow_idx - 1].IsBroken()) + bow_idx = 0; + + //v32 = 0; + int wand_item_id = 0; + //v33 = 0; + //v4 = v1->pEquipment.uMainHand; + int laser_weapon_item_id = 0; + + int main_hand_idx = player->pEquipment.uMainHand; + if (main_hand_idx) + { + ItemGen* item = &player->pInventoryItemList[main_hand_idx - 1]; + //v5 = (char *)v1 + 36 * v4; + if (!item->IsBroken()) + { + //v28b = &v1->pInventoryItems[v4].uItemID; + //v6 = v1->pInventoryItems[v4].uItemID;//*((int *)v5 + 124); + if (item->GetItemEquipType() == EQUIP_WAND) + { + if (item->uNumCharges <= 0) + player->pEquipment.uMainHand = 0; // wand discharged - unequip + else + wand_item_id = item->uItemID;//*((int *)v5 + 124); + } + else if (item->uItemID == ITEM_BLASTER || item->uItemID == ITEM_LASER_RIFLE) + laser_weapon_item_id = item->uItemID;//*((int *)v5 + 124); + } + } + + //v30 = 0; + //v29 = 0; + //v28 = 0; + //v7 = pMouse->uPointingObjectID; + + int target_pid = pMouse->uPointingObjectID; + int target_type = PID_TYPE(target_pid), + target_id = PID_ID(target_pid); + if (target_type != OBJECT_Actor || !pActors[target_id].CanAct()) + { + target_pid = stru_50C198.FindClosestActor(5120, 0, 0); + target_type = PID_TYPE(target_pid); + target_id = PID_ID(target_pid); + } + + Actor* actor = &pActors[target_id]; + int actor_distance = 0; + if (target_type == OBJECT_Actor) + { + int distance_x = actor->vPosition.x - pParty->vPosition.x, + distance_y = actor->vPosition.y - pParty->vPosition.y, + distance_z = actor->vPosition.z - pParty->vPosition.z; + actor_distance = integer_sqrt(distance_x * distance_x + distance_y * distance_y + distance_z * distance_z) - actor->uActorRadius; + if (actor_distance < 0) + actor_distance = 0; + } + + bool shooting_bow = false, + shotting_laser = false, + shooting_wand = false, + melee_attack = false; + if (laser_weapon_item_id) + { + shotting_laser = true; + _42777D_CastSpell_UseWand_ShootArrow(SPELL_LASER_PROJECTILE, uActiveCharacter - 1, 0, 0, uActiveCharacter + 8); + } + else if (wand_item_id) + { + shooting_wand = true; + + int main_hand_idx = player->pEquipment.uMainHand; + _42777D_CastSpell_UseWand_ShootArrow(wand_spell_ids[player->pInventoryItemList[main_hand_idx - 1].uItemID - ITEM_WAND_FIRE], uActiveCharacter - 1, 8, 0, uActiveCharacter + 8); + + if (!--player->pInventoryItemList[main_hand_idx - 1].uNumCharges) + player->pEquipment.uMainHand = 0; + } + else if (target_type == OBJECT_Actor && actor_distance <= 407.2) + { + melee_attack = true; + + Vec3_int_ a3; + a3.x = actor->vPosition.x - pParty->vPosition.x; + a3.y = actor->vPosition.y - pParty->vPosition.y; + a3.z = actor->vPosition.z - pParty->vPosition.z; + Vec3_int_::Normalize(&a3.x, &a3.y, &a3.z); + + Actor::DamageMonsterFromParty(PID(OBJECT_Player, uActiveCharacter - 1), target_id, &a3); + if (player->WearsItem(ITEM_ARTIFACT_SPLITTER, EQUIP_TWO_HANDED) || player->WearsItem(ITEM_ARTIFACT_SPLITTER, EQUIP_SINGLE_HANDED)) + _42FA66_do_explosive_impact(actor->vPosition.x, actor->vPosition.y, actor->vPosition.z + actor->uActorHeight / 2, 0, 512, uActiveCharacter); + } + else if (bow_idx) + { + shooting_bow = true; + _42777D_CastSpell_UseWand_ShootArrow(SPELL_BOW_ARROW, uActiveCharacter - 1, 0, 0, 0); + } + else + { + melee_attack = true; + ; // actor out of range or no actor; no ranged weapon so melee attacking air + } + + if (!pParty->bTurnBasedModeOn && melee_attack) // wands, bows & lasers will add recovery while shooting spell effect + { + int recovery = player->GetAttackRecoveryTime(false); + if (recovery < 30 ) + recovery = 30; + player->SetRecoveryTime(flt_6BE3A4_debug_recmod1 * (double)recovery * 2.133333333333333); + } + + int v34 = 0; + if (shooting_wand) + return; + else if (shooting_bow) + { + v34 = 5; + player->PlaySound(SPEECH_50, 0); + } + if (shotting_laser) + v34 = 7; + else + { + int main_hand_idx = player->pEquipment.uMainHand; + if (player->HasItemEquipped(EQUIP_TWO_HANDED)) + v34 = player->pInventoryItemList[main_hand_idx - 1].GetPlayerSkillType(); + pTurnEngine->ApplyPlayerAction(); + } + + switch (v34) + { + case 0: pAudioPlayer->PlaySound(SOUND_81, 0, 0, -1, 0, 0, 0, 0); break; + case 1: pAudioPlayer->PlaySound(SOUND_84, 0, 0, -1, 0, 0, 0, 0); break; + case 2: pAudioPlayer->PlaySound(SOUND_85, 0, 0, -1, 0, 0, 0, 0); break; + case 3: pAudioPlayer->PlaySound(SOUND_78, 0, 0, -1, 0, 0, 0, 0); break; + case 4: pAudioPlayer->PlaySound(SOUND_80, 0, 0, -1, 0, 0, 0, 0); break; + case 5: pAudioPlayer->PlaySound(SOUND_71, 0, 0, -1, 0, 0, 0, 0); break; + case 6: pAudioPlayer->PlaySound(SOUND_83, 0, 0, -1, 0, 0, 0, 0); break; + case 7: pAudioPlayer->PlaySound(SOUND_67, 0, 0, -1, 0, 0, 0, 0); break; + } +} + + +//----- (0042FA66) -------------------------------------------------------- +void Player::_42FA66_do_explosive_impact(int a1, int a2, int a3, int a4, __int16 a5, signed int a6) +{ + unsigned __int16 v9; // ax@5 + + SpriteObject a1a; // [sp+Ch] [bp-74h]@1 + //SpriteObject::SpriteObject(&a1a); + a1a.uType = 600; + a1a.stru_24.Reset(); + + a1a.spell_id = SPELL_FIRE_FIREBALL; + a1a.spell_level = 8; + a1a.spell_skill = 3; + v9 = 0; + for ( uint i = 0; i < pObjectList->uNumObjects; ++i ) + { + if ( a1a.uType == pObjectList->pObjects[i].uObjectID ) + v9 = i; + } + a1a.uObjectDescID = v9; + a1a.vPosition.x = a1; + a1a.vPosition.y = a2; + a1a.vPosition.z = a3; + a1a.uAttributes = 0; + a1a.uSectorID = pIndoor->GetSector(a1, a2, a3); + a1a.uSpriteFrameID = 0; + a1a.spell_target_pid = 0; + a1a.field_60_distance_related_prolly_lod = 0; + a1a.uFacing = 0; + a1a.uSoundID = 0; + if ( a6 >= 1 || a6 <= 4 ) + a1a.spell_caster_pid = PID(OBJECT_Player, a6 - 1); + else + a1a.spell_caster_pid = 0; + + int id = a1a.Create(0, 0, 0, 0); + if (id != -1) + AttackerInfo.Add(PID(OBJECT_Item, id), a5, SLOWORD(a1a.vPosition.x), SLOWORD(a1a.vPosition.y), + SLOWORD(a1a.vPosition.z), 0, 0); +} + +//----- (00458244) -------------------------------------------------------- +unsigned int SkillToMastery( unsigned int skill_value ) +{ + switch (skill_value & 0x1C0) + { + case 0x100: return 4; // Grandmaster + case 0x80: return 3; // Master + case 0x40: return 2; // Expert + case 0x00: return 1; // Normal + } + assert(false); + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/Player.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,856 @@ +#pragma once +#include "Items.h" +#include "Spells.h" +#include "Conditions.h" + + + +enum PLAYER_BUFFS +{ + PLAYER_BUFF_RESIST_AIR = 0, + PLAYER_BUFF_BLESS = 1, + PLAYER_BUFF_RESIST_BODY = 2, + PLAYER_BUFF_RESIST_EARTH = 3, + PLAYER_BUFF_FATE = 4, + PLAYER_BUFF_RESIST_FIRE = 5, + PLAYER_BUFF_HAMMERHANDS = 6, + PLAYER_BUFF_HASTE = 7, + PLAYER_BUFF_HEROISM = 8, + PLAYER_BUFF_RESIST_MIND = 9, + PLAYER_BUFF_PAIN_REFLECTION = 10, + PLAYER_BUFF_PRESERVATION = 11, + PLAYER_BUFF_REGENERATION = 12, + PLAYER_BUFF_SHIELD = 13, + PLAYER_BUFF_STONESKIN = 14, + PLAYER_BUFF_ACCURACY = 15, + PLAYER_BUFF_ENDURANCE = 16, + PLAYER_BUFF_INTELLIGENCE = 17, + PLAYER_BUFF_LUCK = 18, + PLAYER_BUFF_STRENGTH = 19, + PLAYER_BUFF_WILLPOWER = 20, + PLAYER_BUFF_SPEED = 21, + PLAYER_BUFF_RESIST_WATER = 22, + PLAYER_BUFF_WATER_WALK = 23 +}; + + +#define PLAYER_GUILD_BITS__SPIRIT_MEMBERSHIP 58 +#define PLAYER_GUILD_BITS__ARCOMAGE_WIN 103 +#define PLAYER_GUILD_BITS__ARCOMAGE_LOSE 104 + + +/* 301 */ +enum PlayerSpeech +{ + SPEECH_1 = 1, + SPEECH_2 = 2, + SPEECH_3 = 3, + SPEECH_4 = 4, + SPEECH_5 = 5, + SPEECH_6 = 6, + SPEECH_7 = 7, + SPEECH_8 = 8, + SPEECH_9 = 9, + SPEECH_10 = 10, + SPEECH_11 = 11, + SPEECH_12 = 12, + SPEECH_14 = 14, + SPEECH_NoRoom = 15, // when placing to inventory + SPEECH_DO_POTION_FINE = 16, + SPEECH_17 = 17, + SPEECH_18 = 18, + SPEECH_19 = 19, + SPEECH_20 = 20, + SPEECH_21 = 21, + SPEECH_GoodDay = 22, // greets on dialogue start + SPEECH_GoodEvening = 23, + SPEECH_24 = 24, + SPEECH_25 = 25, + SPEECH_26 = 26, + SPEECH_27 = 27, + SPEECH_28 = 28, + SPEECH_29 = 29, + SPEECH_30 = 30, + SPEECH_31 = 31, + SPEECH_32 = 32, + SPEECH_33 = 33, + SPEECH_34 = 34, + SPEECH_35 = 35, + SPEECH_36 = 36, + SPEECH_37 = 37, + SPEECH_NotEnoughGold = 38, + SPEECH_39 = 39, + SPEECH_40 = 40, + SPEECH_41 = 41, + SPEECH_42 = 42, + SPEECH_43 = 43, + SPEECH_44 = 44, + SPEECH_45 = 45, + SPEECH_46 = 46, + SPEECH_47 = 47, + SPEECH_48 = 48, + SPEECH_49 = 49, + SPEECH_50 = 50, + SPEECH_51 = 51, + SPEECH_52 = 52, + SPEECH_53 = 53, + SPEECH_54 = 54, + SPEECH_55 = 55, + SPEECH_56 = 56, + SPEECH_57 = 57, + SPEECH_58 = 58, + SPEECH_59 = 59, + SPEECH_60 = 60, + SPEECH_61 = 61, + SPEECH_62 = 62, + SPEECH_63 = 63, + SPEECH_64 = 64, + SPEECH_Yell = 65, + SPEECH_Falling_scream = 66, + SPEECH_67 = 67, + SPEECH_68 = 68, + SPEECH_69 = 69, + SPEECH_70 = 70, + SPEECH_CarriageReady = 71, // travelling by carriage + SPEECH_SetSail = 72, // travelling by sea + SPEECH_73 = 73, + SPEECH_74 = 74, + SPEECH_75 = 75, + SPEECH_76 = 76, + SPEECH_77 = 77, + SPEECH_78 = 78, + SPEECH_79 = 79, + SPEECH_80 = 80, + SPEECH_81 = 81, + SPEECH_82 = 82, + SPEECH_83 = 83, + SPEECH_84 = 84, + SPEECH_85 = 85, + SPEECH_86 = 86, + SPEECH_87 = 87, + SPEECH_88 = 88, + SPEECH_89 = 89, + SPEECH_90 = 90, + SPEECH_91 = 91, + SPEECH_92 = 92, + SPEECH_93 = 93, + SPEECH_94 = 94, + SPEECH_95 = 95, + SPEECH_96 = 96, + SPEECH_97 = 97, + SPEECH_98 = 98, + SPEECH_99 = 99, + SPEECH_100 = 100, + SPEECH_101 = 101, + SPEECH_PickMe = 102, + SPEECH_103 = 103, + SPEECH_IDENTIFY_MONSTER_WEAKER = 104, + SPEECH_IDENTIFY_MONSTER_STRONGER = 105, + SPEECH_IDENTIFY_MONSTER_106 = 106, + SPEECH_107 = 107, + SPEECH_108 = 108, + SPEECH_109 = 109, + SPEECH_110 = 110, +}; + + + +/* 339 */ +enum CHARACTER_RACE +{ + CHARACTER_RACE_HUMAN = 0, + CHARACTER_RACE_ELF = 1, + CHARACTER_RACE_GOBLIN = 2, + CHARACTER_RACE_DWARF = 3, +}; + +/* 332 */ +enum CHARACTER_ATTRIBUTE_TYPE +{ + CHARACTER_ATTRIBUTE_STRENGTH = 0, + CHARACTER_ATTRIBUTE_INTELLIGENCE = 1, + CHARACTER_ATTRIBUTE_WILLPOWER = 2, + CHARACTER_ATTRIBUTE_ENDURANCE = 3, + CHARACTER_ATTRIBUTE_ACCURACY = 4, + CHARACTER_ATTRIBUTE_SPEED = 5, + CHARACTER_ATTRIBUTE_LUCK = 6, + CHARACTER_ATTRIBUTE_HEALTH = 7, + CHARACTER_ATTRIBUTE_MANA = 8, + CHARACTER_ATTRIBUTE_AC_BONUS = 9, + + CHARACTER_ATTRIBUTE_RESIST_FIRE = 10, + CHARACTER_ATTRIBUTE_RESIST_AIR = 11, + CHARACTER_ATTRIBUTE_RESIST_WATER = 12, + CHARACTER_ATTRIBUTE_RESIST_EARTH = 13, + CHARACTER_ATTRIBUTE_RESIST_MIND = 14, + CHARACTER_ATTRIBUTE_RESIST_BODY = 15, + + CHARACTER_ATTRIBUTE_SKILL_ALCHEMY = 16, + CHARACTER_ATTRIBUTE_SKILL_STEALING = 17, + CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM = 18, + CHARACTER_ATTRIBUTE_SKILL_ITEM_ID = 19, + CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID = 20, + CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER = 21, + CHARACTER_ATTRIBUTE_SKILL_DODGE = 22, + CHARACTER_ATTRIBUTE_SKILL_UNARMED = 23, + + CHARACTER_ATTRIBUTE_LEVEL = 24, + CHARACTER_ATTRIBUTE_ATTACK = 25, + CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS = 26, + CHARACTER_ATTRIBUTE_MELEE_DMG_MIN = 27, + CHARACTER_ATTRIBUTE_MELEE_DMG_MAX = 28, + CHARACTER_ATTRIBUTE_RANGED_ATTACK = 29, + CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS = 30, + CHARACTER_ATTRIBUTE_RANGED_DMG_MIN = 31, + CHARACTER_ATTRIBUTE_RANGED_DMG_MAX = 32, + CHARACTER_ATTRIBUTE_RESIST_SPIRIT = 33, + + CHARACTER_ATTRIBUTE_SKILL_FIRE = 34, + CHARACTER_ATTRIBUTE_SKILL_AIR = 35, + CHARACTER_ATTRIBUTE_SKILL_WATER = 36, + CHARACTER_ATTRIBUTE_SKILL_EARTH = 37, + CHARACTER_ATTRIBUTE_SKILL_SPIRIT = 38, + CHARACTER_ATTRIBUTE_SKILL_MIND = 39, + CHARACTER_ATTRIBUTE_SKILL_BODY = 40, + CHARACTER_ATTRIBUTE_SKILL_LIGHT = 41, + CHARACTER_ATTRIBUTE_SKILL_DARK = 42, + CHARACTER_ATTRIBUTE_SKILL_MEDITATION = 43, + CHARACTER_ATTRIBUTE_SKILL_BOW = 44, + CHARACTER_ATTRIBUTE_SKILL_SHIELD = 45, + CHARACTER_ATTRIBUTE_SKILL_LEARNING = 46 +}; + +#pragma warning( push ) +#pragma warning( disable: 4341 ) +/* 328 */ +enum PLAYER_SKILL_TYPE: signed __int8 +{ + PLAYER_SKILL_STAFF = 0, + PLAYER_SKILL_SWORD = 1, + PLAYER_SKILL_DAGGER = 2, + PLAYER_SKILL_AXE = 3, + PLAYER_SKILL_SPEAR = 4, + PLAYER_SKILL_BOW = 5, + PLAYER_SKILL_MACE = 6, + PLAYER_SKILL_BLASTER = 7, + PLAYER_SKILL_SHIELD = 8, + PLAYER_SKILL_LEATHER = 9, + PLAYER_SKILL_CHAIN = 10, + PLAYER_SKILL_PLATE = 11, + PLAYER_SKILL_FIRE = 12, + PLAYER_SKILL_AIR = 13, + PLAYER_SKILL_WATER = 14, + PLAYER_SKILL_EARTH = 15, + PLAYER_SKILL_SPIRIT = 16, + PLAYER_SKILL_MIND = 17, + PLAYER_SKILL_BODY = 18, + PLAYER_SKILL_LIGHT = 19, + PLAYER_SKILL_DARK = 20, + PLAYER_SKILL_ITEM_ID = 21, + PLAYER_SKILL_MERCHANT = 22, + PLAYER_SKILL_REPAIR = 23, + PLAYER_SKILL_BODYBUILDING = 24, + PLAYER_SKILL_MEDITATION = 25, + PLAYER_SKILL_PERCEPTION = 26, + PLAYER_SKILL_DIPLOMACY = 27, + PLAYER_SKILL_TIEVERY = 28, + PLAYER_SKILL_TRAP_DISARM = 29, + PLAYER_SKILL_DODGE = 30, + PLAYER_SKILL_UNARMED = 31, + PLAYER_SKILL_MONSTER_ID = 32, + PLAYER_SKILL_ARMSMASTER = 33, + PLAYER_SKILL_STEALING = 34, + PLAYER_SKILL_ALCHEMY = 35, + PLAYER_SKILL_LEARNING = 36, + PLAYER_SKILL_CLUB = 37, + PLAYER_SKILL_MISC = 38, + PLAYER_SKILL_INVALID = -1 +}; +#pragma warning( pop ) + +/* 329 */ +enum PLAYER_CLASS_TYPE: unsigned __int8 +{ + PLAYER_CLASS_KNIGHT = 0, + PLAYER_CLASS_CHEVALIER = 1, + PLAYER_CLASS_CHAMPION = 2, + PLAYER_CLASS_BLACK_KNIGHT = 3, + PLAYER_CLASS_THEIF = 4, + PLAYER_CLASS_ROGUE = 5, + PLAYER_CLASS_SPY = 6, + PLAYER_CLASS_ASSASSIN = 7, + PLAYER_CLASS_MONK = 8, + PLAYER_CLASS_INITIATE = 9, + PLAYER_CLASS_MASTER = 10, + PLAYER_CLASS_NINJA = 11, + PLAYER_CLASS_PALADIN = 12, + PLAYER_CLASS_CRUSADER = 13, + PLAYER_CLASS_HERO = 14, + PLAYER_CLASS_VILLIAN = 15, + PLAYER_CLASS_ARCHER = 16, + PLAYER_CLASS_WARRIOR_MAGE = 17, + PLAYER_CLASS_MASTER_ARCHER = 18, + PLAYER_CLASS_SNIPER = 19, + PLAYER_CLASS_RANGER = 20, + PLAYER_CLASS_HUNTER = 21, + PLAYER_CLASS_RANGER_LORD = 22, + PLAYER_CLASS_BOUNTY_HUNTER = 23, + PLAYER_CLASS_CLERIC = 24, + PLAYER_CLASS_PRIEST = 25, + PLAYER_CLASS_PRIEST_OF_SUN = 26, + PLAYER_CLASS_PRIEST_OF_MOON = 27, + PLAYER_CLASS_DRUID = 28, + PLAYER_CLASS_GREAT_DRUID = 29, + PLAYER_CLASS_ARCH_DRUID = 30, + PLAYER_CLASS_WARLOCK = 31, + PLAYER_CLASS_SORCERER = 32, + PLAYER_CLASS_WIZARD = 33, + PLAYER_CLASS_ARCHMAGE = 34, + PLAYER_CLASS_LICH = 35 +}; + + + + +#pragma pack(push, 1) +struct LloydBeacon +{ + unsigned __int64 uBeaconTime; + int PartyPos_X; + int PartyPos_Y; + int PartyPos_Z; + __int16 PartyRot_X; + __int16 PartyRot_Y; + int SaveFileID; +}; +#pragma pack(pop) + + + +#pragma pack(push, 1) +struct PlayerSpellbookChapter +{ + std::array<char, 11> bIsSpellAvailable; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct PlayerSpells +{ + union + { + struct + { + PlayerSpellbookChapter pFireSpellbook; + PlayerSpellbookChapter pAirSpellbook; + PlayerSpellbookChapter pWaterSpellbook; + PlayerSpellbookChapter pEarthSpellbook; + PlayerSpellbookChapter pSpiritSpellbook; + PlayerSpellbookChapter pMindSpellbook; + PlayerSpellbookChapter pBodySpellbook; + PlayerSpellbookChapter pLightSpellbook; + PlayerSpellbookChapter pDarkSpellbook; + char _pad_0; + }; + struct + { + std::array<PlayerSpellbookChapter, 9> pChapters; + char _pad_1; + }; + struct + { + std::array<char, 99> bHaveSpell; + char _pad_1; + }; + }; +}; +#pragma pack(pop) + + + +#pragma pack(push, 1) +union PlayerEquipment +{ + union + { + struct + { + unsigned int uShield; + unsigned int uMainHand; + unsigned int uBow; + unsigned int uArmor; + unsigned int uHelm; + unsigned int uBelt; + unsigned int uCloak; + unsigned int uGlove; + unsigned int uBoot; + unsigned int uAmulet; + std::array<unsigned int, 6> uRings; + //unsigned int field_2C; + //unsigned int field_30; + //unsigned int field_34; + //unsigned int field_38; + //unsigned int field_3C; + }; + std::array<unsigned int, 16> pIndices; + }; +}; +#pragma pack(pop) + + + + + +enum CHARACTER_EXPRESSION_ID: unsigned __int16 +{ + CHARACTER_EXPRESSION_INVALID = 0, + CHARACTER_EXPRESSION_1 = 1, + CHARACTER_EXPRESSION_CURSED = 2, + CHARACTER_EXPRESSION_WEAK = 3, + CHARACTER_EXPRESSION_SLEEP = 4, + CHARACTER_EXPRESSION_FEAR = 5, + CHARACTER_EXPRESSION_DRUNK = 6, + CHARACTER_EXPRESSION_INSANE = 7, + CHARACTER_EXPRESSION_POISONED = 8, + CHARACTER_EXPRESSION_DISEASED = 9, + CHARACTER_EXPRESSION_PARALYZED = 10, + CHARACTER_EXPRESSION_UNCONCIOUS = 11, + CHARACTER_EXPRESSION_PERTIFIED = 12, + CHARACTER_EXPRESSION_13 = 13, + CHARACTER_EXPRESSION_14 = 14, + CHARACTER_EXPRESSION_15 = 15, + CHARACTER_EXPRESSION_16 = 16, + CHARACTER_EXPRESSION_17 = 17, + CHARACTER_EXPRESSION_18 = 18, + CHARACTER_EXPRESSION_19 = 19, + CHARACTER_EXPRESSION_20 = 20, + CHARACTER_EXPRESSION_21 = 21, + CHARACTER_EXPRESSION_22 = 22, + CHARACTER_EXPRESSION_23 = 23, + CHARACTER_EXPRESSION_24 = 24, + CHARACTER_EXPRESSION_25 = 25, + CHARACTER_EXPRESSION_26 = 26, + CHARACTER_EXPRESSION_27 = 27, + CHARACTER_EXPRESSION_28 = 28, + CHARACTER_EXPRESSION_29 = 29, + CHARACTER_EXPRESSION_30 = 30, + CHARACTER_EXPRESSION_31 = 31, + CHARACTER_EXPRESSION_32 = 32, + CHARACTER_EXPRESSION_33 = 33, + CHARACTER_EXPRESSION_DMGRECVD_MINOR = 34, + CHARACTER_EXPRESSION_DMGRECVD_MODERATE = 35, + CHARACTER_EXPRESSION_DMGRECVD_MAJOR = 36, + CHARACTER_EXPRESSION_37 = 37, + CHARACTER_EXPRESSION_38 = 38, + CHARACTER_EXPRESSION_39 = 39, + + // ? + + CHARACTER_EXPRESSION_SCARED = 46, // like falling + + CHARACTER_EXPRESSION_54 = 54, + CHARACTER_EXPRESSION_55 = 55, + CHARACTER_EXPRESSION_56 = 56, + CHARACTER_EXPRESSION_57 = 57, + CHARACTER_EXPRESSION_FALLING = 58, + + // ? + + CHARACTER_EXPRESSION_DEAD = 98, + CHARACTER_EXPRESSION_ERADICATED = 99, +}; + + +enum PLAYER_SEX: unsigned __int8 +{ + SEX_MALE = 0, + SEX_FEMALE = 1 +}; + +#pragma pack(push, 1) +struct Player +{ + static const unsigned int INVETORYSLOTSWIDTH = 14; + static const unsigned int INVETORYSLOTSHEIGHT = 9; + + + Player(); + + void SetVariable(enum VariableType var, signed int a3); + void AddVariable(enum VariableType var, signed int val); + void SubtractVariable(enum VariableType VarNum, signed int pValue); + bool CompareVariable(enum VariableType VarNum, signed int pValue); + void UseItem_DrinkPotion_etc(signed int a2, int a3); + bool AddItem(struct ItemGen *pItem); + int GetActualAttribute(CHARACTER_ATTRIBUTE_TYPE attrId, unsigned short Player::* attrValue, unsigned short Player::* attrBonus); + int GetBaseStrength(); + int GetBaseIntelligence(); + int GetBaseWillpower(); + int GetBaseEndurance(); + int GetBaseAccuracy(); + int GetBaseSpeed(); + int GetBaseLuck(); + int GetBaseLevel(); + int GetActualLevel(); + int GetActualMight(); + int GetActualIntelligence(); + int GetActualWillpower(); + int GetActualEndurance(); + int GetActualAccuracy(); + int GetActualSpeed(); + int GetActualLuck(); + int GetActualAttack(bool a2); + int GetMeleeDamageMinimal(); + int GetMeleeDamageMaximal(); + int CalculateMeleeDamageTo(bool ignoreSkillBonus, bool ignoreOffhand, unsigned int uTargetActorID); + int GetRangedAttack(); + int GetRangedDamageMin(); + int GetRangedDamageMax(); + int CalculateRangedDamageTo(int a2); + char *GetMeleeDamageString(); + char *GetRangedDamageString(); + bool CanTrainToNextLevel(); + unsigned int GetExperienceDisplayColor(); + int CalculateIncommingDamage(DAMAGE_TYPE dmg_type, int amount); + ITEM_EQUIP_TYPE GetEquippedItemEquipType(ITEM_EQUIP_TYPE uEquipSlot); + PLAYER_SKILL_TYPE GetEquippedItemSkillType(ITEM_EQUIP_TYPE uEquipSlot); + bool IsUnarmed(); + bool HasItemEquipped(ITEM_EQUIP_TYPE uEquipIndex); + bool HasEnchantedItemEquipped(int uEnchantment); + bool WearsItem(int item_id, ITEM_EQUIP_TYPE equip_type); + int StealFromShop( ItemGen *itemToSteal, int a3, int reputation, int a5, int *fineIfFailed); + int StealFromActor(unsigned int uActorID, int _steal_perm, int reputation); + void Heal(int amount); + int ReceiveDamage(signed int amount, DAMAGE_TYPE dmg_type); + int ReceiveSpecialAttackEffect(int attType, struct Actor *pActor); + unsigned int GetSpellSchool(unsigned int uSpellID); + int GetAttackRecoveryTime(bool bRangedAttack); + int GetMaxHealth(); + int GetMaxMana(); + int GetBaseAC(); + int GetActualAC(); + unsigned int GetBaseAge(); + unsigned int GetActualAge(); + int GetBaseResistance(enum CHARACTER_ATTRIBUTE_TYPE a2); + int GetActualResistance(enum CHARACTER_ATTRIBUTE_TYPE a2); + void SetRecoveryTime(signed int sRecoveryTime); + void RandomizeName(); + unsigned int GetMajorConditionIdx(); + int GetParameterBonus(int player_parameter); + int GetSpecialItemBonus(int enchantmentId); + int GetItemsBonus(enum CHARACTER_ATTRIBUTE_TYPE attr, bool a3 = false); + int GetMagicalBonus(enum CHARACTER_ATTRIBUTE_TYPE a2); + int GetActualSkillLevel(PLAYER_SKILL_TYPE uSkillType); + int GetSkillBonus(enum CHARACTER_ATTRIBUTE_TYPE a2); + enum CHARACTER_RACE GetRace(); + PLAYER_SEX GetSexByVoice(); + void SetInitialStats(); + void SetSexByVoice(); + void Reset(PLAYER_CLASS_TYPE classType); + PLAYER_SKILL_TYPE GetSkillIdxByOrder(signed int order); + void DecreaseAttribute(int eAttribute); + void IncreaseAttribute(int eAttribute); + void Player::Zero(); + unsigned int GetStatColor(int uStat); + bool DiscardConditionIfLastsLongerThan(unsigned int uCondition, signed __int64 uTime); + int SelectPhrasesTransaction(ItemGen *pItem, int building_type, int BuildID_2Events, int a5); + int GetBodybuilding(); + int GetMeditation(); + bool CanIdentify(ItemGen *pItem); + bool CanRepair(ItemGen *pItem); + int GetMerchant(); + int GetPerception(); + int GetDisarmTrap(); + char GetLearningPercent(); + bool CanFitItem(unsigned int uSlot, unsigned int uItemID); + int FindFreeInventoryListSlot(); + int CreateItemInInventory(unsigned int uSlot, unsigned int uItemID); + int HasSkill(unsigned int uSkillType); + void WearItem(unsigned int uItemID); + int AddItem(int uSlot, unsigned int uItemID); + int AddItem2(int uSlot, ItemGen *Src); + int CreateItemInInventory2(unsigned int index, ItemGen *Src); + void PutItemArInventoryIndex(int uItemID, int itemListPos, int uSlot); + void RemoveItemAtInventoryIndex(unsigned int uSlot); + bool CanAct(); + bool CanSteal(); + bool CanEquip_RaceAndAlignmentCheck(unsigned int uItemID); + void SetCondition(unsigned int uConditionIdx, int a3); + bool ProfessionOrGuildFlagsCorrect(unsigned int uClass, int a3); + void PlaySound(PlayerSpeech speech, int a3); + void PlayEmotion(CHARACTER_EXPRESSION_ID expression, int a3); + void ItemsEnchant(int enchant_count); + unsigned int GetItemIDAtInventoryIndex(int *a2); + bool IsPlayerHealableByTemple(); + int GetBaseIdentifyPrice(float a2); + int GetBaseRepairPrice(int a2, float a3); + int GetBaseBuyingPrice(int a2, float a3); + int GetBaseSellingPrice(int a2, float a3); + int GetPriceRepair(int a2, float a3); + int GetPriceIdentification(float a2); + int GetBuyingPrice(unsigned int uRealValue, float price_multiplier); + int GetPriceSell(int uRealValue, float price_multiplier); + int GetTempleHealCostModifier(float a2); + int GetConditionDayOfWeek(unsigned int uCondition); + bool NothingOrJustBlastersEquipped(); + void SalesProcess(unsigned int inventory_idnx, int item_index, int _2devent_idx);//0x4BE2DD + bool Recover(signed int a2); + bool CanCastSpell(unsigned int uRequiredMana); + void PlayAwardSound(); + void EquipBody(ITEM_EQUIP_TYPE uEquipType); + bool HasUnderwaterSuitEquipped(); + bool HasItem(unsigned int uItemID, bool checkHeldItem); + void OnInventoryLeftClick(); + + bool PlayerHitOrMiss(Actor *pActor, int a3, int a4); + + unsigned int GetMultiplierForSkillLevel(unsigned int skillValue, int mult1, int mult2, int mult3, int mult4); + int CalculateMeleeDmgToEnemyWithWeapon( ItemGen * weapon, unsigned int uTargetActorID , bool addOneDice); + bool WearsItemAnyWhere(int item_id); + float GetArmorRecoveryMultiplierFromSkillLevel( unsigned char armour_skill_type, float param2, float param3, float param4, float param5 ); + void SetSkillByEvent(unsigned __int16 Player::* skillToSet, unsigned __int16 skillValue); + void AddSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 addSkillValue); + void PlayAwardSound_Anim(); + void PlayAwardSound_Anim_Face(PlayerSpeech speech); + void PlayAwardSound_Anim97(); + void PlayAwardSound_Anim97_Face(PlayerSpeech speech); + void PlayAwardSound_Anim98(); + void PlayAwardSound_Anim98_Face(PlayerSpeech speech); + + bool IsWeak(); + bool IsDead(); + bool IsEradicated(); + bool IsZombie(); + bool IsCursed(); + bool IsPertified(); + bool IsUnconcious(); + bool IsAsleep(); + bool IsParalyzed(); + bool IsDrunk(); + + void SetCursed(unsigned long long state); + void SetWeak(unsigned long long state); + void SetAsleep(unsigned long long state); + void SetAfraid(unsigned long long state); + void SetDrunk(unsigned long long state); + void SetInsane(unsigned long long state); + void SetPoisonWeak(unsigned long long state); + void SetDiseaseWeak(unsigned long long state); + void SetPoisonMedium(unsigned long long state); + void SetDiseaseMedium(unsigned long long state); + void SetPoisonSevere(unsigned long long state); + void SetDiseaseSevere(unsigned long long state); + void SetParalyzed(unsigned long long state); + void SetUnconcious(unsigned long long state); + void SetDead(unsigned long long state); + void SetPertified(unsigned long long state); + void SetEradicated(unsigned long long state); + void SetZombie(unsigned long long state); + + void SetCondWeakWithBlockCheck (int blockable); + void SetCondInsaneWithBlockCheck (int blockable); + void SetCondDeadWithBlockCheck (int blockable); + void SetCondUnconsciousWithBlockCheck( int blockable ); + + inline bool IsRaceHuman() {return GetRace() == CHARACTER_RACE_HUMAN;} + inline bool IsRaceDwarf() {return GetRace() == CHARACTER_RACE_DWARF;} + inline bool IsRaceElf() {return GetRace() == CHARACTER_RACE_ELF;} + inline bool IsRaceGoblin() {return GetRace() == CHARACTER_RACE_GOBLIN;} + + inline bool IsMale() { return GetSexByVoice() == SEX_MALE;} + inline bool IsFemale() { return !IsMale();} + + ItemGen* GetMainHandItem(); + ItemGen* GetOffHandItem(); + ItemGen* GetBowItem(); + ItemGen* GetArmorItem(); + ItemGen* GetHelmItem(); + ItemGen* GetBeltItem(); + ItemGen* GetCloakItem(); + ItemGen* GetGloveItem(); + ItemGen* GetBootItem(); + ItemGen* GetAmuletItem(); + ItemGen* GetNthRingItem(int ringNum); + ItemGen* GetNthEquippedIndexItem(int index); + ItemGen* GetItem(unsigned int PlayerEquipment::* itemPos); + int GetPlayerIndex(); + + static void _42ECB5_PlayerAttacksActor(); + static void _42FA66_do_explosive_impact(int a1, int a2, int a3, int a4, __int16 a5, signed int a6); + + std::array<__int64, 20> pConditions; + unsigned __int64 uExperience; + char pName[16]; + PLAYER_SEX uSex; + PLAYER_CLASS_TYPE classType; + unsigned __int8 uCurrentFace; + char field_BB; + unsigned __int16 uMight; + unsigned __int16 uMightBonus; + unsigned __int16 uIntelligence; + unsigned __int16 uIntelligenceBonus; + unsigned __int16 uWillpower; + unsigned __int16 uWillpowerBonus; + unsigned __int16 uEndurance; + unsigned __int16 uEnduranceBonus; + unsigned __int16 uSpeed; + unsigned __int16 uSpeedBonus; + unsigned __int16 uAccuracy; + unsigned __int16 uAccuracyBonus; + unsigned __int16 uLuck; + unsigned __int16 uLuckBonus; + __int16 sACModifier; + unsigned __int16 uLevel; + __int16 sLevelModifier; + __int16 sAgeModifier; + int field_E0; + int field_E4; + int field_E8; + int field_EC; + int field_F0; + int field_F4; + int field_F8; + int field_FC; + int field_100; + int field_104; + union + { + struct + { + unsigned __int16 skillStaff; + unsigned __int16 skillSword; + unsigned __int16 skillDagger; + unsigned __int16 skillAxe; + unsigned __int16 skillSpear; + unsigned __int16 skillBow; + unsigned __int16 skillMace; + unsigned __int16 skillBlaster; + unsigned __int16 skillShield; + unsigned __int16 skillLeather; + unsigned __int16 skillChain; + unsigned __int16 skillPlate; + unsigned __int16 skillFire; + unsigned __int16 skillAir; + unsigned __int16 skillWater; + unsigned __int16 skillEarth; + unsigned __int16 skillSpirit; + unsigned __int16 skillMind; + unsigned __int16 skillBody; + unsigned __int16 skillLight; + unsigned __int16 skillDark; + unsigned __int16 skillItemId; + unsigned __int16 skillMerchant; + unsigned __int16 skillRepair; + unsigned __int16 skillBodybuilding; + unsigned __int16 skillMeditation; + unsigned __int16 skillPerception; + unsigned __int16 skillDiplomacy; + unsigned __int16 skillThievery; + unsigned __int16 skillDisarmTrap; + unsigned __int16 skillDodge; + unsigned __int16 skillUnarmed; + unsigned __int16 skillMonsterId; + unsigned __int16 skillArmsmaster; + unsigned __int16 skillStealing; + unsigned __int16 skillAlchemy; + unsigned __int16 skillLearning; + }; + std::array<unsigned __int16, 37> pActiveSkills; + }; + unsigned char _achieved_awards_bits[64]; + PlayerSpells spellbook; + char field__1F5[2]; // used to be [31] + int pure_luck_used; + int pure_speed_used; + int pure_intellect_used; + int pure_endurance_used; + int pure_willpower_used; + int pure_accuracy_used; + int pure_might_used; + union //214h + { + struct + { + std::array<ItemGen, 126> pInventoryItemList; + std::array<ItemGen, 12> pEquippedItems; + }; + std::array<ItemGen, 138> pOwnItems; + }; + + std::array<int, 126> pInventoryMatrix; + __int16 sResFireBase; + __int16 sResAirBase; + __int16 sResWaterBase; + __int16 sResEarthBase; + __int16 field_177C; + __int16 sResMagicBase; + __int16 sResSpiritBase; + __int16 sResMindBase; + __int16 sResBodyBase; + __int16 sResLightBase; + __int16 sResDarkBase; + __int16 sResFireBonus; + __int16 sResAirBonus; + __int16 sResWaterBonus; + __int16 sResEarthBonus; + __int16 field_1792; + __int16 sResMagicBonus; + __int16 sResSpiritBonus; + __int16 sResMindBonus; + __int16 sResBodyBonus; + __int16 sResLightBonus; + __int16 sResDarkBonus; + std::array<SpellBuff, 24> pPlayerBuffs; + unsigned int uVoiceID; + int uPrevVoiceID; + int uPrevFace; + int field_192C; + int field_1930; + unsigned __int16 uTimeToRecovery; + char field_1936; + char field_1937; + unsigned int uSkillPoints; + int sHealth; + int sMana; + unsigned int uBirthYear; + PlayerEquipment pEquipment; + int field_1988[49]; + char field_1A4C; + char field_1A4D; + char lastOpenedSpellbookPage; + unsigned __int8 uQuickSpell; + char playerEventBits[64]; + char _some_attack_bonus; + char field_1A91; + char _melee_dmg_bonus; + char field_1A93; + char _ranged_atk_bonus; + char field_1A95; + char _ranged_dmg_bonus; + char field_1A97; + char uFullHealthBonus; + char _health_related; + char uFullManaBonus; + char _mana_related; + CHARACTER_EXPRESSION_ID expression; + unsigned __int16 uExpressionTimePassed; + unsigned __int16 uExpressionTimeLength; + __int16 field_1AA2; + int _expression21_animtime; + int _expression21_frameset; + std::array<LloydBeacon, 5> pInstalledBeacons; + char uNumDivineInterventionCastsThisDay; + char uNumArmageddonCasts; + char uNumFireSpikeCasts; + char field_1B3B; +}; +#pragma pack(pop) + +void __fastcall DamagePlayerFromMonster(unsigned int uObjID, int a2, struct Vec3_int_ *pPos, signed int a4); +bool IsDwarfPresentInParty(bool b); +bool ShouldLoadTexturesForRaceAndGender(unsigned int _this); +int PlayerCreation_GetUnspentAttributePointCount(); +int CycleCharacter(bool backwards); +unsigned int SkillToMastery(unsigned int skill_value); + +extern NZIArray<struct Player *, 5> pPlayers; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/Player.swig Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,6 @@ +%module Player +%{ + #include "Player.h" +%} + +%include "../../../Player.h" \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/SpriteObject.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,1975 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include "Engine/Graphics/Sprites.h" +#include "Engine/Graphics/BSPModel.h" +#include "SpriteObject.h" +#include "Party.h" +#include "TurnEngine.h" +#include "OurMath.h" +#include "ObjectList.h" +#include "Engine/Graphics/Outdoor.h" +#include "Engine/Graphics/ParticleEngine.h" +#include "Timer.h" +#include "Game.h" +#include "LOD.h" +#include "Actor.h" +#include "Events.h" +#include "AudioPlayer.h" +#include "Engine/Graphics/Level/Decoration.h" + +#include "MM7.h" + +#include "stru298.h" +#include "Random.h" + + + + + + + + +size_t uNumSpriteObjects; +std::array<SpriteObject, MAX_SPRITE_OBJECTS> pSpriteObjects; + +//----- (00404828) -------------------------------------------------------- +SpriteObject::SpriteObject() +{ + field_22_glow_radius_multiplier = 1; + uSoundID = 0; + uFacing = 0; + vVelocity.z = 0; + vVelocity.y = 0; + vVelocity.x = 0; + uType = 0; + uObjectDescID = 0; + field_61 = 0; + field_60_distance_related_prolly_lod = 0; + field_20 = 0; + uSpriteFrameID = 0; + spell_skill = 0; + spell_level = 0; + spell_id = 0; + field_54 = 0; +} + +//----- (0042F5ED) -------------------------------------------------------- +int SpriteObject::Create(int yaw, int pitch, int a4, int a5) +{ + signed int v6; // ebx@2 + int v13; // ST2C_4@20 + Vec3_int_ v17; // [sp-20h] [bp-30h]@11 + int angle; // [sp+Ch] [bp-4h]@1 + int a5a; // [sp+20h] [bp+10h]@20 + + angle = yaw; + if (!uObjectDescID) + return -1; + + v6 = 1000; + for (uint i = 0; i < MAX_SPRITE_OBJECTS; ++i) + if (!pSpriteObjects[i].uObjectDescID) + { + v6 = i; + break; + } + + if ( v6 >= 1000 ) + return -1; + field_64.x = vPosition.x; + field_64.y = vPosition.y; + field_64.z = vPosition.z; + + assert(sizeof(SpriteObject) == 0x70); + + switch (a5) + { + case 0: + break; //do nothing + case 1: + Vec3_int_::Rotate(24, stru_5C6E00->uIntegerHalfPi + uFacing, 0, vPosition, &vPosition.x, + &vPosition.y, &vPosition.z); + break; + case 2: + Vec3_int_::Rotate(8, stru_5C6E00->uIntegerHalfPi + uFacing, 0, vPosition, &vPosition.x, + &vPosition.y, &vPosition.z); + break; + case 3: + Vec3_int_::Rotate(8, uFacing - stru_5C6E00->uIntegerHalfPi, 0, vPosition, &vPosition.x, + &vPosition.y, &vPosition.z); + break; + case 4: + Vec3_int_::Rotate(24, uFacing - stru_5C6E00->uIntegerHalfPi, 0, vPosition, &vPosition.x, + &vPosition.y, &vPosition.z); + break; + default: + assert(false); + return 0; + break; + } + + if ( a4 ) + { + v13 = fixpoint_mul(stru_5C6E00->Cos(angle), stru_5C6E00->Cos(pitch)); + a5a = fixpoint_mul(stru_5C6E00->Sin(angle), stru_5C6E00->Cos(pitch)); + vVelocity.x = fixpoint_mul(v13, a4); + vVelocity.y = fixpoint_mul(a5a, a4); + vVelocity.z = fixpoint_mul(stru_5C6E00->Sin(pitch), a4); + } + else + { + vVelocity.y = 0; + vVelocity.x = 0; + vVelocity.z = 0; + } + + memcpy(&pSpriteObjects[v6], this, sizeof(*this)); + if ( v6 >= (signed int)uNumSpriteObjects ) + uNumSpriteObjects = v6 + 1; + return v6; +} + +//----- (00471C03) -------------------------------------------------------- +void SpriteObject::UpdateObject_fn0_ODM(unsigned int uLayingItemID) +{ + ObjectDesc *object; // ebx@1 + int v6; // eax@1 + int v7; // ecx@1 + int v8; // edi@1 + int v9; // eax@4 +// int v17; // ST10_4@25 + //signed int v19; // eax@28 + //Actor *v20; // edi@31 + int v21; // eax@41 +// int v22; // ecx@43 +// __int16 v23; // bx@45 +// char v24; // al@46 + signed int i; // edi@50 + int v26; // edi@52 + int v27; // eax@52 + __int16 v28; // cx@55 + int v29; // eax@55 + //signed int v30; // edi@59 + BSPModel *bmodel; // ecx@61 + ODMFace *face; // edi@61 +// int v33; // eax@62 +// int v34; // ecx@62 + int v35; // eax@63 + int v36; // ecx@67 + __int16 v37; // ax@67 + int v38; // eax@72 + //int v39; // eax@72 +// unsigned __int64 v40; // qax@72 +// int v41; // eax@72 +// unsigned __int8 v42; // sf@74 +// unsigned __int8 v43; // of@74 + int v44; // eax@77 +// __int16 v45; // bx@81 +// int v46; // eax@85 +// const char *v47; // [sp-8h] [bp-B0h]@83 +// enum TEXTURE_TYPE v48; // [sp-4h] [bp-ACh]@46 + int v49; // [sp+Ch] [bp-9Ch]@52 + int v50; // [sp+10h] [bp-98h]@52 + Vec3_int_ v51; // [sp+14h] [bp-94h]@11 + Particle_sw Dst; // [sp+20h] [bp-88h]@45 + int v54; // [sp+8Ch] [bp-1Ch]@1 + int v55; // [sp+90h] [bp-18h]@1 + int v56; // [sp+94h] [bp-14h]@11 + int v57; // [sp+98h] [bp-10h]@1 + int v58; // [sp+9Ch] [bp-Ch]@1 + int on_water; // [sp+A0h] [bp-8h]@1 + int v60; // [sp+A4h] [bp-4h]@11 + + v58 = 0; + object = &pObjectList->pObjects[pSpriteObjects[uLayingItemID].uObjectDescID]; + v57 = IsTerrainSlopeTooHigh(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y); + v55 = 0; + v6 = ODM_GetFloorLevel(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uHeight, &on_water, &v55, 0); + v7 = v6; + v54 = v6; + v8 = v6 + 1; + if ( pSpriteObjects[uLayingItemID].vPosition.z <= v6 + 1 ) + { + if ( on_water ) + { + v9 = v6 + 60; + if ( v55 ) + v9 = v6 + 30; + sub_42F960_create_object(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, v9); + SpriteObject::OnInteraction(uLayingItemID); + } + } + else + v58 = 1; + if ( !(object->uFlags & OBJECT_DESC_NO_GRAVITY) ) + { + if ( v58 ) + { + pSpriteObjects[uLayingItemID].vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); + goto LABEL_13; + } + if ( v57 ) + { + pSpriteObjects[uLayingItemID].vPosition.z = v8; + ODM_GetTerrainNormalAt(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, &v51); + pSpriteObjects[uLayingItemID].vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); + v56 = abs(v51.y * pSpriteObjects[uLayingItemID].vVelocity.y + v51.z * pSpriteObjects[uLayingItemID].vVelocity.z + v51.x * pSpriteObjects[uLayingItemID].vVelocity.x) >> 16; + //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.x) >> 16); + pSpriteObjects[uLayingItemID].vVelocity.x += fixpoint_mul(v56, v51.x); + //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.y) >> 16); + pSpriteObjects[uLayingItemID].vVelocity.y += fixpoint_mul(v56, v51.y); + //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.z) >> 16); + pSpriteObjects[uLayingItemID].vVelocity.z += fixpoint_mul(v56, v51.z); + v7 = v54; + goto LABEL_13; + } + if ( object->uFlags & OBJECT_DESC_INTERACTABLE ) + { + if ( pSpriteObjects[uLayingItemID].vPosition.z < v7 ) + pSpriteObjects[uLayingItemID].vPosition.z = v8; + if ( !_46BFFA_check_object_intercept(uLayingItemID, 0) ) + return; + } + pSpriteObjects[uLayingItemID].vPosition.z = v8; + if ( !(object->uFlags & OBJECT_DESC_BOUNCE) || (v21 = -pSpriteObjects[uLayingItemID].vVelocity.z >> 1, pSpriteObjects[uLayingItemID].vVelocity.z = v21, (signed __int16)v21 < 10) ) + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + + pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.x); + pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.y); + pSpriteObjects[uLayingItemID].vVelocity.z = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.z); + if ( (pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y + + pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x) < 400 ) + { + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + memset(&Dst, 0, 0x68u); + Dst.x = (double)pSpriteObjects[uLayingItemID].vPosition.x; + Dst.y = (double)pSpriteObjects[uLayingItemID].vPosition.y; + Dst.z = (double)pSpriteObjects[uLayingItemID].vPosition.z; + Dst.r = 0.0; + Dst.g = 0.0; + Dst.b = 0.0; + if (object->uFlags & OBJECT_DESC_TRIAL_FIRE ) + { + Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; + Dst.uDiffuse = 0xFF3C1E; + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + } + else if ( object->uFlags & OBJECT_DESC_TRIAL_LINE) + { + Dst.type = ParticleType_Line; + Dst.uDiffuse = rand(); + Dst.timeToLive = 64; + Dst.uTextureID = 0; + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + } + else if ( object->uFlags & OBJECT_DESC_TRIAL_PARTICLE ) + { + Dst.type = ParticleType_Bitmap | ParticleType_8; + Dst.uDiffuse = rand(); + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + } + return; + } + } +LABEL_13: + if ( pSpriteObjects[uLayingItemID].vPosition.x >= -0x8000 && pSpriteObjects[uLayingItemID].vPosition.x <= 0x8000 + && pSpriteObjects[uLayingItemID].vPosition.y >= -0x8000 && pSpriteObjects[uLayingItemID].vPosition.y <= 0x8000 + && pSpriteObjects[uLayingItemID].vPosition.z > v7 && pSpriteObjects[uLayingItemID].vPosition.z <= 13000 + || !(object->uFlags & OBJECT_DESC_INTERACTABLE) ) + goto LABEL_92; + if ( pSpriteObjects[uLayingItemID].vPosition.z < v7 ) + pSpriteObjects[uLayingItemID].vPosition.z = v8; + if ( _46BFFA_check_object_intercept(uLayingItemID, 0) ) + { +LABEL_92: + stru_721530.field_0 = 0; + stru_721530.prolly_normal_d = object->uRadius; + stru_721530.height = object->uHeight; + stru_721530.field_8_radius = 0; + stru_721530.field_70 = 0; + for ( v55 = 0; v55 < 100; ++v55 ) + { + stru_721530.position.x = pSpriteObjects[uLayingItemID].vPosition.x; + stru_721530.normal.x = stru_721530.position.x; + stru_721530.uSectorID = 0; + stru_721530.position.y = pSpriteObjects[uLayingItemID].vPosition.y; + stru_721530.normal.y = pSpriteObjects[uLayingItemID].vPosition.y; + stru_721530.position.z = pSpriteObjects[uLayingItemID].vPosition.z + stru_721530.prolly_normal_d + 1; + stru_721530.normal.z = stru_721530.position.z; + stru_721530.velocity.x = pSpriteObjects[uLayingItemID].vVelocity.x; + stru_721530.velocity.y = pSpriteObjects[uLayingItemID].vVelocity.y; + stru_721530.velocity.z = pSpriteObjects[uLayingItemID].vVelocity.z; + if ( stru_721530._47050A(0) ) + return; + _46E889_collide_against_bmodels(0); + _46E26D_collide_against_sprites(WorldPosToGridCellX(pSpriteObjects[uLayingItemID].vPosition.x), WorldPosToGridCellZ(pSpriteObjects[uLayingItemID].vPosition.y)); + if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) != OBJECT_Player) + _46EF01_collision_chech_player(0); + if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Actor) + { + if (( PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) >= 0 ) + &&( PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) < (signed int)(uNumActors - 1) )) + { + for (v56 =0; v56 < uNumActors; ++v56) + { + if ( pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].GetActorsRelation(&pActors[v56]) ) + Actor::_46DF1A_collide_against_actor(v56, 0); + } + } + } + else + { + for ( i = 0; i < (signed int)uNumActors; ++i ) + Actor::_46DF1A_collide_against_actor(i, 0); + } + v26 = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; + v27 = ODM_GetFloorLevel( stru_721530.normal2.x, stru_721530.normal2.y, stru_721530.normal2.z - stru_721530.prolly_normal_d - 1, + object->uHeight, &v49, &v50, 0); + if ( on_water && v26 < v27 + 60 ) + { + if ( v50 ) + v44 = v27 + 30; + else + v44 = v54 + 60; + sub_42F960_create_object(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, v44); + SpriteObject::OnInteraction(uLayingItemID); + return; + } + if ( stru_721530.field_7C >= stru_721530.field_6C ) + { + pSpriteObjects[uLayingItemID].vPosition.x = stru_721530.normal2.x; + pSpriteObjects[uLayingItemID].vPosition.y = stru_721530.normal2.y; + pSpriteObjects[uLayingItemID].vPosition.z = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; + pSpriteObjects[uLayingItemID].uSectorID = LOWORD(stru_721530.uSectorID); + memset(&Dst, 0, 0x68u); + Dst.x = (double)pSpriteObjects[uLayingItemID].vPosition.x; + Dst.y = (double)pSpriteObjects[uLayingItemID].vPosition.y; + Dst.z = (double)pSpriteObjects[uLayingItemID].vPosition.z; + Dst.r = 0.0; + Dst.g = 0.0; + Dst.b = 0.0; + if ( object->uFlags & OBJECT_DESC_TRIAL_FIRE ) + { + Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; + Dst.uDiffuse = 0xFF3C1E; + Dst.timeToLive = (unsigned __int8)( rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( object->uFlags & OBJECT_DESC_TRIAL_LINE ) + { + Dst.type = ParticleType_Line; + Dst.uTextureID = 0; + Dst.uDiffuse = rand(); + Dst.timeToLive = 64; + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + { + Dst.type = ParticleType_Bitmap | ParticleType_8; + Dst.uDiffuse = rand(); + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + } + return; + } + //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16); + pSpriteObjects[uLayingItemID].vPosition.x += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x); + //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16); + pSpriteObjects[uLayingItemID].vPosition.y += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y); + //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16); + v28 = LOWORD(stru_721530.uSectorID); + pSpriteObjects[uLayingItemID].vPosition.z += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z); + v29 = pSpriteObjects[uLayingItemID].vPosition.z; + pSpriteObjects[uLayingItemID].uSectorID = v28; + stru_721530.field_70 += stru_721530.field_7C; + if ( object->uFlags & OBJECT_DESC_INTERACTABLE ) + { + if ( v29 < v54 ) + pSpriteObjects[uLayingItemID].vPosition.z = v54 + 1; + if ( !_46BFFA_check_object_intercept(uLayingItemID, stru_721530.uFaceID) ) + return; + } + if (PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration) + break; + if (PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel) + { + bmodel = &pOutdoor->pBModels[(signed int)stru_721530.uFaceID >> 9]; + face = &bmodel->pFaces[PID_ID(stru_721530.uFaceID) & 0x3F]; + if ( face->uPolygonType == POLYGON_Floor ) + { + pSpriteObjects[uLayingItemID].vPosition.z = bmodel->pVertices.pVertices[face->pVertexIDs[0]].z + 1; + if ( pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x + + pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y >= 400 ) + { + if ( face->uAttributes & FACE_UNKNOW2 ) + EventProcessor(face->sCogTriggeredID, 0, 1); + } + else + { + LOWORD(v35) = 0; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = v35; + } + } + else + { + v56 = abs(face->pFacePlane.vNormal.x * pSpriteObjects[uLayingItemID].vVelocity.x + + face->pFacePlane.vNormal.y * pSpriteObjects[uLayingItemID].vVelocity.y + + face->pFacePlane.vNormal.z * pSpriteObjects[uLayingItemID].vVelocity.z) >> 16; + if ( (stru_721530.speed >> 3) > v56 ) + v56 = stru_721530.speed >> 3; + //v57 = fixpoint_mul(v56, face->pFacePlane.vNormal.x); + //v58 = fixpoint_mul(v56, face->pFacePlane.vNormal.y); + v60 = fixpoint_mul(v56, face->pFacePlane.vNormal.z); + pSpriteObjects[uLayingItemID].vVelocity.x += 2 * fixpoint_mul(v56, face->pFacePlane.vNormal.x); + pSpriteObjects[uLayingItemID].vVelocity.y += 2 * fixpoint_mul(v56, face->pFacePlane.vNormal.y); + if ( face->pFacePlane.vNormal.z <= 32000 ) + v37 = 2 * (short)v60; + else + { + v36 = v60; + pSpriteObjects[uLayingItemID].vVelocity.z += (signed __int16)v60; + v58 = fixpoint_mul(0x7D00, v36); + v37 = fixpoint_mul(32000, v36); + } + pSpriteObjects[uLayingItemID].vVelocity.z += v37; + if ( face->uAttributes & FACE_UNKNOW2 ) + EventProcessor(face->sCogTriggeredID, 0, 1); + } + } +LABEL_74: + pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.x); + pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.y); + pSpriteObjects[uLayingItemID].vVelocity.z = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.z); + } + v57 = integer_sqrt(pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x + + pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y); + v38 = stru_5C6E00->Atan2(pSpriteObjects[uLayingItemID].vPosition.x - pLevelDecorations[PID_ID(stru_721530.uFaceID)].vPosition.x, + pSpriteObjects[uLayingItemID].vPosition.y - pLevelDecorations[PID_ID(stru_721530.uFaceID)].vPosition.y); + pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v38), v57); + pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v38 - stru_5C6E00->uIntegerHalfPi), v57); + goto LABEL_74; + } +} + +//----- (0047136C) -------------------------------------------------------- +void SpriteObject::UpdateObject_fn0_BLV(unsigned int uLayingItemID) +{ + SpriteObject *pSpriteObject; // esi@1 + ObjectDesc *pObject; // edi@1 +// int v9; // ecx@16 +// __int16 v10; // di@18 +// int v14; // ebx@34 + signed int v15; // ebx@46 + int v17; // eax@50 +// int v18; // eax@52 +// int v19; // ecx@52 +// Vec3_short_ *v20; // ecx@53 + __int16 v22; // ax@57 + int v23; // edi@62 +// unsigned __int8 v27; // sf@64 +// unsigned __int8 v28; // of@64 +// __int16 v29; // di@67 +// char v30; // al@68 + Particle_sw Dst; // [sp+Ch] [bp-84h]@18 + unsigned int uFaceID; // [sp+7Ch] [bp-14h]@4 + int v39; // [sp+80h] [bp-10h]@33 + int v40; // [sp+84h] [bp-Ch]@28 + int v42; // [sp+8Ch] [bp-4h]@4 + + pSpriteObject = &pSpriteObjects[uLayingItemID]; + pObject = &pObjectList->pObjects[pSpriteObject->uObjectDescID]; + pSpriteObject->uSectorID = pIndoor->GetSector(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z); + v42 = BLV_GetFloorLevel(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z, pSpriteObject->uSectorID, &uFaceID); + if ( abs(pSpriteObject->vPosition.x) > 32767 + || abs(pSpriteObject->vPosition.y) > 32767 + || abs(pSpriteObject->vPosition.z) > 20000 + || v42 <= -30000 + && (pSpriteObject->uSectorID == 0)) +// || (v42 = _46CEC3_get_floor_level(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z, v4, &uFaceID), v42 == -30000)) ) + { + SpriteObject::OnInteraction(uLayingItemID); + return; + } + if ( pObject->uFlags & OBJECT_DESC_NO_GRAVITY )//íå ïàäàþùèå îáúåêòû + { +LABEL_25: + stru_721530.field_0 = 0; + stru_721530.prolly_normal_d = pObject->uRadius; + stru_721530.field_84 = -1; + stru_721530.height = pObject->uHeight; + stru_721530.field_8_radius = 0; + stru_721530.field_70 = 0; + for ( uFaceID = 0; uFaceID < 100; uFaceID++ ) + { + stru_721530.position.x = pSpriteObject->vPosition.x; + stru_721530.position.y = pSpriteObject->vPosition.y; + stru_721530.position.z = stru_721530.prolly_normal_d + pSpriteObject->vPosition.z + 1; + + stru_721530.normal.x = stru_721530.position.x; + stru_721530.normal.y = stru_721530.position.y; + stru_721530.normal.z = stru_721530.position.z; + + stru_721530.velocity.x = pSpriteObject->vVelocity.x; + stru_721530.velocity.y = pSpriteObject->vVelocity.y; + stru_721530.velocity.z = pSpriteObject->vVelocity.z; + + stru_721530.uSectorID = pSpriteObject->uSectorID; + if ( stru_721530._47050A(0) ) + return; + + for ( v40 = 0; v40 < 100; ++v40 ) + { + _46E44E_collide_against_faces_and_portals(0); + _46E0B2_collide_against_decorations(); + if (PID_TYPE(pSpriteObject->spell_caster_pid) != OBJECT_Player) + _46EF01_collision_chech_player(1); + if (PID_TYPE(pSpriteObject->spell_caster_pid) == OBJECT_Actor) + { + for ( v42 = 0; v42 < (signed int)uNumActors; ++v42 ) + { + if( pActors[pSpriteObject->spell_caster_pid >> 3].pMonsterInfo.uID != pActors[v42].pMonsterInfo.uID ) + //not sure: pMonsterList->pMonsters[v39b->word_000086_some_monster_id-1].uToHitRadius + Actor::_46DF1A_collide_against_actor(v42, pMonsterList->pMonsters[pActors[v42].word_000086_some_monster_id-1].uToHitRadius); + } + } + else + { + for ( v42 = 0; v42 < (signed int)uNumActors; v42++ ) + Actor::_46DF1A_collide_against_actor(v42, pMonsterList->pMonsters[pActors[v42].word_000086_some_monster_id-1].uToHitRadius); + } + if ( _46F04E_collide_against_portals() ) + break; + } + if ( stru_721530.field_7C >= stru_721530.field_6C ) + { + pSpriteObject->vPosition.x = stru_721530.normal2.x; + pSpriteObject->vPosition.y = stru_721530.normal2.y; + pSpriteObject->vPosition.z = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; + pSpriteObject->uSectorID = LOWORD(stru_721530.uSectorID); + if ( !(HIBYTE(pObject->uFlags) & 1) ) + return; + memset(&Dst, 0, 0x68u); + Dst.x = (double)pSpriteObject->vPosition.x; + Dst.y = (double)pSpriteObject->vPosition.y; + Dst.z = (double)pSpriteObject->vPosition.z; + Dst.r = 0.0; + Dst.g = 0.0; + Dst.b = 0.0; + if ( pObject->uFlags & OBJECT_DESC_TRIAL_FIRE ) + { + Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; + Dst.uDiffuse = 0xFF3C1E; + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( pObject->uFlags & OBJECT_DESC_TRIAL_LINE ) + { + Dst.type = ParticleType_Line; + Dst.uDiffuse = rand(); + Dst.timeToLive = 64; + Dst.uTextureID = 0; + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( pObject->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + { + Dst.type = ParticleType_Bitmap | ParticleType_8; + Dst.uDiffuse = rand(); + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + } + return; + } + //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16; + pSpriteObject->vPosition.x += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x); + //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16; + pSpriteObject->vPosition.y += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y); + //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16; + pSpriteObject->vPosition.z += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z); + pSpriteObject->uSectorID = stru_721530.uSectorID; + stru_721530.field_70 += stru_721530.field_7C; + if ( pObject->uFlags & OBJECT_DESC_INTERACTABLE && !_46BFFA_check_object_intercept(uLayingItemID, stru_721530.uFaceID) ) + return; + v15 = (signed int)stru_721530.uFaceID >> 3; + if (PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration) + { + v40 = integer_sqrt(pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y); + v23 = stru_5C6E00->Atan2(pSpriteObject->vPosition.x - pLevelDecorations[v15].vPosition.x, + pSpriteObject->vPosition.y - pLevelDecorations[v15].vPosition.y); + pSpriteObject->vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v23), v40); + pSpriteObject->vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v23), v40); + } + if (PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel) + { + stru_721530.field_84 = (signed int)PID_ID(stru_721530.uFaceID); + if ( pIndoor->pFaces[v15].uPolygonType != POLYGON_Floor ) + { + v42 = abs(pIndoor->pFaces[v15].pFacePlane_old.vNormal.x * pSpriteObject->vVelocity.x + + pIndoor->pFaces[v15].pFacePlane_old.vNormal.y * pSpriteObject->vVelocity.y + + pIndoor->pFaces[v15].pFacePlane_old.vNormal.z * pSpriteObject->vVelocity.z) >> 16; + if ( (stru_721530.speed >> 3) > v42 ) + v42 = stru_721530.speed >> 3; + pSpriteObject->vVelocity.x += 2 * fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.x); + pSpriteObject->vVelocity.y += 2 * fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.y); + v39 = fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.z); + if ( pIndoor->pFaces[v15].pFacePlane_old.vNormal.z <= 32000 ) + v22 = 2 * v39; + else + { + pSpriteObject->vVelocity.z += v39; + v22 = fixpoint_mul(32000, v39); + } + pSpriteObject->vVelocity.z += v22; + if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) + EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); + pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); + pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); + pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); + continue; + } + if ( pObject->uFlags & OBJECT_DESC_BOUNCE ) + { + v17 = -pSpriteObject->vVelocity.z / 2; + pSpriteObject->vVelocity.z = v17; + if ( (signed __int16)v17 < 10 ) + pSpriteObject->vVelocity.z = 0; + if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) + EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); + pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); + pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); + pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); + continue; + } + pSpriteObject->vVelocity.z = 0; + if ( pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y >= 400 ) + { + if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) + EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); + pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); + pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); + pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); + continue; + } + pSpriteObject->vVelocity.z = 0; + pSpriteObject->vVelocity.y = 0; + pSpriteObject->vVelocity.x = 0; + pSpriteObject->vPosition.z = pIndoor->pVertices[*pIndoor->pFaces[v15].pVertexIDs].z + 1; + } + pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); + pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); + pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); + } + } + //äëÿ ïàäàþùèõ îáúåêòîâ(äëÿ ïðèìåðà âûáðîñ âåùè èç èíâåíòàðÿ) + if ( v42 <= pSpriteObject->vPosition.z - 3 ) + { + pSpriteObject->vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); + goto LABEL_25; + } + if ( !(pObject->uFlags & OBJECT_DESC_INTERACTABLE) || _46BFFA_check_object_intercept(uLayingItemID, 0) ) + { + pSpriteObject->vPosition.z = v42 + 1; + if ( pIndoor->pFaces[uFaceID].uPolygonType == POLYGON_Floor ) + pSpriteObject->vVelocity.z = 0; + else + { + if ( pIndoor->pFaces[uFaceID].pFacePlane_old.vNormal.z < 45000 ) + pSpriteObject->vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); + } + pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); + pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); + pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); + if ( pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y < 400 ) + { + pSpriteObject->vVelocity.x = 0; + pSpriteObject->vVelocity.y = 0; + pSpriteObject->vVelocity.z = 0; + if ( !(pObject->uFlags & OBJECT_DESC_NO_SPRITE) ) + return; + memset(&Dst, 0, 0x68u); + Dst.x = (double)pSpriteObject->vPosition.x; + Dst.y = (double)pSpriteObject->vPosition.y; + Dst.z = (double)pSpriteObject->vPosition.z; + Dst.r = 0.0; + Dst.g = 0.0; + Dst.b = 0.0; + if ( pObject->uFlags & OBJECT_DESC_TRIAL_FIRE ) + { + Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; + Dst.uDiffuse = 0xFF3C1E; + Dst.flt_28 = 1.0; + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( pObject->uFlags & OBJECT_DESC_TRIAL_LINE ) + { + Dst.type = ParticleType_Line; + Dst.uDiffuse = rand(); + Dst.timeToLive = 64; + Dst.uTextureID = 0; + Dst.flt_28 = 1.0; + pGame->pParticleEngine->AddParticle(&Dst); + return; + } + else if ( pObject->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + { + Dst.type = ParticleType_Bitmap | ParticleType_8; + Dst.uDiffuse = rand(); + Dst.flt_28 = 1.0; + Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; + Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); + pGame->pParticleEngine->AddParticle(&Dst); + } + return; + } + goto LABEL_25; + } +} +// 46DF1A: using guessed type int __fastcall 46DF1A_collide_against_actor(int, int); + +//----- (00438E35) -------------------------------------------------------- +void SpriteObject::ExplosionTraps() +{ + MapInfo *pMapInfo; // esi@1 + int dir_x; // ebx@1 + int v7; // edx@2 + unsigned int v10; // eax@7 + signed int v11; // ebx@8 + signed int v13; // edi@20 + int dir_y; // [sp+Ch] [bp-Ch]@1 + int dir_z; // [sp+10h] [bp-8h]@1 + DAMAGE_TYPE pDamageType; // [sp+14h] [bp-4h]@14 + + pMapInfo = &pMapStats->pInfos[pMapStats->GetMapInfo(pCurrentMapName)]; + dir_x = abs(pParty->vPosition.x - this->vPosition.x); + dir_y = abs(pParty->vPosition.y - this->vPosition.y); + dir_z = abs(pParty->vPosition.z + pParty->sEyelevel - this->vPosition.z); + if ( dir_x < dir_y ) + { + v7 = dir_x; + dir_x = dir_y; + dir_y = v7; + } + if ( dir_x < dir_z ) + { + v7 = dir_x; + dir_x = dir_z; + dir_z = v7; + } + if ( dir_y < dir_z ) + { + v7 = dir_z; + dir_z = dir_y; + dir_y = v7; + } + v10 = ((unsigned int)(11 * dir_y) >> 5) + (dir_z / 4) + dir_x; + if ( (signed int)v10 <= 768 ) + { + v11 = 5; + if ( pMapInfo->Trap_D20 ) + { + for ( uint i = 0; i < pMapInfo->Trap_D20; ++i ) + v11 += rand() % 20 + 1; + } + switch ( this->uType ) + { + case 811: + pDamageType = DMGT_FIRE; + break; + case 812: + pDamageType = DMGT_ELECTR; + break; + case 813: + pDamageType = DMGT_COLD; + break; + case 814: + pDamageType = DMGT_BODY; + break; + default: + return; + } + for ( uint i = 1; i <= 4; ++i ) + { + if ( pPlayers[i]->CanAct() && (v13 = pPlayers[i]->GetPerception() + 20, rand() % v13 > 20) ) + pPlayers[i]->PlaySound(SPEECH_6, 0); + else + pPlayers[i]->ReceiveDamage(v11, pDamageType); + } + } +} + +//----- (0042F933) -------------------------------------------------------- +void SpriteObject::OnInteraction(unsigned int uLayingItemID) +{ + pSpriteObjects[uLayingItemID].uObjectDescID = 0; + if ( pParty->bTurnBasedModeOn == 1 ) + { + if (pSpriteObjects[uLayingItemID].uAttributes & 4 ) + { + pSpriteObjects[uLayingItemID].uAttributes &= 0xFFFB;//~0x00000004 + --pTurnEngine->pending_actions; + } + } +} + + +//----- (0042FA22) -------------------------------------------------------- +void CompactLayingItemsList() +{ + int new_obj_pos = 0; + + for ( int i = 0; i < MAX_SPRITE_OBJECTS; ++i ) + { + if ( pSpriteObjects[i].uObjectDescID ) + { + if ( i != new_obj_pos )// + { + memcpy(&pSpriteObjects[new_obj_pos], &pSpriteObjects[i],sizeof(SpriteObject)); + pSpriteObjects[i].uObjectDescID = 0; + } + new_obj_pos++; + } + } + uNumSpriteObjects = new_obj_pos; +} +//----- (00408896) -------------------------------------------------------- +void SpriteObject::InitializeSpriteObjects() +{ + for (uint i = 0; i < uNumSpriteObjects; ++i) + { + SpriteObject* item = &pSpriteObjects[i]; + + if (item->uType && (item->uSoundID & 8 || pObjectList->pObjects[item->uType].uFlags & OBJECT_DESC_UNPICKABLE)) + SpriteObject::OnInteraction(i); + } +} +//----- (0046BEF1) -------------------------------------------------------- +void SpriteObject::_46BEF1_apply_spells_aoe() +{ + //SpriteObject *v1; // edi@1 + //Actor *v2; // esi@2 + //__int16 v3; // fps@4 + //unsigned __int8 v4; // c0@4 + //unsigned __int8 v5; // c3@4 + //signed int v6; // [sp+8h] [bp-4h]@1 + + int v7,v9,v10,v11; + __debugbreak();//Ritor1 + if ( (signed int)uNumActors > 0 ) + { + for ( uint i = 0; i < uNumActors; ++i ) + { + if ( pActors[i].CanAct() ) + { + //UNDEF(v3); + //.text:0046BF26 movsx eax, word ptr [esi-2] + //.text:0046BF2A sub eax, [edi+4] + //.text:0046BF31 mov [ebp+var_8], eax + //.text:0046BF37 fild [ebp+var_8] + // v7 pushed to stack + v7 = pActors[i].vPosition.x - this->vPosition.x; + + //.text:0046BF2D movsx ecx, word ptr [esi+2] + //v8 = pActors[i].vPosition.z; + + //.text:0046BF34 movsx eax, word ptr [esi] + //.text:0046BF3A sub eax, [edi+8] + //.text:0046BF3D mov [ebp+var_8], eax + //.text:0046BF44 fild [ebp+var_8] + // v9 pushed to stack + v9 = pActors[i].vPosition.y - this->vPosition.y; + + //.text:0046BF40 movsx eax, word ptr [esi-6] + //.text:0046BF47 sar eax, 1 + //.text:0046BF49 add eax, ecx + //.text:0046BF4B sub eax, [edi+0Ch] + //.text:0046BF4E mov [ebp+var_8], eax + //.text:0046BF51 fild [ebp+var_8] + //.text:0046BF58 fld st + // v10 pushed to stack, two times + v10 = pActors[i].uActorHeight / 2 + pActors[i].vPosition.z - this->vVelocity.y; + + //.text:0046BF54 movsx eax, word ptr [esi-8] + //.text:0046BF5A add eax, 100h + //.text:0046BF63 mov ecx, eax + //v11 = this->vVelocity.x; + + //.text:0046BF5F fmul st, st(1) + // stack: v10*v10, v10, v9, v7 + //.text:0046BF61 fld st(2) + // stack: v7, v10*v10, v10, v9, v7 + + + //.text:0046BF65 fmul st, st(3) + // stack: v7*v9, v10*v10, v10, v9, v7 + + //.text:0046BF67 imul ecx, eax + v11 = this->vVelocity.x * this->vVelocity.x; + + //.text:0046BF6A faddp st(1), st + // stack: v10*v10+v7*v9, v10, v9, v7 + //.text:0046BF6C fld st(3) + // stack: v7, v10*v10+v7*v9, v10, v9, v7 + //.text:0046BF6E fmul st, st(4) + // stack: v7*v7, v10*v10+v7*v9, v10, v9, v7 + //.text:0046BF70 faddp st(1), st + // stack: v10*v10+v7*v9+v7*v7, v10, v9, v7 + + //.text:0046BF72 mov [ebp+var_8], ecx + //.text:0046BF75 fild [ebp+var_8] + // v11 pushed to stack + + //.text:0046BF78 fcompp + // if ( v11 > v10*v10+v7*v9+v7*v7 ) + // stack: v10, v9, v7 + + //.text:0046BF7A fstp st + // stack: v9, v7 + + //.text:0046BF7C fnstsw ax + //.text:0046BF7E fstp st + // stack: v7 + + //.text:0046BF80 test ah, 41h + //.text:0046BF83 fstp st + //.text:0046BF85 jnz short loc_46BFDD + + if ( v11 >= v7 * v7 + v9 * v9 + v10 * v10 ) + { + if ( pActors[i].DoesDmgTypeDoDamage((DAMAGE_TYPE)0xAu) ) + { + pActors[i].pActorBuffs[this->spell_id].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(this->spell_level << 7) * 0.033333335), + this->spell_skill, 4, 0, 0); + HIWORD(pActors[i].uAttributes) |= 8; + } + } + } + } + } +} + + +//----- (0042F7EB) -------------------------------------------------------- +bool SpriteObject::sub_42F7EB_DropItemAt(unsigned int uSpriteID, int x, int y, int z, int a4, int count, int a7, unsigned __int16 attributes, ItemGen *a9) +{ + unsigned __int16 pObjectDescID; // ax@7 + SpriteObject pSpellObject; // [sp+Ch] [bp-78h]@1 + + pSpellObject.stru_24.Reset(); + if ( a9 ) + memcpy(&pSpellObject.stru_24, a9, sizeof(pSpellObject.stru_24)); + pSpellObject.spell_skill = 0; + pSpellObject.spell_level = 0; + pSpellObject.spell_id = 0; + pSpellObject.field_54 = 0; + pSpellObject.uType = uSpriteID; + pObjectDescID = 0; + for ( uint i = 0; i < (signed int)pObjectList->uNumObjects; ++i ) + { + if ( (short)uSpriteID == pObjectList->pObjects[i].uObjectID ) + pObjectDescID = i; + } + pSpellObject.uObjectDescID = pObjectDescID; + pSpellObject.vPosition.x = x; + pSpellObject.vPosition.y = y; + pSpellObject.vPosition.z = z; + pSpellObject.uSoundID = 0; + pSpellObject.uAttributes = attributes; + pSpellObject.uSectorID = pIndoor->GetSector(x, y, z); + pSpellObject.uSpriteFrameID = 0; + pSpellObject.spell_caster_pid = 0; + pSpellObject.spell_target_pid = 0; + if ( !(pSpellObject.uAttributes & 0x10) ) + { + if ( pItemsTable->uAllItemsCount ) + { + for ( uint i = 1; i < pItemsTable->uAllItemsCount; ++i ) + { + if ( pItemsTable->pItems[i].uSpriteID == uSpriteID ) + pSpellObject.stru_24.uItemID = i; + } + } + } + if ( a7 ) + { + if ( count > 0 ) + { + for ( uint i = count; i; --i ) + { + pSpellObject.uFacing = rand() % (signed int)stru_5C6E00->uIntegerDoublePi; + pSpellObject.Create((signed __int16)pSpellObject.uFacing, + ((signed int)stru_5C6E00->uIntegerHalfPi / 2) + (rand() % ((signed int)stru_5C6E00->uIntegerHalfPi / 2)), a4, 0); + + } + } + } + else + { + pSpellObject.uFacing = 0; + if ( count > 0 ) + { + for ( uint i = count; i; --i ) + { + pSpellObject.Create((signed __int16)pSpellObject.uFacing, stru_5C6E00->uIntegerHalfPi, a4, 0); + } + } + } + return true; +} + +//----- (0042F960) -------------------------------------------------------- +void SpriteObject::sub_42F960_create_object(int x, int y, int z) +{ + unsigned __int16 v7; // ax@5 + signed int v8; // eax@6 + signed int v9; // eax@7 + + SpriteObject a1; // [sp+Ch] [bp-70h]@1 + //SpriteObject::SpriteObject(&a1); + a1.stru_24.Reset(); + + a1.spell_skill = 0; + a1.spell_level = 0; + a1.spell_id = 0; + a1.field_54 = 0; + a1.uType = 800; + v7 = 0; + for ( uint i = 0; i < (signed int)pObjectList->uNumObjects; ++i ) + { + if ( a1.uType == pObjectList->pObjects[i].uObjectID ) + v7 = i; + } + a1.uObjectDescID = v7; + a1.vPosition.x = x; + a1.vPosition.y = y; + a1.vPosition.z = z; + a1.uSoundID = 0; + a1.uAttributes = 0; + a1.uSectorID = pIndoor->GetSector(x, y, z); + a1.uSpriteFrameID = 0; + a1.spell_caster_pid = 0; + a1.spell_target_pid = 0; + v8 = a1.Create(0, 0, 0, 0); + if ( v8 != -1 ) + { + v9 = 8 * v8; + LOBYTE(v9) = v9 | 2; + pAudioPlayer->PlaySound((SoundID)(SOUND_GoldReceived|0x14), v9, 0, -1, 0, 0, 0, 0); + } +} + +//----- (0046BFFA) -------------------------------------------------------- +bool __fastcall _46BFFA_check_object_intercept(unsigned int uLayingItemID, signed int a2) +{ + ObjectDesc *object; // ebx@1 + unsigned int v8; // eax@19 + signed int v10; // ebx@19 + char *v11; // edx@20 + unsigned __int16 v12; // ax@23 + int v13; // eax@27 + int v16; // eax@36 + __int16 v18; // di@37 + signed int v19; // edx@37 + unsigned __int16 v22; // ax@41 + signed int v24; // ebx@46 + char *v25; // edx@47 + signed int v34; // edx@65 + unsigned __int16 v36; // ax@69 + int v37; // ST14_4@72 + int v38; // eax@72 + int v39; // ST10_4@72 + int v40; // ST0C_4@72 + unsigned __int8 v44; // zf@79 + int v47; // eax@81 + signed int v52; // ebx@93 + signed int v56; // ebx@98 + unsigned __int16 v58; // ax@102 + unsigned __int16 v59; // ax@107 + signed int v61; // ebx@107 + unsigned __int16 v63; // ax@111 + int v64; // ebx@114 + signed int v65; // eax@114 + signed int v69; // ebx@124 + unsigned __int16 v71; // ax@128 + unsigned int v72; // ebx@131 + int v78; // eax@133 + signed int v81; // edx@140 + unsigned __int16 v83; // ax@144 + signed int v86; // ebx@151 + unsigned __int16 v88; // ax@155 + unsigned int v89; // eax@158 + int v90; // ST34_4@159 + int v91; // eax@159 + unsigned int v92; // eax@163 + unsigned __int16 v95; // ax@181 + unsigned __int16 v96; // ax@184 + int v97; // eax@185 + char v100; // ST18_1@198 + int v102; // eax@198 + signed int v106; // eax@208 + unsigned int v107; // edx@220 + signed int v108; // ebx@225 + signed int v110; // ebx@234 + unsigned __int16 v112; // ax@238 + unsigned __int16 v113; // si@241 + int v114; // eax@242 + int v115; // eax@245 + signed int v119; // ebx@251 + unsigned __int16 v121; // ax@255 + int v124; // eax@267 + int v125; // [sp-20h] [bp-4Ch]@28 + char v132; // [sp-8h] [bp-34h]@131 + char v134; // [sp-4h] [bp-30h]@131 + signed int v135; // [sp-4h] [bp-30h]@217 + int v136; // [sp+Ch] [bp-20h]@208 + int v137; // [sp+10h] [bp-1Ch]@208 + signed int v138; // [sp+14h] [bp-18h]@207 + signed int v139; // [sp+18h] [bp-14h]@208 + signed int v141; // [sp+1Ch] [bp-10h]@117 + unsigned int v142; // [sp+1Ch] [bp-10h]@158 + signed int v143; // [sp+1Ch] [bp-10h]@172 + signed int v146; // [sp+20h] [bp-Ch]@60 + int v147; // [sp+20h] [bp-Ch]@72 + signed int v148; // [sp+20h] [bp-Ch]@158 + unsigned __int16 v150; // [sp+20h] [bp-Ch]@208 + signed int v152; // [sp+24h] [bp-8h]@208 + + object = &pObjectList->pObjects[pSpriteObjects[uLayingItemID].uObjectDescID]; + //v151 = PID_TYPE(a2); + if (PID_TYPE(a2) == OBJECT_Actor) + { + if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Actor + && !pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].GetActorsRelation(&pActors[PID_ID(a2)])) + return 1; + } + else + { + if (PID_TYPE(a2) == OBJECT_Player && PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Player) + return 1; + } + if (pParty->bTurnBasedModeOn == 1) + { + if (pSpriteObjects[uLayingItemID].uAttributes & 4) + { + --pTurnEngine->pending_actions; + pSpriteObjects[uLayingItemID].uAttributes &= 0xFFFB;//~0x00000004 + } + } + if (PID_TYPE(a2) == OBJECT_BModel && PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) != OBJECT_Player) + { + if (PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) < 500) //bugfix PID_ID(v2->spell_caster_pid)==1000 + pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].uAttributes |= ACTOR_UNKNOW5; + } + + //v6 = v2->uType; + //v7 = v2->uType; + + switch (pSpriteObjects[uLayingItemID].uType) + { + + case 1060: + case 2030: + case 9010: + { + //v9 = 0; + if (PID_TYPE(a2) == 6 || PID_TYPE(a2) == 5 || !PID_TYPE(a2)) + return 1; + if (PID_TYPE(a2) != 2) + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v95 = 0; + for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) + v95 = v52; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!pSpriteObjects[uLayingItemID].uSoundID) + v97 = 0; + else + v97 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); + return 0; + } + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; + v121 = 0; + for (v119 = 0; v119 < (signed int)pObjectList->uNumObjects; ++v119) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v119].uObjectID) + v121 = v119; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v121; + if (!v121) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v13 = 8 * uLayingItemID; + LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); + pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); + return 0; + } + + + case 500: + case 505: + case 510: + case 515: + case 520: + case 525: + case 530: + case 535: + case 540: + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v12 = 0; + for (v10 = 0; v10 < (signed int)pObjectList->uNumObjects; ++v10) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v10].uObjectID) + v12 = v10; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v12; + if (!v12) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (pSpriteObjects[uLayingItemID].uType == 555) + { + v13 = 8 * uLayingItemID; + LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); + pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); + } + return 0; + } + + case 545: + case 550: + { + if (pSpriteObjects[uLayingItemID].stru_24.uItemID != 405 && pSpriteObjects[uLayingItemID].stru_24.uSpecEnchantmentType != 3) + { + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + sub_43A97E(uLayingItemID, a2); + SpriteObject::OnInteraction(uLayingItemID); + if (pSpriteObjects[uLayingItemID].uSoundID == 0) + v16 = 0; + else + v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); + return 0; + } + v18 = 0; + pSpriteObjects[uLayingItemID].uType = 600; + v22 = 0; + for (v19 = 0; v19 < (signed int)pObjectList->uNumObjects; ++v19) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v19].uObjectID) + v22 = v19; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v22; + if (!v22) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = v18; + pSpriteObjects[uLayingItemID].vVelocity.y = v18; + pSpriteObjects[uLayingItemID].vVelocity.x = v18; + pSpriteObjects[uLayingItemID].uSpriteFrameID = v18; + v12 = 0; + for (v10; v10 < (signed int)v8; ++v10) + { + v11 += 56; + if (pSpriteObjects[uLayingItemID].uType != *(short *)v11) + v12 = v10; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v12; + if (!v12) + SpriteObject::OnInteraction(uLayingItemID); + v44 = pSpriteObjects[uLayingItemID].uType == 555; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!v44) + { + v13 = 8 * uLayingItemID; + LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); + pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); + return 0; + } + return 0; + } + + case 600: + { + pSpriteObjects[uLayingItemID].uType = 601; + v36 = 0; + for (v34 = 0; v34 < (signed int)pObjectList->uNumObjects; ++v34) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v34].uObjectID) + v36 = v34; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v36; + if (!v36) + SpriteObject::OnInteraction(uLayingItemID); + v37 = pSpriteObjects[uLayingItemID].vPosition.z; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + v38 = 8 * uLayingItemID; + v39 = pSpriteObjects[uLayingItemID].vPosition.y; + LOBYTE(v38) = PID(OBJECT_Item, uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + v40 = pSpriteObjects[uLayingItemID].vPosition.x; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v147 = v38; + AttackerInfo.Add(v38, 512, v40, v39, v37, 0, 0); + if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); + pAudioPlayer->PlaySound(SOUND_8, v147, 0, -1, 0, 0, 0, 0); + return 0; + } + + case 1010: + case 1100: + case 2060: + case 3010: + case 3030: + case 3060: + case 4000: + case 4030: + case 4050: + case 4100: + case 6010: + case 6090: + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v95 = 0; + for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) + v95 = v52; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + v96 = pSpriteObjects[uLayingItemID].uSoundID; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!v96) + v97 = 0; + else + v97 = (signed __int16)v96 + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); + return 0; + } + + + case 555: + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v18 = 0; + v22 = 0; + v25 = (char *)&pObjectList->pObjects->uObjectID; + for (v24 = 0; v24 < (signed int)pObjectList->uNumObjects; ++v24) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v24].uObjectID) + v22 = v24; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v22; + if (v22 == v18) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = v18; + pSpriteObjects[uLayingItemID].vVelocity.y = v18; + pSpriteObjects[uLayingItemID].vVelocity.x = v18; + pSpriteObjects[uLayingItemID].uSpriteFrameID = v18; + return 0; + } + + case 3090: + { + //v9 = 0; + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 2; + v63 = 0; + for (v61 = 0; v61 < (signed int)pObjectList->uNumObjects; ++v61) + { + if (v59 == pObjectList->pObjects[v61].uObjectID) + v63 = v61; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v63; + if (!v63) + SpriteObject::OnInteraction(uLayingItemID); + v64 = pSpriteObjects[uLayingItemID].uFacing - stru_5C6E00->uIntegerDoublePi; + v44 = pSpriteObjects[uLayingItemID].spell_skill == 4; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + v65 = 7; + if (v44) + v65 = 9; + if (v65 > 0) + { + v141 = v65; + do + { + v64 += (signed int)stru_5C6E00->uIntegerHalfPi / 2; + pSpriteObjects[uLayingItemID].Create(v64, 0, 1000, 0); + --v141; + } while (v141); + } + SpriteObject::OnInteraction(uLayingItemID); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v16 = 0; + else + v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); + return 0; + } + + case 3092: + { + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType - 1; + v58 = 0; + for (v56 = 0; v56 < (signed int)pObjectList->uNumObjects; ++v56) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v56].uObjectID) + v58 = v56; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v58; + if (!v58) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + sub_43A97E(uLayingItemID, a2); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v16 = 0; + else + v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); + return 0; + } + + case 4070: + { + if (PID_TYPE(a2) == 6 || PID_TYPE(a2) == 5 || !PID_TYPE(a2)) + return 1; + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; + v71 = 0; + for (v69 = 0; v69 < (signed int)pObjectList->uNumObjects; ++v69) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v69].uObjectID) + v71 = v69; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v71; + if (!v71) + SpriteObject::OnInteraction(uLayingItemID); + v134 = 0; + v72 = uLayingItemID; + v132 = 0; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + AttackerInfo.Add(PID(OBJECT_Item, v72), 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v132, v134); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v78 = 0; + else + v78 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, pSpriteObjects[uLayingItemID].vPosition.x, 0, -1, 0, v78, 0, 0); + return 0; + } + + case 4090: + { + //v9 = 0; + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 2; + v88 = 0; + for (v86 = 0; v86 < (signed int)pObjectList->uNumObjects; ++v86) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v86].uObjectID) + v88 = v86; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v88; + if (!v88) + SpriteObject::OnInteraction(uLayingItemID); + v89 = pSpriteObjects[uLayingItemID].uFacing - stru_5C6E00->uIntegerDoublePi; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + v142 = v89; + v148 = 7; + do + { + pRnd->SetRange(-128, 128); + v90 = pRnd->GetInRange(); + pRnd->SetRange(5, 500); + v91 = pRnd->GetInRange(); + v142 += (signed int)stru_5C6E00->uIntegerHalfPi >> 1; + pSpriteObjects[uLayingItemID].Create(v90 + v142, 0, v91, 0); + --v148; + } while (v148); + SpriteObject::OnInteraction(uLayingItemID); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v16 = 0; + else + v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); + return 0; + } + + case 4092: + { + pSpriteObjects[uLayingItemID].uType = 4091; + v83 = 0; + for (v81 = 0; v81 < (signed int)pObjectList->uNumObjects; ++v81) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v81].uObjectID) + v83 = v81; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v83; + if (!v83) + SpriteObject::OnInteraction(uLayingItemID); + v134 = 0; + //v72 = uLayingItemID; + v132 = pSpriteObjects[uLayingItemID].field_61; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + AttackerInfo.Add(PID(OBJECT_Item, uLayingItemID), 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v132, v134); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v78 = 0; + else + v78 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, pSpriteObjects[uLayingItemID].vPosition.x, 0, -1, 0, v78, 0, 0); + return 0; + } + + case 8010: + { + if (PID_TYPE(a2) == 3 + && MonsterStats::BelongsToSupertype(pActors[PID_ID(a2)].pMonsterInfo.uID, MONSTER_SUPERTYPE_UNDEAD)) + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + //v9 = 0; + v95 = 0; + for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) + v95 = v52; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + v96 = pSpriteObjects[uLayingItemID].uSoundID; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!v96) + v97 = 0; + else + v97 = (signed __int16)v96 + 4; + v92 = uLayingItemID; + v124 = 8 * v92; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); + return 0; + } + + case 7030: + case 7090: + case 8000: + case 8090: + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v95 = 0; + for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) + v95 = v52; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + v96 = pSpriteObjects[uLayingItemID].uSoundID; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!v96) + v97 = 0; + else + v97 = (signed __int16)v96 + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); + return 0; + } + + case 6040: + case 8030: + case 9030: + { + v143 = 17030; + switch (pSpriteObjects[uLayingItemID].uType) + { + case 0x1798u: + v143 = 15040; + break; + case 0xFAAu: + v143 = 13010; + break; + case 0x2346u: + v143 = 18030; + break; + } + v138 = 1; + if (PID_TYPE(a2) != OBJECT_Actor) + { + if (pSpriteObjects[uLayingItemID].uType != 9030 || pSpriteObjects[uLayingItemID].spell_skill != 4) + { + SpriteObject::OnInteraction(uLayingItemID); + return 0; + } + pSpriteObjects[uLayingItemID]._46BEF1_apply_spells_aoe(); + if (!v138) + { + ++pSpriteObjects[uLayingItemID].uType; + v112 = 0; + for (v110 = 0; v110 < (signed int)pObjectList->uNumObjects; ++v110) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v110].uObjectID) + v112 = v110; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v112; + if (!v112) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v113 = pSpriteObjects[uLayingItemID].uSoundID; + if (v113) + v114 = (signed __int16)v113 + 4; + else + v114 = 0; + v115 = 8 * uLayingItemID; + LOBYTE(v115) = PID(OBJECT_Item, uLayingItemID); + v125 = v143 + 1; + pAudioPlayer->PlaySound((SoundID)v125, v115, 0, -1, 0, v114, 0, 0); + } + else + SpriteObject::OnInteraction(uLayingItemID); + return 0; + } + v106 = a2; + v150 = 0; + v139 = PID_ID(v106); + v137 = pSpriteObjects[uLayingItemID].spell_level; + v152 = pSpriteObjects[uLayingItemID].spell_skill; + v136 = pSpriteObjects[uLayingItemID].spell_id; + if (pSpriteObjects[uLayingItemID].uType == 9030) + { + v150 = 2; + if (v152 == 2) + v150 = 3; + else + { + if (v152 >= 3) + v150 = 4; + } + pActors[v139].uAttributes |= ACTOR_AGGRESSOR; + v107 = v135; + } + if (pSpriteObjects[uLayingItemID].uType == 6040) + { + v135 = 7; + v107 = v135; + } + else + { + if (pSpriteObjects[uLayingItemID].uType == 8030) + { + v135 = 9; + v107 = v135; + } + else + { + if (pSpriteObjects[uLayingItemID].uType != 9030) + { + v107 = v136; + } + if (pSpriteObjects[uLayingItemID].uType == 9030) + { + v135 = 10; + v107 = v135; + } + } + } + if (pSpriteObjects[uLayingItemID].uType != 9030 || v152 != 4) + { + v108 = v139; + if (pActors[v139].DoesDmgTypeDoDamage((DAMAGE_TYPE)v107)) + { + v138 = 0; + if (pSpriteObjects[uLayingItemID].uType == 8030) + { + pActors[v108].uAIState = Standing; + pActors[v108].UpdateAnimation(); + } + pActors[v108].pActorBuffs[v136].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(v137 << 7) * 0.033333335), + v152, v150, 0, 0); + } + } + else + { + pSpriteObjects[uLayingItemID]._46BEF1_apply_spells_aoe(); + } + pSpriteObjects[uLayingItemID].spell_level = 0; + pSpriteObjects[uLayingItemID].spell_skill = 0; + pSpriteObjects[uLayingItemID].spell_id = 0; + if (!v138) + { + ++pSpriteObjects[uLayingItemID].uType; + v112 = 0; + for (v110 = 0; v110 < (signed int)pObjectList->uNumObjects; ++v110) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v110].uObjectID) + v112 = v110; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v112; + if (!v112) + SpriteObject::OnInteraction(uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v113 = pSpriteObjects[uLayingItemID].uSoundID; + if (v113) + v114 = (signed __int16)v113 + 4; + else + v114 = 0; + v115 = 8 * uLayingItemID; + LOBYTE(v115) = PID(OBJECT_Item, uLayingItemID); + v125 = v143 + 1; + pAudioPlayer->PlaySound((SoundID)v125, v115, 0, -1, 0, v114, 0, 0); + } + else + SpriteObject::OnInteraction(uLayingItemID); + return 0; + } + + case 9040: + { + sub_43A97E(uLayingItemID, a2); + ++pSpriteObjects[uLayingItemID].uType; + v95 = 0; + for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) + v95 = v52; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + v96 = pSpriteObjects[uLayingItemID].uSoundID; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + if (!v96) + v97 = 0; + else + v97 = (signed __int16)v96 + 4; + v124 = 8 * uLayingItemID; + LOBYTE(v124) = v124 | 2; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); + return 0; + } + + /* + case 1080: + case 2100: + { + if (PID_TYPE(a2) != 3) + { + //v32 = 0; + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; + v46 = 0; + for (v146 = 0; v146 < (signed int)pObjectList->uNumObjects; ++v146) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v146].uObjectID) + v46 = v146; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v46; + if (!v46) + SpriteObject::OnInteraction(uLayingItemID); + v100 = pSpriteObjects[uLayingItemID].field_61; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v102 = 8 * uLayingItemID; + LOBYTE(v102) = PID(OBJECT_Item, uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + AttackerInfo.Add(v102, 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v100, 0); + if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v47 = 0; + else + v47 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v102, 0, -1, 0, v47, 0, 0); + return 0; + } + return 1; + }*/ + + case 1080: + case 2100: + { + if (PID_TYPE(a2) == 3) + return 1; + //else go to next case + } + + case 1050: + case 9080: + { + v95 = 0; + pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; + for (v146 = 0; v146 < (signed int)pObjectList->uNumObjects; ++v146) + { + if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v146].uObjectID) + v95 = v146; + } + pSpriteObjects[uLayingItemID].uObjectDescID = v95; + if (!v95) + SpriteObject::OnInteraction(uLayingItemID); + v100 = pSpriteObjects[uLayingItemID].field_61; + pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; + v102 = 8 * uLayingItemID; + LOBYTE(v102) = PID(OBJECT_Item, uLayingItemID); + pSpriteObjects[uLayingItemID].vVelocity.x = 0; + pSpriteObjects[uLayingItemID].vVelocity.y = 0; + pSpriteObjects[uLayingItemID].vVelocity.z = 0; + AttackerInfo.Add(v102, 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v100, 0); + if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) + trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); + if (!pSpriteObjects[uLayingItemID].uSoundID) + v47 = 0; + else + v47 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; + v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; + pAudioPlayer->PlaySound((SoundID)v125, v102, 0, -1, 0, v47, 0, 0); + return 0; + } + + default: + return 0; + } + +} + +//----- (0043A97E) -------------------------------------------------------- +void __fastcall sub_43A97E(unsigned int uLayingItemID, signed int a2) +{ + if (PID_TYPE(a2) == OBJECT_Player) + { + layingitem_vel_50FDFC.x = pSpriteObjects[uLayingItemID].vVelocity.x; + layingitem_vel_50FDFC.y = pSpriteObjects[uLayingItemID].vVelocity.y; + layingitem_vel_50FDFC.z = pSpriteObjects[uLayingItemID].vVelocity.z; + + Vec3_int_::Normalize(&layingitem_vel_50FDFC.x, &layingitem_vel_50FDFC.y, &layingitem_vel_50FDFC.z); + DamagePlayerFromMonster(PID(OBJECT_Item, uLayingItemID), pSpriteObjects[uLayingItemID].field_61, &layingitem_vel_50FDFC, -1); + } + else if (PID_TYPE(a2) == OBJECT_Actor) + { + layingitem_vel_50FDFC.x = pSpriteObjects[uLayingItemID].vVelocity.x; + layingitem_vel_50FDFC.y = pSpriteObjects[uLayingItemID].vVelocity.y; + layingitem_vel_50FDFC.z = pSpriteObjects[uLayingItemID].vVelocity.z; + + Vec3_int_::Normalize(&layingitem_vel_50FDFC.x, &layingitem_vel_50FDFC.y, &layingitem_vel_50FDFC.z); + switch (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid)) + { + case OBJECT_Actor: + Actor::ActorDamageFromMonster(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC, pSpriteObjects[uLayingItemID].field_61); + break; + case OBJECT_Player: + Actor::DamageMonsterFromParty(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC); + break; + case OBJECT_Item: + ItemDamageFromActor(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC); + break; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Engine/Objects/SpriteObject.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,62 @@ +#pragma once +#include "Items.h" + +enum +{ + OBJECT_40 = 0x40 + , OBJECT_ATTACHED_TO_ACTOR = 0x80 +}; + +#define MAX_SPRITE_OBJECTS 1000 +/* 72 */ +#pragma pack(push, 1) +struct SpriteObject +{ + inline bool AttachedToActor() const {return (uAttributes & OBJECT_ATTACHED_TO_ACTOR) != 0;} + + SpriteObject(); + int Create(int yaw, int pitch, int a4, int a5); + void _46BEF1_apply_spells_aoe(); + void ExplosionTraps(); + + static void UpdateObject_fn0_BLV(unsigned int uLayingItemID); + static void UpdateObject_fn0_ODM(unsigned int uLayingItemID); + static void OnInteraction(unsigned int uLayingItemID); + static bool sub_42F7EB_DropItemAt(unsigned int uSpriteID, int x, int y, int z, int a4, int count, int a7, unsigned __int16 attributes, ItemGen *a9); + static void sub_42F960_create_object(int x, int y, int z); + static void InitializeSpriteObjects(); + + + unsigned __int16 uType; + unsigned __int16 uObjectDescID; + struct Vec3_int_ vPosition; + struct Vec3_short_ vVelocity; + unsigned __int16 uFacing; + unsigned __int16 uSoundID; + unsigned __int16 uAttributes; + __int16 uSectorID; + unsigned __int16 uSpriteFrameID; + __int16 field_20; + __int16 field_22_glow_radius_multiplier; + struct ItemGen stru_24; + int spell_id; + int spell_level; + int spell_skill; + int field_54; + int spell_caster_pid; + int spell_target_pid; + char field_60_distance_related_prolly_lod; + char field_61; + char field_62[2]; + Vec3_int_ field_64; +}; +#pragma pack(pop) + + +void CompactLayingItemsList(); + +extern size_t uNumSpriteObjects; +extern std::array<SpriteObject, MAX_SPRITE_OBJECTS> pSpriteObjects; + +bool __fastcall _46BFFA_check_object_intercept(unsigned int uLayingItemID, signed int a2); +void __fastcall sub_43A97E(unsigned int uLayingItemID, signed int a2); // idb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Items.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,2286 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include <stdlib.h> +#include <string> +#include "UI\UIHouses.h" +#include "GUIButton.h" + +#include "ErrorHandling.h" + +#include "Items.h" +#include "MapInfo.h" +#include "GUIWindow.h" +#include "Chest.h" +#include "LOD.h" +#include "Monsters.h" +#include "Party.h" +#include "FactionTable.h" +#include "StorylineTextTable.h" +#include "texts.h" +#include "mm7_data.h" +#include "OurMath.h" + + + +struct ITEM_VARIATION + { + unsigned __int16 treasure_level; + unsigned __int16 item_class[4]; + }; + + +std::array<const char, 5> uItemsAmountPerShopType={ 0, 6, 8, 12, 12}; + +const ITEM_VARIATION shopWeap_variation_ord[15] ={ + { 0, { 0, 0, 0, 0 }}, + { 1, { 23, 27, 20, 20 }}, + { 1, { 23, 24, 28, 20 }}, + { 2, { 23, 24, 25, 20 }}, + { 2, { 27, 27, 26, 26 }}, + { 4, { 24, 30, 25, 27 }}, + { 4, { 24, 30, 25, 27 }}, + { 3, { 30, 24, 20, 20 }}, + { 2, { 20, 20, 20, 20 }}, + { 3, { 27, 27, 26, 26 }}, + { 3, { 28, 28, 25, 25 }}, + { 2, { 23, 23, 24, 24 }}, + { 3, { 23, 23, 26, 26 }}, + { 2, { 30, 26, 26, 26 }}, + { 2, { 28, 25, 28, 29 }}}; + +const ITEM_VARIATION shopArmr_variation_ord[28] ={ + { 1, { 35, 35, 38, 38 }}, + { 1, { 31, 31, 31, 34 }}, + { 1, { 35, 35, 38, 38 }}, + { 1, { 31, 31, 32, 34 }}, + { 2, { 35, 35, 38, 38 }}, + { 2, { 31, 32, 32, 33 }}, + { 2, { 35, 35, 38, 38 }}, + { 2, { 31, 31, 32, 32 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 31, 32, 33, 34 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 31, 32, 33, 34 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 31, 31, 31 }}, + { 2, { 35, 35, 38, 38 }}, + { 2, { 31, 32, 34, 34 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 31, 32, 32 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 32, 32, 32, 33 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 31, 31, 32 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 33, 31, 32, 34 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 33, 31, 32, 34 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 33, 31, 32, 34 }}}; + + + +const unsigned __int16 shopMagic_treasure_lvl[14]= {0, 1, 1, 2, 2, 4, 4, 3, 2, 2, 2, 2, 2, 2}; +const unsigned __int16 shopAlch_treasure_lvl[13] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 2, 2, 2, 2}; + +const ITEM_VARIATION shopWeap_variation_spc[15]={ + { 0, { 0, 0, 0, 0 }}, + { 2, { 25, 30, 20, 20}}, + { 2, { 23, 24, 28, 20}}, + { 3, { 23, 24, 25, 20}}, + { 3, { 27, 27, 26, 26}}, + { 5, { 23, 26, 28, 27}}, + { 5, { 23, 26, 28, 27}}, + { 4, { 30, 24, 20, 20}}, + { 3, { 20, 20, 20, 20}}, + { 4, { 27, 27, 26, 26}}, + { 4, { 28, 28, 25, 25}}, + { 4, { 23, 23, 24, 24}}, + { 4, { 24, 24, 27, 20}}, + { 4, { 30, 26, 26, 26}}, + { 4, { 28, 25, 28, 29}}}; + +const ITEM_VARIATION shopArmr_variation_spc[28]={ + { 2, { 35, 35, 38, 38 }}, + { 2, { 31, 31, 31, 34 }}, + { 2, { 35, 35, 38, 38 }}, + { 2, { 31, 31, 32, 34 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 32, 32, 33 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 31, 32, 32 }}, + { 5, { 35, 35, 38, 38 }}, + { 5, { 31, 32, 33, 34 }}, + { 5, { 35, 35, 38, 38 }}, + { 5, { 31, 32, 33, 34 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 31, 31, 31, 31 }}, + { 3, { 35, 35, 38, 38 }}, + { 3, { 31, 32, 34, 34 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 31, 31, 32, 33 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 32, 32, 33, 34 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 31, 31, 31, 32 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 32, 32, 32, 32 }}, + { 4, { 35, 35, 38, 38 }}, + { 4, { 34, 34, 34, 34 }}, + { 5, { 35, 35, 38, 38 }}, + { 5, { 33, 33, 33, 33 }} + }; + +const unsigned __int16 shopMagicSpc_treasure_lvl[14] = {0, 2, 2, 3, 3, 5, 5, 4, 3, 3, 3, 3, 3, 3}; +const unsigned __int16 shopAlchSpc_treasure_lvl[13] = {0, 2, 2, 3, 3, 4, 4, 5, 5, 3, 2, 2, 2}; + + +std::array< std::array<char, 14>, 7> byte_4E8168={{ //byte_4E8178 + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + { 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + { 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4}, + { 2, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5}, + { 2, 2, 2, 2, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6}, + { 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}}}; + +int sub_4BE571_AddItemToSet(int valueToAdd, int *outPutSet, int elemsAlreadyPresent, int elemsNeeded); +int dword_F8B1DC_currentShopOption; // weak + +ItemGen *ptr_50C9A4_ItemToEnchant; + +struct ItemsTable *pItemsTable; // 005D29E0 + + + + + +//----- (00439DF3) -------------------------------------------------------- +int ItemGen::_439DF3_get_additional_damage(int *damage_type, bool *draintargetHP) + { + *draintargetHP = false; + *damage_type = 0; + if ( !uItemID ) + return 0; + UpdateTempBonus(pParty->uTimePlayed); + if (uItemID == 501 ) //Iron Feather -sword + { + *damage_type = 1; + return rand() % 10 + 6; + } + if (uItemID == 507 ) //Ghoulsbane -axe + { + *damage_type = 0; + return rand() % 16 + 3; + } + if ( uItemID == 510 ) //Ullyses -bow + { + *damage_type = 2; + return rand() % 4 + 9; + } + if ( uItemID == 517 ) //Old Nick -dagger + { + *damage_type = 8; + return 8; + } + + switch (uSpecEnchantmentType) + { + case 4: //Adds 3-4 points of Cold damage. + *damage_type = 2; + return rand() % 2 + 3; + break; + case 5: //Adds 6-8 points of Cold damage. + *damage_type = 2; + return rand() % 3 + 6; + break; + case 6: //Adds 9-12 points of Cold damage. + *damage_type = 2; + return rand() % 4 + 9; + break; + case 7: //Adds 2-5 points of Electrical damage. + *damage_type = 1; + return rand() % 4 + 2; + break; + case 8: //Adds 4-10 points of Electrical damage. + *damage_type = 1; + return rand() % 7 + 4; + break; + case 9: //Adds 6-15 points of Electrical damage. + *damage_type = 1; + return rand() % 10 + 6; + break; + case 10: //Adds 1-6 points of Fire damage. + *damage_type = 0; + return GetDiceResult(1, 6); + break; + case 11: //Adds 2-12 points of Fire damage. + *damage_type = 0; + return GetDiceResult(2, 6); + break; + case 12: //Adds 3-18 points of Fire damage. + *damage_type = 0; + return GetDiceResult(3, 6); + break; + case 13: //Adds 5 points of Body damage. + *damage_type = 8; + return 5; + break; + case 14: //Adds 8 points of Body damage. + *damage_type = 8; + return 8; + break; + case 15: //Adds 12 points of Body damage. + *damage_type = 8; + return 12; + break; + case 16: //Drain Hit Points from target. + case 41: //Drain Hit Points from target and Increased Weapon speed. + *damage_type = 10; + *draintargetHP = true; + return 0; + break; + case 46: //Adds 10-20 points of Fire damage and +25 Might. + *damage_type = 0; + return rand() % 11 + 10; + break; + default: + *damage_type = 0; + return 0; + + } + + } + + +//----- (00402F07) -------------------------------------------------------- +void ItemGen::Reset() +{ + this->uHolderPlayer = 0; + this->uAttributes = 0; + this->uNumCharges = 0; + this->uSpecEnchantmentType = 0; + this->m_enchantmentStrength = 0; + this->uEnchantmentType = 0; + this->uItemID = 0; + this->uBodyAnchor = 0; + this->uExpireTime = 0i64; +} + +//----- (00458260) -------------------------------------------------------- +void ItemGen::UpdateTempBonus(__int64 uTimePlayed) +{ + if ( this->uAttributes & ITEM_TEMP_BONUS ) + { + if ( uTimePlayed > (signed __int64)this->uExpireTime ) + { + this->uEnchantmentType = 0; + this->uSpecEnchantmentType = 0; + this->uAttributes = this->uAttributes&(~ITEM_TEMP_BONUS); + } + } +} + +//----- (0045814E) -------------------------------------------------------- +void ItemsTable::Release() +{ + free(pMonstersTXT_Raw); + free(pMonsterPlacementTXT_Raw); + free(pSkillDescTXT_Raw); + free(pSpcItemsTXT_Raw); + free(pStdItemsTXT_Raw); + free(pRndItemsTXT_Raw); + free(pItemsTXT_Raw); + free(pHostileTXT_Raw); + free(pHistoryTXT_Raw); + free(pPotionsTXT_Raw); + free(pPotionNotesTXT_Raw); + pMonstersTXT_Raw = nullptr; + pMonsterPlacementTXT_Raw = nullptr; + pSpcItemsTXT_Raw = nullptr; + pSkillDescTXT_Raw = nullptr; + pStdItemsTXT_Raw = nullptr; + pRndItemsTXT_Raw = nullptr; + pItemsTXT_Raw = nullptr; + pHostileTXT_Raw = nullptr; + pHistoryTXT_Raw = nullptr; + pPotionsTXT_Raw = nullptr; + pPotionNotesTXT_Raw = nullptr; +} + + +//----- (00456D84) -------------------------------------------------------- +void ItemsTable::Initialize() +{ + std::map<std::string, ITEM_EQUIP_TYPE, ci_less> equipStatMap; + equipStatMap["weapon"] = EQUIP_SINGLE_HANDED; + equipStatMap["weapon2"] = EQUIP_TWO_HANDED; + equipStatMap["weapon1or2"] = EQUIP_SINGLE_HANDED; + equipStatMap["missile"] = EQUIP_BOW; + equipStatMap["bow"] = EQUIP_BOW; + equipStatMap["armor"] = EQUIP_ARMOUR; + equipStatMap["shield"] = EQUIP_SHIELD; + equipStatMap["helm"] = EQUIP_HELMET; + equipStatMap["belt"] = EQUIP_BELT; + equipStatMap["cloak"] = EQUIP_CLOAK; + equipStatMap["gauntlets"] = EQUIP_GAUNTLETS; + equipStatMap["boots"] = EQUIP_BOOTS; + equipStatMap["ring"] = EQUIP_RING; + equipStatMap["amulet"] = EQUIP_AMULET; + equipStatMap["weaponw"] = EQUIP_WAND; + equipStatMap["herb"] = EQUIP_REAGENT; + equipStatMap["reagent"] = EQUIP_REAGENT; + equipStatMap["bottle"] = EQUIP_POTION; + equipStatMap["sscroll"] = EQUIP_SPELL_SCROLL; + equipStatMap["book"] = EQUIP_BOOK; + equipStatMap["mscroll"] = EQUIP_MESSAGE_SCROLL; + equipStatMap["gold"] = EQUIP_GOLD; + equipStatMap["gem"] = EQUIP_GEM; + + std::map<std::string, PLAYER_SKILL_TYPE, ci_less> equipSkillMap; + equipSkillMap["staff"] = PLAYER_SKILL_STAFF; + equipSkillMap["sword"] = PLAYER_SKILL_SWORD; + equipSkillMap["dagger"] = PLAYER_SKILL_DAGGER; + equipSkillMap["axe"] = PLAYER_SKILL_AXE; + equipSkillMap["spear"] = PLAYER_SKILL_SPEAR; + equipSkillMap["bow"] = PLAYER_SKILL_BOW; + equipSkillMap["mace"] = PLAYER_SKILL_MACE; + equipSkillMap["blaster"] = PLAYER_SKILL_BLASTER; + equipSkillMap["shield"] = PLAYER_SKILL_SHIELD; + equipSkillMap["leather"] = PLAYER_SKILL_LEATHER; + equipSkillMap["chain"] = PLAYER_SKILL_CHAIN; + equipSkillMap["plate"] = PLAYER_SKILL_PLATE; + equipSkillMap["club"] = PLAYER_SKILL_CLUB; + + std::map<std::string, ITEM_MATERIAL, ci_less> materialMap; + materialMap["artifact"] = MATERIAL_ARTEFACT; + materialMap["relic"] = MATERIAL_RELIC; + materialMap["special"] = MATERIAL_SPECIAL; + + char* test_string; + int item_counter; + + pMapStats = new MapStats; + pMapStats->Initialize(); + + pMonsterStats = new MonsterStats; + pMonsterStats->Initialize(); + pMonsterStats->InitializePlacements(); + + pSpellStats = new SpellStats; + pSpellStats->Initialize(); + + LoadPotions(); + LoadPotionNotes(); + + pFactionTable = new FactionTable; + pFactionTable->Initialize(); + + pStorylineText = new StorylineText; + pStorylineText->Initialize(); + + pStdItemsTXT_Raw = (char *)pEvents_LOD->LoadRaw("stditems.txt", 0); + strtok(pStdItemsTXT_Raw, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + //Standard Bonuses by Group + for (int i=0;i<24;++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + pEnchantments[i].pBonusStat=RemoveQuotes(tokens[0]); + pEnchantments[i].pOfName=RemoveQuotes(tokens[1]); + for (int j = 0; j < 9; j++) + { + pEnchantments[i].to_item[j]=atoi(tokens[j+2]); + } + } + + memset(&pEnchantmentsSumm, 0, 36); + for(int i=0;i<9;++i) + { + for (int j=0;j<24;++j) + pEnchantmentsSumm[i]+=pEnchantments[j].to_item[i]; + } + + //Bonus range for Standard by Level + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + for(int i=0;i<6;++i) //counted from 1 + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() == 4, "Invalid number of tokens"); + bonus_ranges[i].minR = atoi(tokens[2]); + bonus_ranges[i].maxR =atoi(tokens[3]); + } + + + pSpcItemsTXT_Raw = (char *)pEvents_LOD->LoadRaw("spcitems.txt", 0); + strtok(pSpcItemsTXT_Raw, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + for (int i=0;i<72;++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() >= 17, "Invalid number of tokens"); + pSpecialEnchantments[i].pBonusStatement=RemoveQuotes(tokens[0]); + pSpecialEnchantments[i].pNameAdd= RemoveQuotes(tokens[1]); + for (int j = 0; j < 12; j++) + { + pSpecialEnchantments[i].to_item_apply[j]=atoi(tokens[j+2]); + } + int res; + res=atoi(tokens[14]); + if(!res) + { + ++tokens[14]; + while (*tokens[14]==' ')//fix X 2 case + ++tokens[14]; + res=atoi(tokens[14]); + } + pSpecialEnchantments[i].iValue=res; + pSpecialEnchantments[i].iTreasureLevel= tolower(tokens[15][0]) - 97; + } + + pSpecialEnchantments_count = 71; + memset(&pSpecialEnchantmentsSumm, 0, 96); + for(int i=0;i<12;++i) + { + for (unsigned int j=0;j<=pSpecialEnchantments_count;++j) + pSpecialEnchantmentsSumm[i]+=pSpecialEnchantments[j].to_item_apply[i]; + } + + InitializeBuildingResidents(); + + pItemsTXT_Raw = (char*) pEvents_LOD->LoadRaw("items.txt", 0); + strtok(pItemsTXT_Raw, "\r"); + strtok(NULL, "\r"); + uAllItemsCount = 0; + item_counter = 0; + while (item_counter < 800) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + item_counter=atoi(tokens[0]); + uAllItemsCount=item_counter; + pItems[item_counter].pIconName = RemoveQuotes(tokens[1]); + pItems[item_counter].pName = RemoveQuotes(tokens[2]); + pItems[item_counter].uValue=atoi(tokens[3]); + auto findResult = equipStatMap.find(tokens[4]); + pItems[item_counter].uEquipType = findResult == equipStatMap.end() ? EQUIP_NONE : findResult->second; + auto findResult2 = equipSkillMap.find(tokens[5]); + pItems[item_counter].uSkillType = findResult2 == equipSkillMap.end() ? PLAYER_SKILL_MISC : findResult2->second; + auto tokens2 = Tokenize(tokens[6], 'd'); + if (tokens2.size() == 2) + { + pItems[item_counter].uDamageDice=atoi(tokens2[0]); + pItems[item_counter].uDamageRoll=atoi(tokens2[1]); + } + else if (tolower(tokens2[0][0]) != 's') + { + pItems[item_counter].uDamageDice=atoi(tokens2[0]); + pItems[item_counter].uDamageRoll=1; + } + else + { + pItems[item_counter].uDamageDice=0; + pItems[item_counter].uDamageRoll=0; + } + pItems[item_counter].uDamageMod=atoi(tokens[7]); + auto findResult3 = materialMap.find(tokens[8]); + pItems[item_counter].uMaterial = findResult3 == materialMap.end() ? MATERIAL_COMMON : findResult3->second; + pItems[item_counter].uItemID_Rep_St=atoi(tokens[9]); + pItems[item_counter].pUnidentifiedName = RemoveQuotes(tokens[10]); + pItems[item_counter].uSpriteID=atoi(tokens[11]); + + pItems[item_counter]._additional_value=0; + pItems[item_counter]._bonus_type=0; + if (pItems[item_counter].uMaterial==MATERIAL_SPECIAL) + { + for(int ii=0; ii<24; ++ii) + { + if (!_stricmp(tokens[12],pEnchantments[ii].pOfName)) + { + pItems[item_counter]._bonus_type=ii+1; + break; + } + } + if (!pItems[item_counter]._bonus_type) + { + for(int ii=0; ii<72; ++ii) + { + if (!_stricmp(tokens[12],pSpecialEnchantments[ii].pNameAdd)) + { + pItems[item_counter]._additional_value=ii+1; + } + } + } + } + + if ((pItems[item_counter].uMaterial==MATERIAL_SPECIAL)&&(pItems[item_counter]._bonus_type)) + { + char b_s=atoi(tokens[13]); + if (b_s) + pItems[item_counter]._bonus_strength=b_s; + else + pItems[item_counter]._bonus_strength=1; + } + else + pItems[item_counter]._bonus_strength=0; + pItems[item_counter].uEquipX=atoi(tokens[14]); + pItems[item_counter].uEquipY=atoi(tokens[15]); + pItems[item_counter].pDescription = RemoveQuotes(tokens[16]); + item_counter++; + } + + uAllItemsCount = item_counter; + pRndItemsTXT_Raw = (char *)pEvents_LOD->LoadRaw("rnditems.txt", 0); + strtok(pRndItemsTXT_Raw, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + for (item_counter = 0; item_counter < 619; item_counter++) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() > 7, "Invalid number of tokens"); + item_counter = atoi(tokens[0]); + pItems[item_counter].uChanceByTreasureLvl1=atoi(tokens[2]); + pItems[item_counter].uChanceByTreasureLvl2=atoi(tokens[3]); + pItems[item_counter].uChanceByTreasureLvl3=atoi(tokens[4]); + pItems[item_counter].uChanceByTreasureLvl4=atoi(tokens[5]); + pItems[item_counter].uChanceByTreasureLvl5=atoi(tokens[6]); + pItems[item_counter].uChanceByTreasureLvl6=atoi(tokens[7]); + } + + //ChanceByTreasureLvl Summ - to calculate chance + memset(&uChanceByTreasureLvlSumm, 0, 24); + for(int i=0;i<6;++i) + { + for (int j=1;j<item_counter;++j) + uChanceByTreasureLvlSumm[i]+=pItems[j].uChanceByTreasureLvl[i]; + } + + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + for (int i=0;i<3;++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() > 7, "Invalid number of tokens"); + switch (i) + { + case 0: + uBonusChanceStandart[0]=atoi(tokens[2]); + uBonusChanceStandart[1]=atoi(tokens[3]); + uBonusChanceStandart[2]=atoi(tokens[4]); + uBonusChanceStandart[3]=atoi(tokens[5]); + uBonusChanceStandart[4]=atoi(tokens[6]); + uBonusChanceStandart[5]=atoi(tokens[7]); + break; + case 1: + uBonusChanceSpecial[0]=atoi(tokens[2]); + uBonusChanceSpecial[1]=atoi(tokens[3]); + uBonusChanceSpecial[2]=atoi(tokens[4]); + uBonusChanceSpecial[3]=atoi(tokens[5]); + uBonusChanceSpecial[4]=atoi(tokens[6]); + uBonusChanceSpecial[5]=atoi(tokens[7]); + break; + case 2: + uBonusChanceWpSpecial[0]=atoi(tokens[2]); + uBonusChanceWpSpecial[1]=atoi(tokens[3]); + uBonusChanceWpSpecial[2]=atoi(tokens[4]); + uBonusChanceWpSpecial[3]=atoi(tokens[5]); + uBonusChanceWpSpecial[4]=atoi(tokens[6]); + uBonusChanceWpSpecial[5]=atoi(tokens[7]); + break; + } + } + free(pRndItemsTXT_Raw); + pRndItemsTXT_Raw = nullptr; + + pSkillDescTXT_Raw = (char *)pEvents_LOD->LoadRaw("skilldes.txt", 0); + strtok(pSkillDescTXT_Raw, "\r"); + for (int i=0; i<37; ++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() >= 6, "Invalid number of tokens"); + pSkillDesc[i] = RemoveQuotes(tokens[1]); + pNormalSkillDesc[i] = RemoveQuotes(tokens[2]); + pExpertSkillDesc[i] = RemoveQuotes(tokens[3]); + pMasterSkillDesc[i] = RemoveQuotes(tokens[4]); + pGrandSkillDesc[i] = RemoveQuotes(tokens[5]); + } + + pStatsTXT_Raw = (char *)pEvents_LOD->LoadRaw("stats.txt", 0); + strtok(pStatsTXT_Raw, "\r"); + for (int i=0; i<26; ++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() == 2, "Invalid number of tokens"); + switch (i) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + pAttributeDescriptions[i] = RemoveQuotes(tokens[1]); + break; + case 7: + pHealthPointsAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 8: + pArmourClassAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 9: + pSpellPointsAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 10: + pPlayerConditionAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 11: + pFastSpellAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 12: + pPlayerAgeAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 13: + pPlayerLevelAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 14: + pPlayerExperienceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 15: + pAttackBonusAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 16: + pAttackDamageAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 17: + pMissleBonusAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 18: + pMissleDamageAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 19: + pFireResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 20: + pAirResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 21: + pWaterResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 22: + pEarthResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 23: + pMindResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 24: + pBodyResistanceAttributeDescription = RemoveQuotes(tokens[1]); + break; + case 25: + pSkillPointsAttributeDescription = RemoveQuotes(tokens[1]); + break; + } + } + + pClassTXT_Raw = 0; + pClassTXT_Raw = (char *)pEvents_LOD->LoadRaw("class.txt", 0); + strtok(pClassTXT_Raw, "\r"); + for (int i=0; i<36; ++i) + { + test_string = strtok(NULL, "\r") + 1; + auto tokens = Tokenize(test_string, '\t'); + Assert(tokens.size() == 3, "Invalid number of tokens"); + pClassDescriptions[i]=RemoveQuotes(tokens[1]); + } + + + + ItemGen::PopulateSpecialBonusMap(); + ItemGen::PopulateArtifactBonusMap(); + ItemGen::PopulateRegularBonusMap(); + + + } + +//----- (00456D17) -------------------------------------------------------- +void ItemsTable::SetSpecialBonus(ItemGen *pItem) +{ + if ( pItems[pItem->uItemID].uMaterial == MATERIAL_SPECIAL ) + { + pItem->uEnchantmentType = pItems[pItem->uItemID]._bonus_type; + pItem->uSpecEnchantmentType = pItems[pItem->uItemID]._additional_value; + pItem->m_enchantmentStrength = pItems[pItem->uItemID]._bonus_strength; + } +} + +//----- (00456D43) -------------------------------------------------------- +bool ItemsTable::IsMaterialSpecial(ItemGen *pItem) +{ + return this->pItems[pItem->uItemID].uMaterial == MATERIAL_SPECIAL; +} + +//----- (00456D5E) -------------------------------------------------------- +bool ItemsTable::IsMaterialNonCommon(ItemGen *pItem) +{ + return pItems[pItem->uItemID].uMaterial == MATERIAL_SPECIAL || + pItems[pItem->uItemID].uMaterial == MATERIAL_RELIC || + pItems[pItem->uItemID].uMaterial == MATERIAL_ARTEFACT; +} + + +//----- (00453B3C) -------------------------------------------------------- +void ItemsTable::LoadPotions() +{ + + CHAR Text[90]; + char* test_string; + unsigned int uRow; + unsigned int uColumn; + unsigned __int8 potion_value; + + free(pPotionNotesTXT_Raw); + auto tokens = Tokenize("", '\t'); + char* pPotionsTXT_Raw = (char *)pEvents_LOD->LoadRaw("potion.txt", 0); + test_string = strtok(pPotionsTXT_Raw ,"\r") + 1; + while (test_string) + { + tokens = Tokenize(test_string, '\t'); + if (!strcmp(tokens[0], "222")) + break; + test_string = strtok(NULL ,"\r") + 1; + } + if (!test_string) + { + MessageBoxA(0, "Error Pre-Parsing Potion Table", "Load Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + + for (uRow = 0;uRow < 50; ++uRow) + { + if (tokens.size() < 50) + { + wsprintfA(Text, "Error Parsing Potion Table at Row: %d Column: %d", uRow, tokens.size()); + MessageBoxA(0, Text, "Parsing Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + for (uColumn = 0; uColumn < 50; ++uColumn) + { + char* currValue = tokens[uColumn + 7]; + potion_value = atoi(currValue); + if ( !potion_value && tolower(currValue[0]) == 'e') + { + potion_value = atoi(currValue + 1); + } + this->potion_data[uRow][uColumn]=potion_value; + } + + test_string = strtok(NULL ,"\r") + 1; + if (!test_string) + { + wsprintfA(Text, "Error Parsing Potion Table at Row: %d Column: %d", uRow, 0); + MessageBoxA(0, Text, "Parsing Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + tokens = Tokenize(test_string, '\t'); + } +} + +//----- (00453CE5) -------------------------------------------------------- +void ItemsTable::LoadPotionNotes() +{ + + CHAR Text[90]; + char* test_string; + unsigned int uRow; + unsigned int uColumn; + unsigned __int8 potion_note; + + free(pPotionNotesTXT_Raw); + auto tokens = Tokenize("", '\t'); + char* pPotionNotesTXT_Raw = (char *)pEvents_LOD->LoadRaw("potnotes.txt", 0); + test_string = strtok(pPotionNotesTXT_Raw ,"\r") + 1; + while (test_string) + { + tokens = Tokenize(test_string, '\t'); + if (!strcmp(tokens[0], "222")) + break; + test_string = strtok(NULL ,"\r") + 1; + } + if (!test_string) + { + MessageBoxA(0, "Error Pre-Parsing Potion Table", "Load Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + + for (uRow = 0;uRow < 50; ++uRow) + { + if (tokens.size() < 50) + { + wsprintfA(Text, "Error Parsing Potion Table at Row: %d Column: %d", uRow, tokens.size()); + MessageBoxA(0, Text, "Parsing Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + for (uColumn = 0; uColumn < 50; ++uColumn) + { + char* currValue = tokens[uColumn + 7]; + potion_note = atoi(currValue); + if ( !potion_note && tolower(currValue[0]) == 'e') + { + potion_note = atoi(currValue + 1); + } + this->potion_note[uRow][uColumn]=potion_note; + } + + test_string = strtok(NULL ,"\r") + 1; + if (!test_string) + { + wsprintfA(Text, "Error Parsing Potion Table at Row: %d Column: %d", uRow, 0); + MessageBoxA(0, Text, "Parsing Error", MB_ICONHAND|MB_CANCELTRYCONTINUE); + return; + } + tokens = Tokenize(test_string, '\t'); + } + + + } + + +//----- (00456442) -------------------------------------------------------- +unsigned int ItemGen::GetValue() + { + unsigned int uBaseValue; // edi@1 + unsigned int bonus; + + uBaseValue = pItemsTable->pItems[this->uItemID].uValue; + if ( this->uAttributes & ITEM_TEMP_BONUS || pItemsTable->IsMaterialNonCommon(this) ) + return uBaseValue; + if (uEnchantmentType ) + return uBaseValue + 100 * m_enchantmentStrength;; + if (uSpecEnchantmentType ) + { + bonus = pItemsTable->pSpecialEnchantments[uSpecEnchantmentType].iTreasureLevel; + if ( bonus > 10 ) + return uBaseValue + bonus; + else + return uBaseValue * bonus; + } + return uBaseValue; + } + +//----- (00456499) -------------------------------------------------------- +const char *ItemGen::GetDisplayName() +{ + if (IsIdentified()) + return GetIdentifiedName(); + else + return pItemsTable->pItems[uItemID].pUnidentifiedName; +} + +//----- (004564B3) -------------------------------------------------------- +const char *ItemGen::GetIdentifiedName() +{ + unsigned __int8 equip_type; + const char *player_name; + const char *nameModificator; + const char *format_str; + + equip_type = GetItemEquipType(); + if ( (equip_type == EQUIP_REAGENT) || (equip_type == EQUIP_POTION) || (equip_type == EQUIP_GOLD) ) + { + sprintf(item__getname_buffer.data(), "%s", pItemsTable->pItems[uItemID].pName); + return item__getname_buffer.data(); + } + sprintf(item__getname_buffer.data(), "%s", pItemsTable->pItems[uItemID].pName); + if ( uItemID == ITEM_LICH_JAR_FULL ) //Lich Jar + { + if ( (uHolderPlayer >0 )&& (uHolderPlayer <= 4) ) + { + player_name = pPlayers[uHolderPlayer]->pName; + if ( player_name[strlen(player_name) - 1] == 's' ) + format_str = pGlobalTXT_LocalizationStrings[655]; //"%s' Jar" + else + format_str = pGlobalTXT_LocalizationStrings[654]; //"%s's Jar" + sprintf(item__getname_buffer.data(), format_str, pPlayers[uHolderPlayer]->pName); + return item__getname_buffer.data(); + } + } + if ( !pItemsTable->IsMaterialNonCommon(this) ) + { + if ( uEnchantmentType ) + { + strcat(item__getname_buffer.data(), " "); + nameModificator = pItemsTable->pEnchantments[uEnchantmentType-1].pOfName; + } + else + { + if ( !uSpecEnchantmentType ) + return item__getname_buffer.data(); + if ( uSpecEnchantmentType == 16 //Drain Hit Points from target. + || uSpecEnchantmentType == 39 //Double damage vs Demons. + || uSpecEnchantmentType == 40 //Double damage vs Dragons + || uSpecEnchantmentType == 45 //+5 Speed and Accuracy + || uSpecEnchantmentType == 56 //+5 Might and Endurance. + || uSpecEnchantmentType == 57 //+5 Intellect and Personality. + || uSpecEnchantmentType == 58 //Increased Value. + || uSpecEnchantmentType == 60 //+3 Unarmed and Dodging skills + || uSpecEnchantmentType == 61 //+3 Stealing and Disarm skills. + || uSpecEnchantmentType == 59 //Increased Weapon speed. + || uSpecEnchantmentType == 63 //Double Damage vs. Elves. + || uSpecEnchantmentType == 64 //Double Damage vs. Undead. + || uSpecEnchantmentType == 67 //Adds 5 points of Body damage and +2 Disarm skill. + || uSpecEnchantmentType == 68 ) //Adds 6-8 points of Cold damage and +5 Armor Class. + { //enchantment and name positions inverted! + sprintf( item__getname_buffer.data(), "%s %s", + pItemsTable->pSpecialEnchantments[uSpecEnchantmentType-1].pNameAdd, + pItemsTable->pItems[uItemID].pName); + return item__getname_buffer.data(); + } + strcat(item__getname_buffer.data(), " "); + nameModificator = pItemsTable->pSpecialEnchantments[uSpecEnchantmentType-1].pNameAdd; + } + strcat(item__getname_buffer.data(), nameModificator); + } + return item__getname_buffer.data(); +} + + +//----- (00456620) -------------------------------------------------------- +void ItemsTable::GenerateItem(int treasure_level, unsigned int uTreasureType, ItemGen *out_item) + { + int treasureLevelMinus1; // ebx@3 + int current_chance; // ebx@43 + int tmp_chance; // ecx@47 + int v17; // ebx@57 + int v18; // edx@62 + unsigned int special_chance; // edx@86 + unsigned int v26; // edx@89 + unsigned int v27; // eax@89 + int v32; // ecx@91 + int v33; // eax@91 +// unsigned int v34; // eax@97 + int v45; // eax@120 + int v46; // edx@120 + int j; // eax@121 + int val_list[800]; // [sp+Ch] [bp-C88h]@33 + int total_chance; // [sp+C8Ch] [bp-8h]@33 + signed int v56; // [sp+CA0h] [bp+Ch]@55 + int v57; // [sp+CA0h] [bp+Ch]@62 + + if (!out_item) + out_item = (ItemGen *)malloc(sizeof(ItemGen)); + memset(out_item, 0, sizeof(*out_item)); + + + treasureLevelMinus1 = treasure_level - 1; + if ( uTreasureType ) //generate known treasure type + { + ITEM_EQUIP_TYPE requested_equip; + PLAYER_SKILL_TYPE requested_skill = PLAYER_SKILL_INVALID; + switch (uTreasureType) + { + case 20: requested_equip = EQUIP_SINGLE_HANDED; break; + case 21: requested_equip = EQUIP_ARMOUR; break; + case 22: requested_skill = PLAYER_SKILL_MISC; break; + case 23: requested_skill = PLAYER_SKILL_SWORD; break; + case 24: requested_skill = PLAYER_SKILL_DAGGER; break; + case 25: requested_skill = PLAYER_SKILL_AXE; break; + case 26: requested_skill = PLAYER_SKILL_SPEAR; break; + case 27: requested_skill = PLAYER_SKILL_BOW; break; + case 28: requested_skill = PLAYER_SKILL_MACE; break; + case 29: requested_skill = PLAYER_SKILL_CLUB; break; + case 30: requested_skill = PLAYER_SKILL_STAFF; break; + case 31: requested_skill = PLAYER_SKILL_LEATHER; break; + case 32: requested_skill = PLAYER_SKILL_CHAIN; break; + case 33: requested_skill = PLAYER_SKILL_PLATE; break; + case 34: requested_equip = EQUIP_SHIELD; break; + case 35: requested_equip = EQUIP_HELMET; break; + case 36: requested_equip = EQUIP_BELT; break; + case 37: requested_equip = EQUIP_CLOAK; break; + case 38: requested_equip = EQUIP_GAUNTLETS; break; + case 39: requested_equip = EQUIP_BOOTS; break; + case 40: requested_equip = EQUIP_RING; break; + case 41: requested_equip = EQUIP_AMULET; break; + case 42: requested_equip = EQUIP_WAND; break; + case 43: requested_equip = EQUIP_SPELL_SCROLL; break; + case 44: requested_equip = EQUIP_POTION; break; + case 45: requested_equip = EQUIP_REAGENT; break; + case 46: requested_equip = EQUIP_GEM; break; + default: + __debugbreak(); // check this condition + requested_equip = (ITEM_EQUIP_TYPE)(uTreasureType - 1); + break; + } + memset(val_list, 0, sizeof(val_list)); + total_chance = 0; + j=0; + //a2a = 1; + if (requested_skill == PLAYER_SKILL_INVALID) // no skill for this item needed + { + for (uint i = 1; i < 500; ++i) + { + if (pItems[i].uEquipType == requested_equip) + { + val_list[j] = i; + ++j; + total_chance += pItems[i].uChanceByTreasureLvl[treasure_level - 1]; + } + } + } + else //have needed skill + { + for (uint i = 1; i < 500; ++i) + { + if (pItems[i].uSkillType == requested_skill) + { + val_list[j] = i; + ++j; + total_chance += pItems[i].uChanceByTreasureLvl[treasure_level - 1]; + } + } + } + + current_chance = 0; + if ( total_chance ) + { + current_chance = rand() % total_chance + 1; + tmp_chance = 0; + j=0; + while(tmp_chance < current_chance) + { + out_item->uItemID = val_list[j]; + tmp_chance += pItems[val_list[j]].uChanceByTreasureLvl[treasure_level - 1]; + ++j; + } + } + else + { + out_item->uItemID = 1; + } + } + else + { + //artifact + if ( treasureLevelMinus1 == 5 ) + { + v56 = 0; + for(int i=0; i<29; ++i) + v56 += pParty->pIsArtifactFound[i]; + v17 = rand() % 29; + if ((rand() % 100 < 5) && !pParty->pIsArtifactFound[v17] && v56 < 13) + { + pParty->pIsArtifactFound[v17] = 1; + out_item->uAttributes = 0; + out_item->uItemID = v17 + 500; + SetSpecialBonus(out_item); + return; + } + } + + v57 = 0; + v18 = rand() % this->uChanceByTreasureLvlSumm[treasure_level - 1] + 1; + while (v57 < v18) + { + ++out_item->uItemID; + v57 += pItems[out_item->uItemID].uChanceByTreasureLvl[treasureLevelMinus1]; + } + } + if (out_item->GetItemEquipType() == EQUIP_POTION && out_item->uItemID != ITEM_POTION_BOTTLE ) + {// if it potion set potion spec + out_item->uEnchantmentType = 0; + for (int i=0; i<2; ++i) + out_item->uEnchantmentType += rand() % 4 + 1; + out_item->uEnchantmentType = out_item->uEnchantmentType * treasure_level; + } + + if ( out_item->uItemID == ITEM_SPELLBOOK_LIGHT_DIVINE_INTERVENTION + && !(unsigned __int16)_449B57_test_bit(pParty->_quest_bits, 239) ) + out_item->uItemID = ITEM_SPELLBOOK_LIGHT_SUN_BURST; + if ( pItemsTable->pItems[out_item->uItemID].uItemID_Rep_St ) + out_item->uAttributes = 0; + else + out_item->uAttributes = 1; + + if ( out_item->GetItemEquipType() != EQUIP_POTION ) + { + out_item->uSpecEnchantmentType = 0; + out_item->uEnchantmentType = 0; + } + //try get special enhansment + switch (out_item->GetItemEquipType()) + { + case EQUIP_SINGLE_HANDED: + case EQUIP_TWO_HANDED : + case EQUIP_BOW : + if ( !uBonusChanceWpSpecial[treasureLevelMinus1] ) + return; + if ((uint)(rand() % 100)>=uBonusChanceWpSpecial[treasureLevelMinus1]) + return; + break; + case EQUIP_ARMOUR : + case EQUIP_SHIELD : + case EQUIP_HELMET : + case EQUIP_BELT : + case EQUIP_CLOAK : + case EQUIP_GAUNTLETS : + case EQUIP_BOOTS : + case EQUIP_RING : + + if ( !uBonusChanceStandart[treasureLevelMinus1] ) + return; + special_chance = rand() % 100; + if ( special_chance < uBonusChanceStandart[treasureLevelMinus1]) + { + v26 = rand() %pEnchantmentsSumm[out_item->GetItemEquipType()-3] + 1; + v27 = 0; + while(v27 < v26) + { + ++out_item->uEnchantmentType; + v27+=pEnchantments[out_item->uEnchantmentType].to_item[out_item->GetItemEquipType()-3]; + } + + v33 = rand() % (bonus_ranges[treasureLevelMinus1].maxR - bonus_ranges[treasureLevelMinus1].minR + 1); + out_item->m_enchantmentStrength = v33 + bonus_ranges[treasureLevelMinus1].minR; + v32 = out_item->uEnchantmentType - 1; + if ( v32 == 21 || v32 == 22 || v32 == 23 ) //Armsmaster skill, Dodge skill, Unarmed skill + out_item->m_enchantmentStrength = out_item->m_enchantmentStrength/2; + if ( out_item->m_enchantmentStrength <= 0 ) + out_item->m_enchantmentStrength = 1; + return; + + } + else if ( special_chance >= uBonusChanceStandart[treasureLevelMinus1] + uBonusChanceSpecial[treasureLevelMinus1] ) + return; + break; + case EQUIP_WAND: + out_item->uNumCharges = rand() % 6 + out_item->GetDamageMod() + 1; + out_item->uMaxCharges = out_item->uNumCharges; + return; + default: + return; + } + + j=0; + int spc_sum=0; + int spc; + memset(&val_list, 0, 3200); + for (unsigned int i=0; i<pSpecialEnchantments_count;++i) + { + int tr_lv= pSpecialEnchantments[i].iTreasureLevel; + if ((treasure_level - 1 == 2) && ( tr_lv == 1 || tr_lv == 0 ) || + (treasure_level - 1 == 3) && (tr_lv == 2 || tr_lv == 1 || tr_lv == 0) || + (treasure_level - 1 == 4) && (tr_lv == 3 || tr_lv == 2 || tr_lv == 1) || + (treasure_level - 1 == 5) && (tr_lv == 3) + ) + { + spc=pSpecialEnchantments[i].to_item_apply[out_item->GetItemEquipType()]; + spc_sum+=spc; + if(spc) + { + val_list[j++]=i; + } + } + } + + v46 = rand()%spc_sum+1;//ñëó÷àéíûå çíà÷åíèÿ îò 1 äî spc_sum + j=0; + v45 = 0; + while (v45<v46) + { + ++j; + out_item->uSpecEnchantmentType=val_list[j]; + v45+=pSpecialEnchantments[val_list[j]].to_item_apply[out_item->GetItemEquipType()]; + } +} + +//----- (004505CC) -------------------------------------------------------- +bool ItemGen::GenerateArtifact() +{ + signed int uNumArtifactsNotFound; // esi@1 + int artifacts_list[32]; + + memset(artifacts_list, 0,sizeof(artifacts_list)); + uNumArtifactsNotFound = 0; + + for (int i=500;i<529;++i) + if ( !pParty->pIsArtifactFound[i-500] ) + artifacts_list[uNumArtifactsNotFound++] = i; + + Reset(); + if ( uNumArtifactsNotFound ) + { + uItemID = artifacts_list[rand() % uNumArtifactsNotFound]; + pItemsTable->SetSpecialBonus(this); + return true; + } + else + return false; + +} + +std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* >ItemGen::regularBonusMap; +std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* >ItemGen::specialBonusMap; +std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* >ItemGen::artifactBonusMap; + +#define NEWBONUSINTOSPECIALLIST(x,y) AddToMap(ItemGen::specialBonusMap, enchId, x, y); +#define NEWBONUSINTOSPECIALLIST2(x,y,z) AddToMap(ItemGen::specialBonusMap, enchId, x, y, z); + +#define NEWBONUSINTOREGULARLIST(x) AddToMap(ItemGen::regularBonusMap, enchId, x); + +#define NEWBONUSINTOARTIFACTLIST(x,y) AddToMap(ItemGen::artifactBonusMap, itemId, x, y); +#define NEWBONUSINTOARTIFACTLIST2(x,y,z) AddToMap(ItemGen::artifactBonusMap, itemId, x, y, z); + +void ItemGen::AddToMap( std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* > &maptoadd, int enchId, CHARACTER_ATTRIBUTE_TYPE attrId, int bonusValue /*= 0*/, unsigned __int16 Player::* skillPtr /*= NULL*/ ) +{ + auto key = maptoadd.find(enchId); + std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* currMap; + if (key == maptoadd.end()) + { + currMap = new std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>; + maptoadd[enchId] = currMap; + } + else + { + currMap = key->second; + } + Assert(currMap->find(attrId) == currMap->end(), "Attribute %d already present for enchantment %d", attrId, enchId); + (*currMap)[attrId] = new CEnchantment(bonusValue, skillPtr); +} + +void ItemGen::PopulateSpecialBonusMap() +{ + int enchId = 1;// of Protection, +10 to all Resistances + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 10); + NEWBONUSINTOSPECIALLIST( CHARACTER_ATTRIBUTE_RESIST_AIR, 10); + NEWBONUSINTOSPECIALLIST( CHARACTER_ATTRIBUTE_RESIST_WATER, 10); + NEWBONUSINTOSPECIALLIST( CHARACTER_ATTRIBUTE_RESIST_EARTH, 10); + NEWBONUSINTOSPECIALLIST( CHARACTER_ATTRIBUTE_RESIST_MIND, 10); + NEWBONUSINTOSPECIALLIST( CHARACTER_ATTRIBUTE_RESIST_BODY, 10); + + enchId = 2;//of The Gods, +10 to all Seven Statistics + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_STRENGTH, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ACCURACY, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_SPEED, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_LUCK, 10); + + enchId = 26;//of Air Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_AIR,0, &Player::skillAir); + + enchId = 27;//of Body Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_BODY,0, &Player::skillBody); + + enchId = 28;//of Dark Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_DARK,0, &Player::skillDark); + + enchId = 29;//of Earth Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_EARTH,0, &Player::skillEarth); + + enchId = 30;//of Fire Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_FIRE,0, &Player::skillFire); + + enchId = 31;//of Light Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_LIGHT,0, &Player::skillLight); + + enchId = 32;//of Mind Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_MIND,0, &Player::skillMind); + + enchId = 33;//of Spirit Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_SPIRIT,0, &Player::skillSpirit); + + enchId = 34;//of Water Magic + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_WATER,0, &Player::skillWater); + + enchId = 42;//of Doom + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_STRENGTH, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ACCURACY, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_SPEED, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_LUCK, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_HEALTH, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_MANA, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_AC_BONUS, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_MIND, 1); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_BODY, 1); + + enchId = 43;//of Earth + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_AC_BONUS, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_HEALTH, 10); + + enchId = 44;//of Life + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_HEALTH, 10); + + enchId = 45;//Rogues + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_SPEED, 5); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ACCURACY, 5); + + enchId = 46;//of The Dragon + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_STRENGTH, 25); + + enchId = 47;//of The Eclipse + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_MANA, 10); + + enchId = 48;//of The Golem + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 15); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_AC_BONUS, 5); + + enchId = 49;//of The Moon + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_LUCK, 10); + + enchId = 50;//of The Phoenix + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 30); + + enchId = 51;//of The Sky + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_MANA, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_SPEED, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 10); + + enchId = 52;//of The Stars + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ACCURACY, 10); + + enchId = 53;//of The Sun + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_STRENGTH, 10); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 10); + + enchId = 54;//of The Troll + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 15); + + enchId = 55;//of The Unicorn + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_LUCK, 15); + + enchId = 56;//Warriors + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_STRENGTH, 5); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 5); + + enchId = 57;//Wizards + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 5); + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 5); + + enchId = 60;//Monks' + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_DODGE, 3, &Player::skillDodge); + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_UNARMED, 3, &Player::skillUnarmed); + + enchId = 61;//Thieves' + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM, 3, &Player::skillStealing); + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_STEALING, 3, &Player::skillDisarmTrap); + + enchId = 62;//of Identifying + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_ITEM_ID, 3, &Player::skillItemId); + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID, 3, &Player::skillMonsterId); + + enchId = 67;//Assassins' + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM, 2, &Player::skillDisarmTrap); + + enchId = 68;//Barbarians' + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_AC_BONUS, 5); + + enchId = 69;//of the Storm + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, 20); + + enchId = 70;//of the Ocean + NEWBONUSINTOSPECIALLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, 10); + NEWBONUSINTOSPECIALLIST2(CHARACTER_ATTRIBUTE_SKILL_ALCHEMY, 2, &Player::skillAlchemy); +} + +void ItemGen::PopulateRegularBonusMap() +{ + int enchId = 1;//of Might + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_STRENGTH); + + enchId = 2;//of Thought + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE); + + enchId = 3;//of Charm + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_WILLPOWER); + + enchId = 4;//of Vigor + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_ENDURANCE); + + enchId = 5;//of Precision + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_ACCURACY); + + enchId = 6;//of Speed + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SPEED); + + enchId = 7;//of Luck + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_LUCK); + + enchId = 8;//of Health + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_HEALTH); + + enchId = 9;//of Magic + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_MANA); + + enchId = 10;//of Defense + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_AC_BONUS); + + enchId = 11;//of Fire Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE); + + enchId = 12;//of Air Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_AIR); + + enchId = 13;//of Water Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_WATER); + + enchId = 14;//of Earth Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH); + + enchId = 15;//of Mind Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_MIND); + + enchId = 16;//of Body Resistance + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_RESIST_BODY); + + enchId = 17;//of Alchemy + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_ALCHEMY); + + enchId = 18;//of Stealing + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_STEALING); + + enchId = 19;//of Disarming + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM); + + enchId = 20;//of Items + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_ITEM_ID); + + enchId = 21;//of Monsters + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID); + + enchId = 22;//of Arms + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER); + + enchId = 23;//of Dodging + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_DODGE); + + enchId = 24;//of the Fist + NEWBONUSINTOREGULARLIST(CHARACTER_ATTRIBUTE_SKILL_UNARMED); +} + +void ItemGen::PopulateArtifactBonusMap() +{ + int itemId; + itemId = ITEM_ARTIFACT_PUCK; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 40); + + itemId = ITEM_ARTIFACT_IRON_FEATHER; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 40); + + itemId = ITEM_ARTIFACT_WALLACE; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 40); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER, 10); + + itemId = ITEM_ARTIFACT_CORSAIR; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_LUCK, 40); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM, 5); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_STEALING, 5); + + itemId = ITEM_ARTIFACT_GOVERNORS_ARMOR; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ACCURACY, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_LUCK, 10); + + itemId = ITEM_ARTIFACT_YORUBA; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 25); + + itemId = ITEM_ARTIFACT_SPLITTER; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 50); + + itemId = ITEM_ARTEFACT_ULLYSES, + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ACCURACY, 50); + + itemId = ITEM_ARTEFACT_HANDS_OF_THE_MASTER, + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_DODGE, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_UNARMED, 10); + + itemId = ITEM_ARTIFACT_LEAGUE_BOOTS; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, 40); + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_WATER, 0, &Player::skillWater); + + itemId = ITEM_ARTIFACT_RULERS_RING; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_MIND, 0, &Player::skillMind); + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_DARK, 0, &Player::skillDark); + + itemId = ITEM_RELIC_MASH; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 150); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, -40); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, -40); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, -40); + + itemId = ITEM_RELIC_ETHRICS_STAFF; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_DARK, 0, &Player::skillDark); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_MEDITATION, 15); + + itemId = ITEM_RELIC_HARECS_LEATHER; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM, 5); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_STEALING, 5); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_LUCK, 50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_MIND, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_BODY, -10); + + itemId = ITEM_RELIC_OLD_NICK; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM, 5); + + itemId = ITEM_RELIC_AMUCK; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 100); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 100); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_AC_BONUS, -15); + + itemId = ITEM_RELIC_GLORY_SHIELD; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_SPIRIT, 0, &Player::skillSpirit); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_SHIELD, 5); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_MIND, -10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_BODY, -10); + + itemId = ITEM_RELIC_KELEBRIM; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH, -30); + + itemId = ITEM_RELIC_TALEDONS_HELM; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_LIGHT, 0, &Player::skillLight); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_LUCK, -40); + + itemId = ITEM_RELIC_SCHOLARS_CAP; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_LEARNING, +15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, -50); + + itemId = ITEM_RELIC_PHYNAXIAN_CROWN; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_FIRE, 0, &Player::skillFire); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, +50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 30); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_AC_BONUS, -20); + + itemId = ITEM_RILIC_TITANS_BELT; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 75); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, -40); + + itemId = ITEM_RELIC_TWILIGHT; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, 50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_LUCK, 50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, -15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, -15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, -15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH, -15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_MIND, -15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_BODY, -15); + + itemId = ITEM_RELIC_ANIA_SELVING; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ACCURACY, 150); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_BOW, 5); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_AC_BONUS, -25); + + itemId = ITEM_RELIC_JUSTICE; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_MIND, 0, &Player::skillMind); + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_BODY, 0, &Player::skillBody); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, -40); + + itemId = ITEM_RELIC_MEKORIGS_HAMMER; + NEWBONUSINTOARTIFACTLIST2(CHARACTER_ATTRIBUTE_SKILL_SPIRIT, 0, &Player::skillSpirit); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 75); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, -50); + + itemId = ITEM_ARTIFACT_HERMES_SANDALS; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, 100); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ACCURACY, 50); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, 50); + + itemId = ITEM_ARTIFACT_CLOAK_OF_THE_SHEEP; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, -20); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, -20); + + itemId = ITEM_ARTIFACT_MINDS_EYE; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_WILLPOWER, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_INTELLIGENCE, 15); + + itemId = ITEM_ELVEN_CHAINMAIL; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SPEED, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ACCURACY, 15); + + itemId = ITEM_FORGE_GAUNTLETS; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_ENDURANCE, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 30); + + itemId = ITEM_ARTIFACT_HEROS_BELT; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_STRENGTH, 15); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER, 5); + + itemId = ITEM_ARTIFACT_LADYS_ESCORT; + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_FIRE, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_AIR, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_WATER, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_EARTH, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_MIND, 10); + NEWBONUSINTOARTIFACTLIST(CHARACTER_ATTRIBUTE_RESIST_BODY, 10); +} + +void ItemGen::GetItemBonusSpecialEnchantment( Player* owner, CHARACTER_ATTRIBUTE_TYPE attrToGet, int* additiveBonus, int* halfSkillBonus ) +{ + auto bonusList = ItemGen::specialBonusMap.find(this->uSpecEnchantmentType); + if (bonusList == ItemGen::specialBonusMap.end()) + { + return; + } + std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* currList = bonusList->second; + if (currList->find(attrToGet) != currList->end()) + { + CEnchantment* currBonus = (*currList)[attrToGet]; + if (currBonus->statPtr != NULL) + { + if (currBonus->statBonus == 0) + { + *halfSkillBonus = owner->*currBonus->statPtr / 2; + } + else + { + if (*additiveBonus < currBonus->statBonus) + { + *additiveBonus = currBonus->statBonus; + } + } + } + else + { + *additiveBonus += currBonus->statBonus; + } + } +} + +void ItemGen::GetItemBonusArtifact( Player* owner, CHARACTER_ATTRIBUTE_TYPE attrToGet, int* bonusSum ) +{ + auto bonusList = ItemGen::artifactBonusMap.find(this->uItemID); + if (bonusList == ItemGen::artifactBonusMap.end()) + { + return; + } + std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* currList = bonusList->second; + if (currList->find(attrToGet) != currList->end()) + { + CEnchantment* currBonus = (*currList)[attrToGet]; + if (currBonus->statPtr != NULL) + { + *bonusSum = owner->*currBonus->statPtr / 2; + } + else + { + *bonusSum += currBonus->statBonus; + } + } +} + +bool ItemGen::IsRegularEnchanmentForAttribute( CHARACTER_ATTRIBUTE_TYPE attrToGet ) +{ + auto bonusList = ItemGen::specialBonusMap.find(this->uEnchantmentType); + if (bonusList == ItemGen::specialBonusMap.end()) + { + return false; + } + std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* currList = bonusList->second; + return (currList->find(attrToGet) != currList->end()); +} + +ITEM_EQUIP_TYPE ItemGen::GetItemEquipType() +{ + return pItemsTable->pItems[this->uItemID].uEquipType; +} + +unsigned char ItemGen::GetPlayerSkillType() +{ + return pItemsTable->pItems[this->uItemID].uSkillType; +} + +char* ItemGen::GetIconName() +{ + return pItemsTable->pItems[this->uItemID].pIconName; +} + +unsigned __int8 ItemGen::GetDamageDice() +{ + return pItemsTable->pItems[this->uItemID].uDamageDice; +} + +unsigned __int8 ItemGen::GetDamageRoll() +{ + return pItemsTable->pItems[this->uItemID].uDamageRoll; +} + +unsigned __int8 ItemGen::GetDamageMod() +{ + return pItemsTable->pItems[this->uItemID].uDamageMod; +} +//----- (004B8E3D) -------------------------------------------------------- +void GenerateStandartShopItems() +{ + signed int item_count; + signed int shop_index; + int treasure_lvl; + int item_class; + int mdf; + + shop_index = (signed int)window_SpeakInHouse->ptr_1C; + if ( uItemsAmountPerShopType[p2DEvents[shop_index - 1].uType] ) + { + for (item_count = 0; item_count < uItemsAmountPerShopType[p2DEvents[shop_index - 1].uType]; ++item_count ) + { + if (shop_index <= 14) //weapon shop + { + treasure_lvl = shopWeap_variation_ord[shop_index].treasure_level; + item_class = shopWeap_variation_ord[shop_index].item_class[rand() % 4]; + } + else if (shop_index <= 28) //armor shop + { + mdf = 0; + if (item_count > 3) + ++mdf;// rechek offsets + treasure_lvl = shopArmr_variation_ord[2*(shop_index - 15) + mdf].treasure_level; + item_class = shopArmr_variation_ord[2*(shop_index - 15) + mdf].item_class[rand() % 4]; + } + else if (shop_index <= 41) //magic shop + { + treasure_lvl = shopMagic_treasure_lvl[shop_index - 28]; + item_class = 22; //misc + } + else if (shop_index <= 53) //alchemist shop + { + if (item_count < 6) + { + pParty->StandartItemsInShops[shop_index][item_count].Reset(); + pParty->StandartItemsInShops[shop_index][item_count].uItemID = 220; //potion bottle + continue; + } + else + { + treasure_lvl = shopAlch_treasure_lvl[shop_index - 41]; + item_class = 45; //reagent + } + } + pItemsTable->GenerateItem(treasure_lvl, item_class, &pParty->StandartItemsInShops[shop_index][item_count]); + pParty->StandartItemsInShops[shop_index][item_count].SetIdentified(); //identified + } + } + pParty->InTheShopFlags[shop_index] = 0; +} + +//----- (004B8F94) -------------------------------------------------------- +void GenerateSpecialShopItems() +{ + signed int item_count; + signed int shop_index; + int treasure_lvl; + int item_class; + int mdf; + + shop_index = (signed int)window_SpeakInHouse->ptr_1C; + if ( uItemsAmountPerShopType[p2DEvents[shop_index - 1].uType] ) + { + for ( item_count = 0; item_count < uItemsAmountPerShopType[p2DEvents[shop_index - 1].uType]; ++item_count ) + { + if (shop_index <= 14) //weapon shop + { + treasure_lvl = shopWeap_variation_spc[shop_index].treasure_level; + item_class = shopWeap_variation_spc[shop_index].item_class[rand() % 4]; + } + else if (shop_index <= 28) //armor shop + { + mdf = 0; + if (item_count > 3) + ++mdf; + treasure_lvl = shopArmr_variation_spc[2*(shop_index - 15) + mdf].treasure_level; + item_class = shopArmr_variation_spc[2*(shop_index - 15) + mdf].item_class[rand() % 4]; + } + else if (shop_index <= 41) //magic shop + { + treasure_lvl = shopMagicSpc_treasure_lvl[shop_index - 28]; + item_class = 22; //misc + } + else if (shop_index <= 53) //alchemist shop + { + if (item_count < 6) + { + pParty->SpecialItemsInShops[shop_index][item_count].Reset(); + pParty->SpecialItemsInShops[shop_index][item_count].uItemID = rand() % 32 + 740; //mscrool + continue; + } + else + { + treasure_lvl = shopAlchSpc_treasure_lvl[shop_index - 41]; + item_class = 44; //potion + } + } + pItemsTable->GenerateItem(treasure_lvl, item_class, &pParty->SpecialItemsInShops[shop_index][item_count]); + pParty->SpecialItemsInShops[shop_index][item_count].SetIdentified(); //identified + } + } + pParty->InTheShopFlags[shop_index] = 0; +} + + +//----- (00450218) -------------------------------------------------------- +void GenerateItemsInChest() + { + unsigned int mapType; // eax@1 + MapInfo *currMapInfo; // esi@1 + ItemGen *currItem; // ebx@2 + int additionaItemCount; // ebp@4 + int treasureLevelBot; // edi@4 + int treasureLevelTop; // esi@4 + signed int treasureLevelRange; // esi@4 + int resultTreasureLevel; // edx@4 + int goldAmount; // esi@8 + int v11; // ebp@25 + int v12; // esi@25 + signed int whatToGenerateProb; // [sp+10h] [bp-18h]@1 + + mapType = pMapStats->GetMapInfo(pCurrentMapName); + currMapInfo = &pMapStats->pInfos[mapType]; + for(int i=1; i<20;++i) + { + for(int j=0; j<140;++j) + { + + currItem = &pChests[i].igChestItems[j]; + if ( currItem->uItemID < 0 ) + { + additionaItemCount = rand() % 5; //additional items in chect + treasureLevelBot = byte_4E8168[abs(currItem->uItemID)-1][2*currMapInfo->Treasure_prob]; + treasureLevelTop = byte_4E8168[abs(currItem->uItemID)-1][2*currMapInfo->Treasure_prob+1]; + treasureLevelRange = treasureLevelTop - treasureLevelBot + 1; + resultTreasureLevel = treasureLevelBot + rand() % treasureLevelRange; //treasure level + if (resultTreasureLevel<7) + { + v11 = 0; + do + { + whatToGenerateProb = rand() % 100; + if (whatToGenerateProb<20) + { + currItem->Reset(); + } + else if (whatToGenerateProb<60) //generate gold + { + goldAmount=0; + currItem->Reset(); + switch (resultTreasureLevel) + { + case 1: //small gold + goldAmount = rand() % 51 + 50; + currItem->uItemID = 197; + break; + case 2://small gold + goldAmount = rand() % 101 + 100; + currItem->uItemID = 197; + break; + case 3: //medium + goldAmount = rand() % 301 + 200; + currItem->uItemID = 198; + break; + case 4: //medium + goldAmount = rand() % 501 + 500; + currItem->uItemID = 198; + break; + case 5: //big + goldAmount = rand() % 1001 + 1000; + currItem->uItemID = 199; + break; + case 6: //big + goldAmount = rand() % 3001 + 2000; + currItem->uItemID = 199; + break; + } + currItem->SetIdentified(); + currItem->uSpecEnchantmentType = goldAmount; + } + else + { + pItemsTable->GenerateItem(resultTreasureLevel, 0, currItem); + } + v12 = 0; + while ( !(pChests[i].igChestItems[v12].uItemID==0) &&(v12<140)) + { + ++v12; + } + if (v12 >= 140) + break; + currItem=&pChests[i].igChestItems[v12]; + v11++; + } while (v11 < additionaItemCount + 1); // + 1 because it's the item at pChests[i].igChestItems[j] and the additional ones + } + else + currItem->GenerateArtifact(); + } + } + } + +} + + + + +// 4505CC: using guessed type int var_A0[32]; + //----- (004B3703) -------------------------------------------------------- +void FillAviableSkillsToTeach( int _this ) + { + const char *v30; // ecx@65 + unsigned int v29; // edx@56 + int v15; // ecx@19 + int v33; // [sp-4h] [bp-2Ch]@23 + int v34; // [sp-4h] [bp-2Ch]@43 + int v21; // ecx@34 + int v35[5]; // [sp+Ch] [bp-1Ch]@8 + int v37=0; // [sp+24h] [bp-4h]@1* + int i=0; + + dword_F8B1DC_currentShopOption = 0; + + switch (_this) + { + case 1: //shop weapon + for (int i=0; i<2; ++i) + { + for (int j=0; j<4; ++j) + { + if ( i ) + v21 = shopWeap_variation_spc[(unsigned int)window_SpeakInHouse->ptr_1C].item_class[j]; + else + v21 = shopWeap_variation_ord[(unsigned int)window_SpeakInHouse->ptr_1C].item_class[j]; + + switch (v21) + { + case 23: v34 = 37; break; + case 24: v34 = 38; break; + case 25: v34 = 39; break; + case 26: v34 = 40; break; + case 27: v34 = 41; break; + case 28: v34 = 42; break; + case 30: v34 = 36; break; + default: + continue; + } + v37 = sub_4BE571_AddItemToSet(v34, v35, v37, 5); + } + } + break; + case 2: //shop armor + + for (int i=0; i<2; ++i) + { + for (int j=0; j<2; ++j) + { + for (int k=0; k<4; ++k) + { + if ( i ) + v15 = shopArmr_variation_spc[(unsigned int)window_SpeakInHouse->ptr_1C-15+j].item_class[k]; + else + v15 = shopArmr_variation_ord[(unsigned int)window_SpeakInHouse->ptr_1C-15+j].item_class[k]; + switch (v15) + { + case 31: v33 = 45; break; + case 32: v33 = 46; break; + case 33: v33 = 47; break; + case 34: v33 = 44; break; + default: + continue; + } + v37 = sub_4BE571_AddItemToSet(v33, v35, v37, 5); + } + } + } + break; + case 3: //shop magic + v37 = 2; + v35[0] = 57; + v35[1] = 59; + break; + case 4: //shop alchemist + v37 = 2; + v35[0] = 71; + v35[1] = 68; + break; + case 21: //tavern + v37 = 3; + v35[0] = 70; + v35[1] = 65; + v35[2] = 62; + break; + case 23: //temple + v37 = 3; + v35[0] = 67; + v35[1] = 66; + v35[2] = 58; + break; + case 30: ///trainig + v37 = 2; + v35[0] = 69; + v35[1] = 60; + break; + } + for(i=0;i<v37;++i) + { + v29=v35[i]; + switch(v29) + { + case 40 :v30 = pSkillNames[4]; break; + case 5 : v30 = pSkillNames[23]; break; + case 36 :v30 = pSkillNames[0]; break; + case 37 :v30 = pSkillNames[1]; break; + case 38 :v30 = pSkillNames[2]; break; + case 39 :v30 = pSkillNames[3]; break; + case 41 :v30 = pSkillNames[5]; break; + case 42 :v30 = pSkillNames[6]; break; + case 44 :v30 = pSkillNames[8]; break; + case 45 :v30 = pSkillNames[9]; break; + case 46 :v30 = pSkillNames[10]; break; + case 47 :v30 = pSkillNames[11]; break; + case 66 :v30 = pSkillNames[30]; break; + case 57 :v30 = pSkillNames[21]; break; + case 58 :v30 = pSkillNames[22]; break; + case 60 :v30 = pSkillNames[24]; break; + case 62 :v30 = pSkillNames[26]; break; + case 65 :v30 = pSkillNames[29]; break; + case 67:v30 = pSkillNames[31]; break; + case 68:v30 = pSkillNames[32]; break; + case 69:v30 = pSkillNames[33]; break; + case 70:v30 = pSkillNames[34]; break; + case 71:v30 = pSkillNames[35]; break; + default: + v30 = pGlobalTXT_LocalizationStrings[127]; //"No Text!" + } + pShopOptions[dword_F8B1DC_currentShopOption] = const_cast<char *>(v30); + ++dword_F8B1DC_currentShopOption; + CreateButtonInColumn(i+1, v29); + } + pDialogueWindow->_41D08F_set_keyboard_control_group(i, 1, 0, 2); + dword_F8B1E0 = pDialogueWindow->pNumPresenceButton; + } + + //----- (004BE571) -------------------------------------------------------- +int sub_4BE571_AddItemToSet(int valueToAdd, int *outPutSet, int elemsAlreadyPresent, int elemsNeeded) +{ + int i; // esi@3 + + if ( elemsAlreadyPresent < elemsNeeded ) + { + for ( i = 0; i < elemsAlreadyPresent; ++i ) + { + if ( valueToAdd == outPutSet[i] ) + return elemsAlreadyPresent; + } + outPutSet[elemsAlreadyPresent] = valueToAdd; + return elemsAlreadyPresent + 1; + } + return elemsNeeded; +} +//----- (0043C91D) -------------------------------------------------------- +int GetItemTextureFilename(char *pOut, signed int item_id, int index, int shoulder) +{ + int result; // eax@2 + ITEM_EQUIP_TYPE pEquipType; + + result = 0; //BUG fn is void + pEquipType = pItemsTable->pItems[item_id].uEquipType; + if ( item_id > 500 ) + { + switch ( item_id ) + { + case ITEM_RELIC_HARECS_LEATHER: + if (byte_5111F6_OwnedArtifacts[2] != 0) + item_id = 234; + break; + case ITEM_ARTIFACT_YORUBA: + if (byte_5111F6_OwnedArtifacts[1] != 0) + item_id = 236; + break; + case ITEM_ARTIFACT_GOVERNORS_ARMOR: + if (byte_5111F6_OwnedArtifacts[0] != 0) + item_id = 235; + break; + case ITEM_ELVEN_CHAINMAIL: + if (byte_5111F6_OwnedArtifacts[16] != 0) + item_id = 73; + break; + case ITEM_ARTIFACT_LEAGUE_BOOTS: + if (byte_5111F6_OwnedArtifacts[3] != 0) + item_id = 312; + break; + case ITEM_RELIC_TALEDONS_HELM: + if (byte_5111F6_OwnedArtifacts[4] != 0) + item_id = 239; + break; + case ITEM_RELIC_SCHOLARS_CAP: + if (byte_5111F6_OwnedArtifacts[5] != 0) + item_id = 240; + break; + case ITEM_RELIC_PHYNAXIAN_CROWN: + if (byte_5111F6_OwnedArtifacts[6] != 0) + item_id = 241; + break; + case ITEM_ARTIFACT_MINDS_EYE: + if (byte_5111F6_OwnedArtifacts[7] != 0) + item_id = 93; + break; + case ITEM_RARE_SHADOWS_MASK: + if (byte_5111F6_OwnedArtifacts[8] != 0) + item_id = 344; + break; + case ITEM_RILIC_TITANS_BELT: + if (byte_5111F6_OwnedArtifacts[9] != 0) + item_id = 324; + break; + case ITEM_ARTIFACT_HEROS_BELT: + if (byte_5111F6_OwnedArtifacts[10] != 0) + item_id = 104; + break; + case ITEM_RELIC_TWILIGHT: + if (byte_5111F6_OwnedArtifacts[11] != 0) + item_id = 325; + break; + case ITEM_ARTIFACT_CLOAK_OF_THE_SHEEP: + if (byte_5111F6_OwnedArtifacts[12] != 0) + item_id = 330; + break; + case ITEM_RARE_SUN_CLOAK: + if (byte_5111F6_OwnedArtifacts[13] != 0) + item_id = 347; + break; + case ITEM_RARE_MOON_CLOAK: + if (byte_5111F6_OwnedArtifacts[14] != 0) + item_id = 348; + break; + case ITEM_RARE_VAMPIRES_CAPE: + if (byte_5111F6_OwnedArtifacts[15] != 0) + item_id = 350; + break; + default: + return 0; + } + } + + switch (pEquipType) + { + case EQUIP_ARMOUR: + if ( !shoulder ) + return sprintf(pOut, "item%3.3dv%d", item_id, index); + else if ( shoulder == 1 ) + return sprintf(pOut, "item%3.3dv%da1", item_id, index); + else if ( shoulder == 2 ) + return sprintf(pOut, "item%3.3dv%da2", item_id, index); + break; + case EQUIP_CLOAK: + if ( !shoulder ) + return sprintf(pOut, "item%3.3dv%d", item_id, index); + else + return sprintf(pOut, "item%3.3dv%da1", item_id, index); + default: + return sprintf(pOut, "item%3.3dv%d", item_id, index); + } + + result = item_id - 504; + return result; +} + + +//----- (004BDAAF) -------------------------------------------------------- +bool ItemGen::MerchandiseTest(int _2da_idx) +{ + bool test; + + if ( (p2DEvents[_2da_idx - 1].uType != 4 || (signed int)this->uItemID < 740 || (signed int)this->uItemID > 771) + && ((signed int)this->uItemID >= 600 || (signed int)this->uItemID >= 529 && (signed int)this->uItemID <= 599) || this->IsStolen()) + return false; + switch( p2DEvents[_2da_idx - 1].uType ) + { + case BuildingType_WeaponShop: + { + test = this->GetItemEquipType() <= EQUIP_BOW; + break; + } + case BuildingType_ArmorShop: + { + test = this->GetItemEquipType() >= EQUIP_ARMOUR && this->GetItemEquipType() <= EQUIP_BOOTS; + break; + } + case BuildingType_MagicShop: + { + test = this->GetPlayerSkillType() == PLAYER_SKILL_MISC || this->GetItemEquipType() == EQIUP_ANY; + break; + } + case BuildingType_AlchemistShop: + { + test = this->GetItemEquipType() == EQUIP_REAGENT || this->GetItemEquipType() == EQUIP_POTION + || (this->GetItemEquipType() > EQUIP_POTION && !(this->GetItemEquipType() != EQUIP_MESSAGE_SCROLL + || (signed int)this->uItemID < 740) && this->uItemID != 771); + break; + } + default: + { + test = false; + break; + } + } + return test; +} + +//----- (00493F79) -------------------------------------------------------- +void init_summoned_item(stru351_summoned_item *_this, __int64 duration) +{ + signed __int64 v2; // ST2C_8@1 + signed __int64 v3; // qax@1 + //signed __int64 v4; // ST1C_8@1 + unsigned __int64 v5; // qax@1 + unsigned int v6; // ebx@1 + + v2 = (signed __int64)((double)duration * 0.234375); + v3 = v2 / 60 / 60; + //v4 = v3; + v5 = (unsigned int)v3 / 0x18; + v6 = (unsigned int)(v5 / 7) >> 2; + _this->field_0_expire_second = v2 % 60; + _this->field_4_expire_minute = v2 / 60 % 60; + _this->field_8_expire_hour = v3 % 24; + _this->field_10_expire_week = v5 / 7 & 3; + _this->field_C_expire_day = (unsigned int)v5 % 0x1C; + _this->field_14_exprie_month = v6 % 0xC; + _this->field_18_expire_year = v6 / 0xC + game_starting_year; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Items.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,530 @@ +#pragma once +#include <array> +#include <map> +#include "NZIArray.h" + +enum DAMAGE_TYPE:unsigned int + { + DMGT_FIRE = 0, + DMGT_ELECTR = 1, + DMGT_COLD = 2, + DMGT_EARTH = 3, + DMGT_PHISYCAL= 4, + DMGT_MAGICAL = 5, + DMGT_SPIRIT = 6, + DMGT_MIND = 7, + DMGT_BODY = 8, + DMGT_LIGHT = 9, + DMGT_DARK =10 + }; + + + +/* 338 */ +enum ITEM_FLAGS :unsigned int +{ + ITEM_IDENTIFIED = 0x1, + ITEM_BROKEN = 0x2, + ITEM_TEMP_BONUS = 0x8, + ITEM_AURA_EFFECT_RED = 0x10, + ITEM_AURA_EFFECT_BLUE = 0x20, + ITEM_AURA_EFFECT_GREEN = 0x40, + ITEM_AURA_EFFECT_PURPLE = 0x80, + ITEM_ENCHANT_ANIMATION = 0xF0, + ITEM_STOLEN = 0x100, + ITEM_HARDENED = 0x200, +}; + + +enum ITEM_MATERIAL +{ + MATERIAL_COMMON =0, + MATERIAL_ARTEFACT = 1, + MATERIAL_RELIC = 2, + MATERIAL_SPECIAL = 3 +}; + +/* 330 */ +enum ITEM_TYPE +{ + ITEM_LONGSWORD_1 = 0x1, + ITEM_DAGGER_1 = 0xF, + ITEM_AXE_1 = 0x17, + ITEM_SPEAR_1 = 0x1F, + ITEM_CROSSBOW_1 = 0x2F, + ITEM_MACE_1 = 0x32, + ITEM_STAFF_1 = 0x3D, + ITEM_BLASTER = 64, + ITEM_LASER_RIFLE = 65, + ITEM_LEATHER_1 = 0x42, + ITEM_CHAINMAIL_1 = 0x47, + ITEM_PLATE_1 = 0x4C, + ITEM_BUCKLER_1 = 0x54, + ITEM_GAUNTLETS_1 = 0x6E, + ITEM_BOOTS_1 = 0x73, + ITEM_WAND_FIRE = 135, + ITEM_WAND_STUN = 138, + ITEM_WAND_INCENERATION = 0x9F, + ITEM_REAGENT_WIDOWSWEEP_BERRIES = 200, + ITEM_TROLL_BLOOD = 0xCA, + ITEM_DRAGON_EYE = 0xCC, + ITEM_HARPY_FEATHER = 0xCF, + ITEM_DEVIL_ICHOR = 0xD6, + ITEM_OOZE_ECTOPLASM_BOTTLE = 0xD9, + ITEM_REAGENT_PHILOSOPHERS_STONE = 219, + ITEM_POTION_BOTTLE = 220, + ITEM_POTION_CATALYST = 221, + ITEM_POTION_CURE_WOUNDS = 222, + ITEM_POTION_CURE_DISEASE = 225, + ITEM_POTION_AWAKEN = 227, + ITEM_POTION_HASTE = 228, + ITEM_POTION_RECHARGE_ITEM = 233, + ITEM_POTION_HARDEN_ITEM = 236, + ITEM_POTION_CURE_INSANITY = 239, + ITEM_POTION_MIGHT_BOOST = 240, + ITEM_POTION_ACCURACY_BOOST = 245, + ITEM_POTION_FLAMING_POTION = 246, + ITEM_POTION_SWIFT_POTION = 250, + ITEM_POTION_BODY_RESISTANE = 261, + ITEM_POTION_STONE_TO_FLESH = 262, + ITEM_POTION_SLAYING_POTION = 263, + ITEM_POTION_REJUVENATION = 271, + ITEM_SPELLBOOK_TORCHLIGHT = 400,//0x190 + ITEM_SPELLBOOK_FIRE_STRIKE = 401,//0x191, + ITEM_SPELLBOOK_AIR_FEATHER_FALL = 0x19C, + ITEM_SPELLBOOK_WATER_POISON_SPRAY = 0x1A7, + ITEM_SPELLBOOK_EARTH_SLOW = 0x1B2, + ITEM_SPELLBOOK_SPIRIT_BLESS = 0x1BD, + ITEM_SPELLBOOK_MIND_MIND_BLAST = 0x1C8, + ITEM_SPELLBOOK_BODY_FIRST_AID = 0x1D3, + ITEM_SPELLBOOK_BODY_HEAL = 0x1D6, + ITEM_SPELLBOOK_BODY_BREAK_POISON = 0x1D7, + ITEM_SPELLBOOK_LIGHT_LIGHT_BOLT = 0x1DD, + ITEM_SPELLBOOK_LIGHT_SUN_BURST = 0x1E6, + ITEM_SPELLBOOK_LIGHT_DIVINE_INTERVENTION = 0x1E7, + ITEM_ARTIFACT_PUCK = 500,//0x1F4, + ITEM_ARTIFACT_IRON_FEATHER = 501, + ITEM_ARTIFACT_WALLACE = 502, + ITEM_ARTIFACT_CORSAIR = 503, + ITEM_ARTIFACT_GOVERNORS_ARMOR = 504,//1F8 + ITEM_ARTIFACT_YORUBA = 505,//1F9 + ITEM_ARTIFACT_SPLITTER = 506,//1FA + ITEM_ARTIFACT_GHOULSBANE = 507,//1FA + ITEM_ARTIFACT_GIBBET = 508,//1FA + ITEM_ARTIFACT_CHARELE = 509,//1FA + ITEM_ARTEFACT_ULLYSES =510, + ITEM_ARTEFACT_HANDS_OF_THE_MASTER =511, + ITEM_ARTIFACT_LEAGUE_BOOTS = 512,//200 + ITEM_ARTIFACT_RULERS_RING = 513, + ITEM_RELIC_MASH = 514, + ITEM_RELIC_ETHRICS_STAFF = 515,//204 + ITEM_RELIC_HARECS_LEATHER = 516,//204 + ITEM_RELIC_OLD_NICK = 517, + ITEM_RELIC_AMUCK = 518, + ITEM_RELIC_GLORY_SHIELD = 519, + ITEM_RELIC_KELEBRIM = 520,//208 + ITEM_RELIC_TALEDONS_HELM = 521,//209 + ITEM_RELIC_SCHOLARS_CAP = 522,//20A + ITEM_RELIC_PHYNAXIAN_CROWN = 523,//20B + ITEM_RILIC_TITANS_BELT = 524,//20C + ITEM_RELIC_TWILIGHT = 525,//20D + ITEM_RELIC_ANIA_SELVING = 526, + ITEM_RELIC_JUSTICE = 527, + ITEM_RELIC_MEKORIGS_HAMMER = 528, + ITEM_ARTIFACT_HERMES_SANDALS = 529, + ITEM_ARTIFACT_CLOAK_OF_THE_SHEEP = 530,//212 + ITEM_ARTIFACT_ELFBANE = 531,//212 + ITEM_ARTIFACT_MINDS_EYE = 532,//214 + ITEM_ELVEN_CHAINMAIL = 533,//215 + ITEM_FORGE_GAUNTLETS = 534, + ITEM_ARTIFACT_HEROS_BELT = 535,//217 + ITEM_ARTIFACT_LADYS_ESCORT = 536, + ITEM_RARE_CLANKERS_AMULET = 537, + ITEM_RARE_LIETENANTS_CUTLASS = 538, + ITEM_RARE_MEDUSAS_MIRROR = 539, + ITEM_RARE_LADY_CARMINES_DAGGER = 540, + ITEM_RARE_VILLAINS_BLADE = 541, + ITEM_RARE_PERFECT_BOW = 542, + ITEM_RARE_PERFECT_BOW_FIXED = 543, + ITEM_RARE_SHADOWS_MASK = 544,//220 + ITEM_RARE_GHOST_RING = 545,//220 + ITEM_RARE_FAERIE_RING = 546,//220 + ITEM_RARE_SUN_CLOAK = 547,//223 + ITEM_RARE_MOON_CLOAK = 548,//224 + ITEM_RARE_ZOKKARS_AXE = 549,//224 + ITEM_RARE_VAMPIRES_CAPE = 550,//226 + ITEM_RARE_MINOTAURS_AXE = 551,//226 + ITEM_RARE_GROGNARDS_CUTLASS = 552,//226 + ITEM_LICH_JAR_FULL = 601, + ITEM_WETSUIT = 604, + ITEM_LICH_JAR_EMPTY = 615, + ITEM_RECIPE_REJUVENATION = 740, + ITEM_RECIPE_BODY_RESISTANCE = 771, +}; + +/* 331 */ +enum ITEM_EQUIP_TYPE: unsigned __int8 +{ + EQUIP_SINGLE_HANDED = 0, + EQUIP_TWO_HANDED = 1, + EQUIP_BOW = 2, + EQUIP_ARMOUR = 3, + EQUIP_SHIELD = 4, + EQUIP_HELMET = 5, + EQUIP_BELT = 6, + EQUIP_CLOAK = 7, + EQUIP_GAUNTLETS = 8, + EQUIP_BOOTS = 9, + EQUIP_RING = 10, + EQUIP_AMULET = 11, + EQUIP_WAND = 12, + EQUIP_REAGENT = 13, + EQUIP_POTION = 14, + EQUIP_SPELL_SCROLL = 15, + EQUIP_BOOK = 16, + EQIUP_ANY = 16, + EQUIP_MESSAGE_SCROLL = 17, + EQUIP_GOLD = 18, + EQUIP_GEM = 19, + EQUIP_NONE = 20 +}; + +enum CHARACTER_ATTRIBUTE_TYPE; +struct Player; + +typedef struct CEnchantment +{ + unsigned __int16 Player::* statPtr; + int statBonus; + CEnchantment(int bonus, unsigned __int16 Player::* skillPtr = nullptr): + statBonus(bonus), + statPtr(skillPtr) + { + } +} CEnchantment; + +/* 64 */ +#pragma pack(push, 1) +struct ItemGen //0x24 +{ + //----- (0042EB25) -------------------------------------------------------- + // inline ItemGen() + // { + // Reset(); + // } + static void AddToMap(std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* > &maptoadd, + int enchId, + CHARACTER_ATTRIBUTE_TYPE attrId, + int bonusValue = 0, + unsigned __int16 Player::* skillPtr = nullptr); + + static std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* > regularBonusMap; + static std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* > specialBonusMap; + static std::map<int, std::map<CHARACTER_ATTRIBUTE_TYPE, CEnchantment*>* > artifactBonusMap; + + static void PopulateSpecialBonusMap(); + static void PopulateRegularBonusMap(); + static void PopulateArtifactBonusMap(); + static void ClearItemBonusMaps(); + + inline void ResetEnchantAnimation(){uAttributes &= 0xFFFFFF0F;} + inline bool ItemEnchanted()const {return(uAttributes & ITEM_ENCHANT_ANIMATION) != 0;} + inline bool AuraEffectRed()const {return(uAttributes & ITEM_ENCHANT_ANIMATION) == ITEM_AURA_EFFECT_RED;} + inline bool AuraEffectBlue()const {return(uAttributes & ITEM_ENCHANT_ANIMATION) == ITEM_AURA_EFFECT_BLUE;} + inline bool AuraEffectGreen()const {return(uAttributes & ITEM_ENCHANT_ANIMATION) == ITEM_AURA_EFFECT_GREEN;} + inline bool AuraEffectPurple()const {return(uAttributes & ITEM_ENCHANT_ANIMATION) == ITEM_AURA_EFFECT_PURPLE;} + + void GetItemBonusSpecialEnchantment(Player* owner, CHARACTER_ATTRIBUTE_TYPE attrToGet, int* additiveBonus, int* halfSkillBonus); + void GetItemBonusArtifact(Player* owner, CHARACTER_ATTRIBUTE_TYPE attrToGet, int* bonusSum); + bool IsRegularEnchanmentForAttribute(CHARACTER_ATTRIBUTE_TYPE attrToGet); + + inline bool IsBroken() {return (uAttributes & ITEM_BROKEN) != 0;} + inline void SetBroken() {uAttributes |= ITEM_BROKEN;} + inline bool IsIdentified() {return (uAttributes & ITEM_IDENTIFIED) != 0;} + inline void SetIdentified() {uAttributes |= ITEM_IDENTIFIED;} + inline bool IsStolen() {return (uAttributes & ITEM_STOLEN) != 0;} + inline void SetStolen() {uAttributes |= ITEM_STOLEN;} + + bool GenerateArtifact(); + unsigned int GetValue(); + const char *GetDisplayName(); + const char *GetIdentifiedName(); + void UpdateTempBonus(__int64 uTimePlayed); + void Reset(); + int _439DF3_get_additional_damage(int *a2, bool *vampiyr); + + ITEM_EQUIP_TYPE GetItemEquipType(); + unsigned char GetPlayerSkillType(); + char* GetIconName(); + unsigned __int8 GetDamageDice(); + unsigned __int8 GetDamageRoll(); + unsigned __int8 GetDamageMod(); + bool MerchandiseTest(int _2da_idx); + int uItemID; //0 + int uEnchantmentType; //4 + int m_enchantmentStrength; //8 + int uSpecEnchantmentType; // 25 +5 levels //0c + // 16 Drain Hit Points from target. + // 35 Increases chance of disarming. + // 39 Double damage vs Demons. + // 40 Double damage vs Dragons + // 45 +5 Speed and Accuracy + // 56 +5 Might and Endurance. + // 57 +5 Intellect and Personality. + // 58 Increased Value. + // 60 +3 Unarmed and Dodging skills + // 61 +3 Stealing and Disarm skills. + // 59 Increased Weapon speed. + // 63 Double Damage vs. Elves. + // 64 Double Damage vs. Undead. + // 67 Adds 5 points of Body damage and +2 Disarm skill. + // 68 Adds 6-8 points of Cold damage and +5 Armor Class. + // 71 Prevents drowning damage. + // 72 Prevents falling damage. + int uNumCharges; //10 + unsigned int uAttributes; //14 + unsigned __int8 uBodyAnchor; //18 + char uMaxCharges; //19 + char uHolderPlayer; //1A + char field_1B; //1B + unsigned __int64 uExpireTime; //1C +}; +#pragma pack(pop) + + + +/* 175 */ +#pragma pack(push, 1) +struct ItemDesc //30h + { //Item # |Pic File|Name|Value|Equip Stat|Skill Group|Mod1|Mod2|material| + ///ID/Rep/St|Not identified name|Sprite Index|VarA|VarB|Equip X|Equip Y|Notes + char *pIconName; //0 4 + char *pName; //4 8 + char *pUnidentifiedName; //8 c + char *pDescription; //0c 10 + unsigned int uValue; //10 14 + unsigned __int16 uSpriteID; //14 18 + __int16 field_1A; //16 + signed __int16 uEquipX; //18 1c + signed __int16 uEquipY; //1a 1e + ITEM_EQUIP_TYPE uEquipType; //1c 20 + unsigned __int8 uSkillType; //1d 21 + unsigned __int8 uDamageDice; //1e 22 + unsigned __int8 uDamageRoll; //1f 23 + unsigned __int8 uDamageMod; //20 24 + unsigned __int8 uMaterial; //21 25 + char _additional_value; //22 26 + char _bonus_type; //23 27 + char _bonus_strength; //24 28 + char field_25; // 25 29 + char field_26; //26 2A + char field_27; // 27 2b + union + { + unsigned __int8 uChanceByTreasureLvl[6]; + struct { + unsigned __int8 uChanceByTreasureLvl1; // 28 2c + unsigned __int8 uChanceByTreasureLvl2; // 29 2d + unsigned __int8 uChanceByTreasureLvl3; // 2A 2e + unsigned __int8 uChanceByTreasureLvl4; // 2B 2f + unsigned __int8 uChanceByTreasureLvl5; // 2C 30 + unsigned __int8 uChanceByTreasureLvl6; // 2D 32 + }; + }; + unsigned char uItemID_Rep_St; //2e 32 + char field_2f; +}; +#pragma pack(pop) + + + +/* 177 */ +#pragma pack(push, 1) +struct ItemEnchantment + { //Bonus|Sta|Of Name|Arm|Shld|Helm|Belt|Cape|Gaunt|Boot|Ring|Amul + char *pBonusStat; + char *pOfName; +/* union{ + struct { + unsigned char to_arm; + unsigned char to_shld; + unsigned char to_helm; + unsigned char to_belt; + unsigned char to_cape; + unsigned char to_gaunt; + unsigned char to_boot; + unsigned char to_ring; + unsigned char to_amul; + }; */ + unsigned char to_item[12]; + // }; + }; +#pragma pack(pop) + +/* 178 */ +#pragma pack(push, 1) +struct ItemSpecialEnchantment //1Ch +{ //Bonus Stat|Name Add|W1|W2|Miss|Arm|Shld|Helm|Belt|Cape|Gaunt|Boot|Ring|Amul|Value|Lvl|Description fo special Bonuses and values + + char *pBonusStatement; //0 + char *pNameAdd; //4 + char to_item_apply[12]; //8 + int iValue; //14 + int iTreasureLevel; //18 +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct BonusRange +{ + unsigned int minR; + unsigned int maxR; +}; +#pragma pack(pop) + +/* 176 */ +#pragma pack(push, 1) +struct ItemsTable +{ + void Initialize(); + void LoadPotions(); + void LoadPotionNotes(); + void GenerateItem(int treasure_level, unsigned int uTreasureType, ItemGen *pItem); + void SetSpecialBonus(ItemGen *pItem); + bool IsMaterialSpecial(ItemGen *pItem); + bool IsMaterialNonCommon(ItemGen *pItem); + void Release(); + + int uAllItemsCount; + NZIArray<ItemDesc, 800> pItems; //4-9604h + ItemEnchantment pEnchantments[24]; //9604h + ItemSpecialEnchantment pSpecialEnchantments[72]; //97E4h -9FC4h + char field_9FC4[5000]; + char field_B348[5000]; + char field_C6D0[5000]; + char field_DA58[5000]; + char field_EDE0[384]; + unsigned __int16 potion_data[50][50]; // 77B2h*2=EF64h -102ECh + unsigned __int16 potion_note[50][50]; // 8176h*2=102ECh -11674h + char *pItemsTXT_Raw; //11674h + char *pRndItemsTXT_Raw; + char *pStdItemsTXT_Raw; //1167Ch + char *pSpcItemsTXT_Raw; //11680h + unsigned int uChanceByTreasureLvlSumm[6]; //11684 + unsigned int uBonusChanceStandart[6]; //1169c + unsigned int uBonusChanceSpecial[6]; //116B4 + unsigned int uBonusChanceWpSpecial[6]; //116cc -116e4 + unsigned int pEnchantmentsSumm[9]; //116E4h -11708h + BonusRange bonus_ranges[6]; //45C2h*4 =11708h + unsigned int pSpecialEnchantmentsSumm[24]; //11738h + unsigned int pSpecialEnchantments_count; //11798h + char field_1179C; + char field_1179D; + char field_1179E; + char field_1179F; +}; +#pragma pack(pop) + +void GenerateStandartShopItems(); +void GenerateSpecialShopItems(); +void GenerateItemsInChest(); + +extern std::array<const char, 5> uItemsAmountPerShopType; // weak +extern ItemGen *ptr_50C9A4_ItemToEnchant; + +extern struct ItemsTable *pItemsTable; + +/* ++10 to all Resistances. 1 + +10 to all Seven Statistics. 2 + Explosive Impact! 3 + Adds 3-4 points of Cold damage. 4 + Adds 6-8 points of Cold damage. 5 + Adds 9-12 points of Cold damage. 6 + Adds 2-5 points of Electrical damage. 7 + Adds 4-10 points of Electrical damage. 8 + Adds 6-15 points of Electrical damage. 9 + Adds 1-6 points of Fire damage. 10 + Adds 2-12 points of Fire damage. 11 + Adds 3-18 points of Fire damage. 12 + Adds 5 points of Body damage. 13 + Adds 8 points of Body damage. 14 + Adds 12 points of Body damage. 15 + Drain Hit Points from target. 16 + Increases rate of Recovery. 17 + Wearer resistant to Diseases. 18 + Wearer resistant to Insanity. 19 + Wearer resistant to Paralysis. 20 + Wearer resistant to Poison. 21 + Wearer resistant to Sleep. 22 + Wearer resistant to Stone. 23 + Increased Knockback. 24 + +5 Level. 25 + Increases effect of all Air spells. 26 + Increases effect of all Body spells. 27 + Increases effect of all Dark spells. 28 + Increases effect of all Earth spells. 29 + Increases effect of all Fire spells. 30 + Increases effect of all Light spells. 31 + Increases effect of all Mind spells. 32 + Increases effect of all Spirit spells. 33 + Increases effect of all Water spells. 34 + Increases chance of Disarming. 35 + Half damage from all missile attacks. 36 + Regenerate Hit points over time. 37 + Regenerate Spell points over time. 38 + Double damage vs Demons. 39 + Double damage vs Dragons 40 + Drain Hit Points from target and Increased Weapon speed. 41 + +1 to Seven Stats, HP, SP, Armor, Resistances. 42 + +10 to Endurance, Armor, Hit points. 43 + +10 Hit points and Regenerate Hit points over time. 44 + +5 Speed and Accuracy. 45 + Adds 10-20 points of Fire damage and +25 Might. 46 + +10 Spell points and Regenerate Spell points over time. 47 + +15 Endurance and +5 Armor. 48 + +10 Intellect and Luck. 49 + +30 Fire Resistance and Regenerate Hit points over time. 50 + +10 Spell points, Speed, Intellect. 51 + +10 Endurance and Accuracy. 52 + +10 Might and Personality. 53 + +15 Endurance and Regenerate Hit points over time. 54 + +15 Luck and Regenerate Spell points over time. 55 + +5 Might and Endurance. 56 + +5 Intellect and Personality. 57 + Increased Value. 58 + Increased Weapon speed. 59 + +3 Unarmed and Dodging skills. 60 + +3 Stealing and Disarm skills. 61 + +3 ID Item and ID Monster skills. 62 + Double Damage vs. Elves. 63 + Double Damage vs. Undead. 64 + Double Damage vs. Titans. 65 + Regenerate Spell points and Hit points over time. 66 + Adds 5 points of Body damage and +2 Disarm skill. 67 + Adds 6-8 points of Cold damage and +5 Armor Class. 68 + +20 Air Resistance and Shielding. 69 + +10 Water Resistance and +2 Alchemy skill. 70 + Prevents damage from drowning. 71 + Prevents damage from falling. 72 +*/ + + +/* 391 */ +#pragma pack(push, 1) +struct stru351_summoned_item +{ + int field_0_expire_second; + int field_4_expire_minute; + int field_8_expire_hour; + int field_C_expire_day; + int field_10_expire_week; + int field_14_exprie_month; + int field_18_expire_year; +}; +#pragma pack(pop) + + +int GetItemTextureFilename(char *pOut, signed int item_id, int index, int shoulder); +void FillAviableSkillsToTeach(int _this); +void init_summoned_item(struct stru351_summoned_item *_this, __int64 duration);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Monsters.cpp Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,1245 @@ +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> + +#define _CRT_SECURE_NO_WARNINGS +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "ErrorHandling.h" + +#include "Monsters.h" +#include "FrameTableInc.h" +#include "LOD.h" +#include "texts.h" +#include "mm7_data.h" + + + + + +struct MonsterStats *pMonsterStats; +struct MonsterList *pMonsterList; + +unsigned int ParseSpellType(struct FrameTableTxtLine* tbl, int* next_token); + +int ParseAttackType(const char *damage_type_str); +void ParseDamage( char *damage_str, unsigned __int8* dice_rolls, unsigned __int8* dice_sides, unsigned __int8* dmg_bonus ); +int ParseMissleAttackType(const char *missle_attack_str); +int ParseSpecialAttack(const char *spec_att_str); + +//----- (004548E2) -------------------------------------------------------- +unsigned int ParseSpellType( struct FrameTableTxtLine * tbl, int* next_token ) + { + + if (!tbl->pProperties[0] ) + { + ++*next_token; + return 0; + } + if ( !_stricmp(tbl->pProperties[0], "Dispel") ) //dispel magic + { + ++*next_token; + return 80; + } + else if ( !_stricmp(tbl->pProperties[0], "Day") ) //day of protection + { + *next_token+=2;; + return 85; + } + else if ( !_stricmp(tbl->pProperties[0], "Hour") ) //hour of power + { + *next_token+=2;; + return 86; + } + else if ( !_stricmp(tbl->pProperties[0], "Shield") ) + return 17; + else if ( !_stricmp(tbl->pProperties[0], "Spirit") ) + { + ++*next_token; + return 52; + } + else if ( !_stricmp(tbl->pProperties[0], "Power") ) //power cure + { + ++*next_token; + return 77; + } + else if ( !_stricmp(tbl->pProperties[0], "Meteor") ) //meteot shower + { + ++*next_token; + return 9; + } + else if ( !_stricmp(tbl->pProperties[0], "Lightning") ) //Lightning bolt + { + ++*next_token; + return 18; + } + else if ( !_stricmp(tbl->pProperties[0], "Implosion") ) + return 20; + else if ( !_stricmp(tbl->pProperties[0], "Stone") ) + { + ++*next_token; + return 38; + } + else if ( !_stricmp(tbl->pProperties[0], "Haste") ) + return 5; + else if ( !_stricmp(tbl->pProperties[0], "Heroism") ) + return 51; + else if ( !_stricmp(tbl->pProperties[0], "Pain") ) //pain reflection + { + ++*next_token; + return 95; + } + else if ( !_stricmp(tbl->pProperties[0], "Sparks") ) + return 15; + else if ( !_stricmp(tbl->pProperties[0], "Light") ) + { + ++*next_token; + return 78; + } + else if ( !_stricmp(tbl->pProperties[0], "Toxic") ) //toxic cloud + { + ++*next_token; + return 90; + } + else if ( !_stricmp(tbl->pProperties[0], "ShrapMetal") ) + return 93; + else if ( !_stricmp(tbl->pProperties[0], "Paralyze") ) + return 81; + else if ( !_stricmp(tbl->pProperties[0], "Fireball") ) + return 6; + else if ( !_stricmp(tbl->pProperties[0], "Incinerate") ) + return 11; + else if ( !_stricmp(tbl->pProperties[0], "Fire") ) + { + ++*next_token; + return 2; + } + else if ( !_stricmp(tbl->pProperties[0], "Rock") ) + { + ++*next_token; + return 41; + } + else if ( !_stricmp(tbl->pProperties[0], "Mass") ) + { + ++*next_token; + return 44; + } + else if ( !_stricmp(tbl->pProperties[0], "Ice") ) + { + ++*next_token; + return 26; + } + else if ( !_stricmp(tbl->pProperties[0], "Acid") ) + { + ++*next_token; + return 29; + } + else if ( !_stricmp(tbl->pProperties[0], "Bless") ) + return 46; + else if ( !_stricmp(tbl->pProperties[0], "Dragon") ) + { + ++*next_token; + return 97; + } + else if ( !_stricmp(tbl->pProperties[0], "Reanimate") ) + return 89; + else if ( !_stricmp(tbl->pProperties[0], "Summon") ) + { + ++*next_token; + return 82; + } + else if ( !_stricmp(tbl->pProperties[0], "Fate") ) + return 47; + else if ( !_stricmp(tbl->pProperties[0], "Harm") ) + return 70; + else if ( !_stricmp(tbl->pProperties[0], "Mind") ) + { + ++*next_token; + return 57; + } + else if ( !_stricmp(tbl->pProperties[0], "Blades") ) + return 39; + else if ( !_stricmp(tbl->pProperties[0], "Psychic") ) + { + ++*next_token; + return 65; + } + else if ( !_stricmp(tbl->pProperties[0], "Hammerhands") ) + return 73; + else + { + sprintf(pTmpBuf.data(), "Unknown monster spell %s", tbl->pProperties[0]); + MessageBoxA(nullptr, pTmpBuf.data(), "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Itemdata.cpp:1562", 0); + ++*next_token; + return 0; + } + } + +//----- (00454CB4) -------------------------------------------------------- +int ParseAttackType( const char *damage_type_str ) + { + + switch (tolower(*damage_type_str)) + { + case 'f': return 0; //fire + case 'a': return 1; //air + case 'w': return 2; //water + case 'e': return 3; //earth + + case 's': return 6; //spirit + case 'm': return 7; //mind + //m ?? 8 + case 'l': return 9; //light + case 'd': return 10; //dark + // d?? 11 + } + return 4; //phis + + } + +//----- (00454D7D) -------------------------------------------------------- +void ParseDamage( char *damage_str, unsigned __int8* dice_rolls, unsigned __int8* dice_sides, unsigned __int8* dmg_bonus ) + { + int str_len=0; + int str_pos=0; + bool dice_flag=false; + + *dice_rolls = 0; + *dice_sides = 1; + *dmg_bonus = 0; + + str_len = strlen(damage_str); + if (str_len<=0) + return; + for (str_pos=0;str_pos<str_len;++str_pos ) + { + if (tolower(damage_str[str_pos])=='d') + { + damage_str[str_pos]='\0'; + *dice_rolls=atoi(damage_str); + *dice_sides=atoi(&damage_str[str_pos+1]); + dice_flag=true; + damage_str[str_pos]='d'; + } + else if (tolower(damage_str[str_pos])=='+') + *dmg_bonus=atoi(&damage_str[str_pos+1]); + } + if (!dice_flag) + { + if ((*damage_str>='0')&&(*damage_str<='9')) + { + *dice_rolls =atoi(damage_str); + *dice_sides = 1; + } + } + } + +//----- (00454E3A) -------------------------------------------------------- +int ParseMissleAttackType(const char *missle_attack_str) + { + if ( !_stricmp(missle_attack_str, "ARROW") ) + return 1; + else if ( !_stricmp(missle_attack_str, "ARROWF") ) + return 2; + else if ( !_stricmp(missle_attack_str, "FIRE") ) + return 3; + else if ( !_stricmp(missle_attack_str, "AIR") ) + return 4; + else if ( !_stricmp(missle_attack_str, "WATER") ) + return 5; + else if ( !_stricmp(missle_attack_str, "EARTH") ) + return 6; + else if ( !_stricmp(missle_attack_str, "SPIRIT") ) + return 7; + else if ( !_stricmp(missle_attack_str, "MIND") ) + return 8; + else if ( !_stricmp(missle_attack_str, "BODY") ) + return 9; + else if ( !_stricmp(missle_attack_str, "LIGHT") ) + return 10; + else if ( !_stricmp(missle_attack_str, "DARK") ) + return 11; + else if ( !_stricmp(missle_attack_str, "ENER") ) + return 13; + else return 0; + } + + +int ParseSpecialAttack(char *spec_att_str) + { + _strlwr(spec_att_str); + if ( strstr(spec_att_str, "curse") ) + return 1; + else if ( strstr(spec_att_str, "weak") ) + return 2; + else if ( strstr(spec_att_str, "asleep") ) + return 3; + else if ( strstr(spec_att_str, "afraid") ) + return 23; + else if ( strstr(spec_att_str, "drunk") ) + return 4; + else if ( strstr(spec_att_str, "insane") ) + return 5; + else if ( strstr(spec_att_str, "poison weak") ) + return 6; + else if ( strstr(spec_att_str, "poison medium") ) + return 7; + else if ( strstr(spec_att_str, "poison severe") ) + return 8; + else if ( strstr(spec_att_str, "disease weak") ) + return 9; + else if ( strstr(spec_att_str, "disease medium") ) + return 10; + else if ( strstr(spec_att_str, "disease severe") ) + return 11; + else if ( strstr(spec_att_str, "paralyze") ) + return 12; + else if ( strstr(spec_att_str, "uncon") ) + return 13; + else if ( strstr(spec_att_str, "dead") ) + return 14; + else if ( strstr(spec_att_str, "stone") ) + return 15; + else if ( strstr(spec_att_str, "errad") ) + return 16; + else if ( strstr(spec_att_str, "brkitem") ) + return 17; + else if ( strstr(spec_att_str, "brkarmor") ) + return 18; + else if ( strstr(spec_att_str, "brkweapon") ) + return 19; + else if ( strstr(spec_att_str, "steal") ) + return 20; + else if ( strstr(spec_att_str, "age") ) + return 21; + else if ( strstr(spec_att_str, "drainsp") ) + return 22; + else return 0; + } + +//----- (004598FC) -------------------------------------------------------- +bool MonsterList::FromFileTxt(const char *Args) +{ + MonsterList *v2; // ebx@1 + FILE *v3; // eax@1 + unsigned int v4; // esi@3 + void *v5; // eax@9 + FILE *v6; // ST14_4@11 + char *i; // eax@11 + signed int v8; // esi@12 + unsigned __int16 v9; // ax@16 + const char *v10; // ST18_4@16 + unsigned __int16 v11; // ax@16 + const char *v12; // ST14_4@16 + unsigned __int16 v13; // ax@16 + const char *v14; // ST10_4@16 + __int16 v15; // ax@16 + const char *v16; // ST0C_4@16 + int v17; // esi@16 + unsigned __int8 v18; // al@16 + signed int v19; // esi@16 + unsigned __int16 v20; // ax@17 + int v21; // ecx@17 + char Buf; // [sp+4h] [bp-304h]@3 + FrameTableTxtLine v24; // [sp+1F8h] [bp-110h]@4 + FrameTableTxtLine v25; // [sp+274h] [bp-94h]@4 + int v26; // [sp+2F0h] [bp-18h]@16 + char v27; // [sp+2F4h] [bp-14h]@14 + char v28; // [sp+2F5h] [bp-13h]@14 + char v29; // [sp+2F6h] [bp-12h]@14 + char v30; // [sp+2F7h] [bp-11h]@14 + char v31; // [sp+2F8h] [bp-10h]@14 + char v32; // [sp+2F9h] [bp-Fh]@14 + char v33; // [sp+2FAh] [bp-Eh]@14 + char v34; // [sp+2FBh] [bp-Dh]@14 + char v35; // [sp+2FCh] [bp-Ch]@14 + char v36; // [sp+2FDh] [bp-Bh]@14 + char v37; // [sp+2FEh] [bp-Ah]@14 + char v38; // [sp+2FFh] [bp-9h]@14 + char v39; // [sp+300h] [bp-8h]@14 + char v40; // [sp+301h] [bp-7h]@14 + char v41; // [sp+302h] [bp-6h]@14 + char v42; // [sp+303h] [bp-5h]@14 + FILE *File; // [sp+304h] [bp-4h]@1 + unsigned int Argsa; // [sp+310h] [bp+8h]@3 + int Argsb; // [sp+310h] [bp+8h]@16 + + v2 = this; + v3 = fopen(Args, "r"); + File = v3; + if ( !v3 ) + Error("MonsterRaceListStruct::load - Unable to open file: %s."); + + v4 = 0; + Argsa = 0; + if ( fgets(&Buf, 490, v3) ) + { + do + { + *strchr(&Buf, 10) = 0; + memcpy(&v25, frame_table_txt_parser(&Buf, &v24), sizeof(v25)); + if ( v25.uPropCount && *v25.pProperties[0] != 47 ) + ++Argsa; + } + while ( fgets(&Buf, 490, File) ); + v4 = Argsa; + } + v2->uNumMonsters = v4; + v5 = malloc(152 * v4); + v2->pMonsters = (MonsterDesc *)v5; + if ( !v5 ) + Error("MonsterRaceListStruct::load - Out of Memory!"); + + v6 = File; + v2->uNumMonsters = 0; + fseek(v6, 0, 0); + for ( i = fgets(&Buf, 490, File); i; i = fgets(&Buf, 490, File) ) + { + *strchr(&Buf, 10) = 0; + memcpy(&v25, frame_table_txt_parser(&Buf, &v24), sizeof(v25)); + v8 = 0; + if ( v25.uPropCount && *v25.pProperties[0] != 47 ) + { + strcpy(v2->pMonsters[v2->uNumMonsters].pMonsterName, v25.pProperties[0]); + v35 = 0; + v36 = 1; + v37 = 7; + v38 = 2; + v39 = 3; + v40 = 4; + v41 = 5; + v42 = 6; + v27 = 1; + v28 = 2; + v29 = 3; + v30 = 4; + v31 = 4; + v32 = 5; + v33 = 6; + v34 = 7; + do + { + strcpy( + v2->pMonsters[v2->uNumMonsters].pSpriteNames[(unsigned __int8)*(&v35 + v8)], + v25.pProperties[(unsigned __int8)*(&v27 + v8)]); + ++v8; + } + while ( v8 < 8 ); + v9 = atoi(v25.pProperties[8]); + v10 = v25.pProperties[9]; + v2->pMonsters[v2->uNumMonsters].uMonsterHeight = v9; + v11 = atoi(v10); + v12 = v25.pProperties[10]; + v2->pMonsters[v2->uNumMonsters].uMovementSpeed = v11; + v13 = atoi(v12); + v14 = v25.pProperties[11]; + v2->pMonsters[v2->uNumMonsters].uMonsterRadius = v13; + v15 = atoi(v14); + v16 = v25.pProperties[12]; + v2->pMonsters[v2->uNumMonsters].uToHitRadius = v15; + v17 = (unsigned __int8)atoi(v16); + Argsb = atoi(v25.pProperties[13]) & 0xFF; + v26 = atoi(v25.pProperties[14]) & 0xFF; + v18 = atoi(v25.pProperties[15]); + v2->pMonsters[v2->uNumMonsters].sTintColor = v18 | ((v26 | ((Argsb | (v17 << 8)) << 8)) << 8); + v19 = 0; + do + { + v20 = atoi(v25.pProperties[v19 + 16]); + v21 = v19++ ; + v2->pMonsters[v2->uNumMonsters].pSoundSampleIDs[v21] = v20; + } + while ( v19 < 4 ); + ++v2->uNumMonsters; + } + } + fclose(File); + return 1; +} + +//----- (004598AF) -------------------------------------------------------- +void MonsterList::FromFile(void *data_mm6, void *data_mm7, void *data_mm8) +{ + uint num_mm6_monsters = data_mm6 ? *(int *)data_mm6 : 0, + num_mm7_monsters = data_mm7 ? *(int *)data_mm7 : 0, + num_mm8_monsters = data_mm8 ? *(int *)data_mm8 : 0; + + uNumMonsters = num_mm6_monsters + num_mm7_monsters + num_mm8_monsters; + Assert(uNumMonsters); + Assert(!num_mm8_monsters); + + pMonsters = (MonsterDesc *)malloc(sizeof(MonsterDesc) * uNumMonsters); + memcpy(pMonsters, (char *)data_mm7 + 4, num_mm7_monsters * sizeof(MonsterDesc)); + for (uint i = 0; i < num_mm6_monsters; ++i) + { + auto src = (MonsterDesc_mm6 *)((char *)data_mm6 + 4) + i; + MonsterDesc* dst = &pMonsters[num_mm7_monsters + i]; + + dst->uMonsterHeight = src->uMonsterHeight; + dst->uMonsterRadius = src->uMonsterRadius; + dst->uMovementSpeed = src->uMovementSpeed; + dst->uToHitRadius = src->uToHitRadius; + dst->sTintColor = -1; + memcpy(dst->pSoundSampleIDs, src->pSoundSampleIDs, sizeof(src->pSoundSampleIDs)); + memcpy(dst->pMonsterName, src->pMonsterName, sizeof(src->pMonsterName)); + memcpy(dst->pSpriteNames, src->pSpriteNames, sizeof(src->pSpriteNames)); + } + memcpy(pMonsters + num_mm6_monsters + num_mm7_monsters, (char *)data_mm8 + 4, num_mm8_monsters * sizeof(MonsterDesc)); +} + +//----- (00459860) -------------------------------------------------------- +void MonsterList::ToFile() +{ + MonsterList *v1; // esi@1 + FILE *v2; // eax@1 + FILE *v3; // edi@1 + + v1 = this; + v2 = fopen("data\\dmonlist.bin", "wb"); + v3 = v2; + if ( !v2 ) + Error("Unable to save dmonlist.bin!"); + fwrite(v1, 4u, 1u, v2); + fwrite(v1->pMonsters, 0x98u, v1->uNumMonsters, v3); + fclose(v3); +} + + +//----- (004563FF) -------------------------------------------------------- +signed int MonsterStats::FindMonsterByTextureName(const char *monster_textr_name) +{ + for (int i=1; i<uNumMonsters; ++i) + { + if((pInfos[i].pName )&& (!_stricmp(pInfos[i].pPictureName, monster_textr_name))) + return i; + } + return -1; +} + + +//----- (00454F4E) -------------------------------------------------------- +void MonsterStats::InitializePlacements() +{ + int i; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; +// int item_counter; + + pMonsterPlacementTXT_Raw = (char *)pEvents_LOD->LoadRaw("placemon.txt", 0); + strtok(pMonsterPlacementTXT_Raw, "\r"); + for (i=1; i<31; ++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + if (decode_step==1) + pPlaceStrings[i]=RemoveQuotes(test_string); + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<3)&&!break_loop); + } + uNumPlacements = 31; +} + +//----- (0045501E) -------------------------------------------------------- +void MonsterStats::Initialize() + { + int i;//,j; + char* test_string; + unsigned char c; + bool break_loop; + unsigned int temp_str_len; + char* tmp_pos; + int decode_step; +// int item_counter; + int curr_rec_num; + char parse_str[64]; + char Src[120]; + FrameTableTxtLine parsed_field; + + free(pMonstersTXT_Raw); + pMonstersTXT_Raw = (char *)pEvents_LOD->LoadRaw("monsters.txt", 0); + strtok(pMonstersTXT_Raw, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + strtok(NULL, "\r"); + uNumMonsters = 265; + curr_rec_num=0; + for (i=0;i<uNumMonsters-1;++i) + { + test_string = strtok(NULL, "\r") + 1; + break_loop = false; + decode_step=0; + do + { + c = *(unsigned char*)test_string; + temp_str_len = 0; + while((c!='\t')&&(c>0)) + { + ++temp_str_len; + c=test_string[temp_str_len]; + } + tmp_pos=test_string+temp_str_len; + if (*tmp_pos == 0) + break_loop = true; + *tmp_pos = 0; + if (temp_str_len) + { + switch (decode_step) + { + case 0: + curr_rec_num=atoi(test_string); + pInfos[curr_rec_num].uID=curr_rec_num; + break; + case 1: + pInfos[curr_rec_num].pName=RemoveQuotes(test_string); + break; + case 2: + pInfos[curr_rec_num].pPictureName=RemoveQuotes(test_string); + break; + case 3: + pInfos[curr_rec_num].uLevel=atoi(test_string); + break; + case 4: + { + int str_len=0; + int str_pos=0; + pInfos[curr_rec_num].uHP=0; + if (test_string[0]=='"') + test_string[0]=' '; + str_len=strlen(test_string); + if (str_len==0) + break; + while ((test_string[str_pos]!=',')&&(str_pos<str_len)) + ++str_pos; + if (str_len==str_pos) + pInfos[curr_rec_num].uHP=atoi(test_string); + else + { + test_string[str_pos]='\0'; + pInfos[curr_rec_num].uHP=1000*atoi(test_string); + pInfos[curr_rec_num].uHP+=atoi(&test_string[str_pos+1]); + test_string[str_pos]=','; + } + } + break; + case 5: + pInfos[curr_rec_num].uAC=atoi(test_string); + break; + case 6: + { + int str_len=0; + int str_pos=0; + pInfos[curr_rec_num].uExp=0; + if (test_string[0]=='"') + test_string[0]=' '; + str_len=strlen(test_string); + if (str_len==0) + break; + while ((test_string[str_pos]!=',')&&(str_pos<str_len)) + ++str_pos; + if (str_len==str_pos) + pInfos[curr_rec_num].uExp=atoi(test_string); + else + { + test_string[str_pos]='\0'; + pInfos[curr_rec_num].uExp=1000*atoi(test_string); + pInfos[curr_rec_num].uExp+=atoi(&test_string[str_pos+1]); + test_string[str_pos]=','; + } + } + break; + case 7: + { + int str_len=0; + int str_pos=0; + bool chance_flag=false; + bool dice_flag=false; + bool item_type_flag=false; + char* item_name; + pInfos[curr_rec_num].uTreasureDropChance=0; + pInfos[curr_rec_num].uTreasureDiceRolls=0; + pInfos[curr_rec_num].uTreasureDiceSides=0; + pInfos[curr_rec_num].uTreasureType=0; + pInfos[curr_rec_num].uTreasureLevel=0; + if (test_string[0]=='"') + test_string[0]=' '; + str_len=strlen(test_string); + do + { + switch(tolower(test_string[str_pos])) + { + case '%': chance_flag=true; break; + case 'd': dice_flag=true; break; + case 'l': item_type_flag=true; break; + } + ++str_pos; + } + while(str_pos<str_len); + if (chance_flag) + { + pInfos[curr_rec_num].uTreasureDropChance=atoi(test_string); + } + else + { + if ((!dice_flag)&&(!item_type_flag)) + break; + pInfos[curr_rec_num].uTreasureDropChance=100; + } + if (dice_flag) + { + str_pos=0; + dice_flag=false; + do + { + switch(tolower(test_string[str_pos])) + { + case '%': + pInfos[curr_rec_num].uTreasureDiceRolls=atoi(&test_string[str_pos+1]); + dice_flag=true; + break; + case 'd': + if(!dice_flag) + pInfos[curr_rec_num].uTreasureDiceRolls=atoi(test_string); + pInfos[curr_rec_num].uTreasureDiceSides=atoi(&test_string[str_pos+1]); + str_pos=str_len; + break; + + } + ++str_pos; + } + while(str_pos<str_len); + } + if (item_type_flag) + { + str_pos=0; + do + { + if (tolower(test_string[str_pos])=='l') + break; + ++str_pos; + } + while(str_pos<str_len); + + pInfos[curr_rec_num].uTreasureLevel=test_string[str_pos+1]-'0'; + item_name=&test_string[str_pos+2]; + if (*item_name) + { + if ( !_stricmp(item_name, "WEAPON")) + pInfos[curr_rec_num].uTreasureType= 20; + else if ( !_stricmp(item_name, "ARMOR")) + pInfos[curr_rec_num].uTreasureType= 21; + else if ( !_stricmp(item_name, "MISC")) + pInfos[curr_rec_num].uTreasureType= 22; + else if ( !_stricmp(item_name, "SWORD")) + pInfos[curr_rec_num].uTreasureType= 23; + else if ( !_stricmp(item_name, "DAGGER")) + pInfos[curr_rec_num].uTreasureType= 24; + else if ( !_stricmp(item_name, "AXE")) + pInfos[curr_rec_num].uTreasureType= 25; + else if ( !_stricmp(item_name, "SPEAR")) + pInfos[curr_rec_num].uTreasureType= 26; + else if ( !_stricmp(item_name, "BOW")) + pInfos[curr_rec_num].uTreasureType= 27; + else if ( !_stricmp(item_name, "MACE")) + pInfos[curr_rec_num].uTreasureType= 28; + else if ( !_stricmp(item_name, "CLUB")) + pInfos[curr_rec_num].uTreasureType= 29; + else if ( !_stricmp(item_name, "STAFF")) + pInfos[curr_rec_num].uTreasureType= 30; + else if ( !_stricmp(item_name, "LEATHER")) + pInfos[curr_rec_num].uTreasureType= 31; + else if ( !_stricmp(item_name, "CHAIN")) + pInfos[curr_rec_num].uTreasureType= 32; + else if ( !_stricmp(item_name, "PLATE")) + pInfos[curr_rec_num].uTreasureType= 33; + else if ( !_stricmp(item_name, "SHIELD")) + pInfos[curr_rec_num].uTreasureType= 34; + else if ( !_stricmp(item_name, "HELM")) + pInfos[curr_rec_num].uTreasureType= 35; + else if ( !_stricmp(item_name, "BELT")) + pInfos[curr_rec_num].uTreasureType= 36; + else if ( !_stricmp(item_name, "CAPE")) + pInfos[curr_rec_num].uTreasureType= 37; + else if ( !_stricmp(item_name, "GAUNTLETS")) + pInfos[curr_rec_num].uTreasureType= 38; + else if ( !_stricmp(item_name, "BOOTS")) + pInfos[curr_rec_num].uTreasureType= 39; + else if ( !_stricmp(item_name, "RING")) + pInfos[curr_rec_num].uTreasureType= 40; + else if ( !_stricmp(item_name, "AMULET")) + pInfos[curr_rec_num].uTreasureType= 41; + else if ( !_stricmp(item_name, "WAND")) + pInfos[curr_rec_num].uTreasureType= 42; + else if ( !_stricmp(item_name, "SCROLL")) + pInfos[curr_rec_num].uTreasureType= 43; + else if ( !_stricmp(item_name, "GEM")) + pInfos[curr_rec_num].uTreasureType= 46; + } + } + + } + break; + case 8: + { + pInfos[curr_rec_num].bQuestMonster=0; + if (atoi(test_string)) + pInfos[curr_rec_num].bQuestMonster=1; + } + break; + case 9: + { + pInfos[curr_rec_num].uFlying=false; + if (_strnicmp(test_string, "n",1)) + pInfos[curr_rec_num].uFlying=true; + } + break; + case 10: + { + switch(tolower(test_string[0])) + { + case 's': pInfos[curr_rec_num].uMovementType=MONSTER_MOVEMENT_TYPE_SHORT;// short + if (tolower(test_string[1])!='h') + pInfos[curr_rec_num].uMovementType=MONSTER_MOVEMENT_TYPE_STAIONARY; //stationary + break; //short + case 'l': pInfos[curr_rec_num].uMovementType = MONSTER_MOVEMENT_TYPE_LONG; break; //long + case 'm': pInfos[curr_rec_num].uMovementType = MONSTER_MOVEMENT_TYPE_MEDIUM; break; //med + case 'g': pInfos[curr_rec_num].uMovementType = MONSTER_MOVEMENT_TYPE_GLOBAL; break; //global? + default: + pInfos[curr_rec_num].uMovementType = MONSTER_MOVEMENT_TYPE_FREE; //free + } + } + break; + case 11: + { + switch(tolower(test_string[0])) + { + case 's': pInfos[curr_rec_num].uAIType=0; break; // suicide + case 'w': pInfos[curr_rec_num].uAIType=1; break; //wimp + case 'n': pInfos[curr_rec_num].uAIType=2; break; //normal + default: + pInfos[curr_rec_num].uAIType=3; //Agress + } + } + break; + case 12: + pInfos[curr_rec_num].uHostilityType=(MonsterInfo::HostilityRadius)atoi(test_string); + break; + case 13: + pInfos[curr_rec_num].uBaseSpeed=atoi(test_string); + break; + case 14: + pInfos[curr_rec_num].uRecoveryTime=atoi(test_string); + break; + case 15: + { + int str_len=0; + int str_pos=0; + pInfos[curr_rec_num].uAttackPreference=0; + pInfos[curr_rec_num].uNumCharactersAttackedPerSpecialAbility=0; + str_len=strlen(test_string); + for (str_pos=0;str_pos<str_len;++str_pos ) + { + switch(tolower(test_string[str_pos])) + { + case '0': pInfos[curr_rec_num].uAttackPreference|=0x0004; break; + case '2': pInfos[curr_rec_num].uNumCharactersAttackedPerSpecialAbility=2; break; + case '3': pInfos[curr_rec_num].uNumCharactersAttackedPerSpecialAbility=3; break; + case '4': pInfos[curr_rec_num].uNumCharactersAttackedPerSpecialAbility=4; break; + case 'c': pInfos[curr_rec_num].uAttackPreference|=0x0010; break; + case 'd': pInfos[curr_rec_num].uAttackPreference|=0x0008; break; + case 'e': pInfos[curr_rec_num].uAttackPreference|=0x1000; break; + case 'f': pInfos[curr_rec_num].uAttackPreference|=0x0400; break; + case 'h': pInfos[curr_rec_num].uAttackPreference|=0x0800; break; + case 'k': pInfos[curr_rec_num].uAttackPreference|=0x0001; break; + case 'm': pInfos[curr_rec_num].uAttackPreference|=0x0100; break; + case 'o': pInfos[curr_rec_num].uAttackPreference|=0x0400; break; + case 'p': pInfos[curr_rec_num].uAttackPreference|=0x0002; break; + case 'r': pInfos[curr_rec_num].uAttackPreference|=0x0040; break; + case 's': pInfos[curr_rec_num].uAttackPreference|=0x0020; break; + case 't': pInfos[curr_rec_num].uAttackPreference|=0x0080; break; + case 'w': pInfos[curr_rec_num].uAttackPreference|=0x2000; break; + case 'x': pInfos[curr_rec_num].uAttackPreference|=0x0200; break; + } + } + } + break; + case 16: + { + int str_len=0; + int str_pos=0; + pInfos[curr_rec_num].uSpecialAttackLevel=1; + pInfos[curr_rec_num].uSpecialAttackType=(SPECIAL_ATTACK_TYPE)0; + str_len=strlen(test_string); + if (str_len>1) + { + for (str_pos=0;str_pos<str_len;++str_pos ) + { + if (tolower(test_string[str_pos])=='x') + { + test_string[str_pos]='\0'; + pInfos[curr_rec_num].uSpecialAttackLevel=atoi(&test_string[str_pos+1]); + test_string[str_pos]='x'; + break; + } + } + pInfos[curr_rec_num].uSpecialAttackType=(SPECIAL_ATTACK_TYPE)ParseSpecialAttack(test_string); + } + } + break; + case 17: + pInfos[curr_rec_num].uAttack1Type=ParseAttackType(test_string); + break; + case 18: + { + ParseDamage(test_string, &pInfos[curr_rec_num].uAttack1DamageDiceRolls, + &pInfos[curr_rec_num].uAttack1DamageDiceSides, + &pInfos[curr_rec_num].uAttack1DamageBonus); + } + break; + case 19: + pInfos[curr_rec_num].uMissleAttack1Type=ParseMissleAttackType(test_string); + break; + case 20: + pInfos[curr_rec_num].uAttack2Chance=atoi(test_string); + break; + case 21: + pInfos[curr_rec_num].uAttack2Type=ParseAttackType(test_string); + break; + case 22: + { + ParseDamage(test_string, &pInfos[curr_rec_num].uAttack2DamageDiceRolls, + &pInfos[curr_rec_num].uAttack2DamageDiceSides, + &pInfos[curr_rec_num].uAttack2DamageBonus); + } + break; + case 23: + pInfos[curr_rec_num].uMissleAttack2Type=ParseMissleAttackType(test_string); + break; + case 24: + pInfos[curr_rec_num].uSpell1UseChance=atoi(test_string); + break; + case 25: + { + int param_num; + char type_flag; + strcpy(parse_str,test_string); + parse_str[0]=' '; + parse_str[strlen(parse_str)-1]=' '; + frame_table_txt_parser(parse_str,&parsed_field); + if (parsed_field.uPropCount>2) + { + param_num=1; + pInfos[curr_rec_num].uSpell1ID=ParseSpellType(&parsed_field,¶m_num); + type_flag=*parsed_field.pProperties[param_num]; + pInfos[curr_rec_num].uSpellSkillAndMastery1=atoi(parsed_field.pProperties[param_num+1])&0x003F; + switch(type_flag) + { + case 'E': pInfos[curr_rec_num].uSpellSkillAndMastery1|=0x0040; break; + case 'M': pInfos[curr_rec_num].uSpellSkillAndMastery1|=0x0080; break; + case 'G': pInfos[curr_rec_num].uSpellSkillAndMastery1|=0x0100; break; + } + } + else + { + pInfos[curr_rec_num].uSpell1ID=0; + pInfos[curr_rec_num].uSpellSkillAndMastery1=0; + } + + } + break; + case 26: + pInfos[curr_rec_num].uSpell2UseChance=atoi(test_string); + break; + case 27: + { + int param_num; + char type_flag; + strcpy(parse_str,test_string); + parse_str[0]=' '; + parse_str[strlen(parse_str)-1]=' '; + frame_table_txt_parser(parse_str,&parsed_field); + if (parsed_field.uPropCount>2) + { + param_num=1; + pInfos[curr_rec_num].uSpell2ID=ParseSpellType(&parsed_field,¶m_num); + type_flag=*parsed_field.pProperties[param_num]; + pInfos[curr_rec_num].uSpellSkillAndMastery2=atoi(parsed_field.pProperties[param_num+1])&0x003F; + switch(type_flag) + { + case 'E': pInfos[curr_rec_num].uSpellSkillAndMastery2|=0x0040; break; + case 'M': pInfos[curr_rec_num].uSpellSkillAndMastery2|=0x0080; break; + case 'G': pInfos[curr_rec_num].uSpellSkillAndMastery2|=0x0100; break; + } + } + else + { + pInfos[curr_rec_num].uSpell2ID=0; + pInfos[curr_rec_num].uSpellSkillAndMastery2=0; + } + } + break; + case 28: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResFire=200; + else + pInfos[curr_rec_num].uResFire=atoi(test_string); + } + break; + case 29: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResAir=200; + else + pInfos[curr_rec_num].uResAir=atoi(test_string); + } + break; + case 30: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResWater=200; + else + pInfos[curr_rec_num].uResWater=atoi(test_string); + } + break; + case 31: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResEarth=200; + else + pInfos[curr_rec_num].uResEarth=atoi(test_string); + } + break; + case 32: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResMind=200; + else + pInfos[curr_rec_num].uResMind=atoi(test_string); + } + break; + case 33: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResSpirit=200; + else + pInfos[curr_rec_num].uResSpirit=atoi(test_string); + } + break; + case 34: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResBody=200; + else + pInfos[curr_rec_num].uResBody=atoi(test_string); + } + break; + case 35: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResLight=200; + else + pInfos[curr_rec_num].uResLight=atoi(test_string); + } + break; + case 36: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResDark=200; + else + pInfos[curr_rec_num].uResDark=atoi(test_string); + } + break; + case 37: + { + if (tolower(test_string[0])=='i') + pInfos[curr_rec_num].uResPhysical=200; + else + pInfos[curr_rec_num].uResPhysical=atoi(test_string); + } + break; + case 38: + { +// int param_num; +// char type_flag; + pInfos[curr_rec_num].uSpecialAbilityType=0; + pInfos[curr_rec_num].uSpecialAbilityDamageDiceBonus=0; + strcpy(parse_str,test_string); + parse_str[0]=' '; + parse_str[strlen(parse_str)-1]=' '; + frame_table_txt_parser(parse_str,&parsed_field); + if ( parsed_field.uPropCount ) + { + // v74 = v94.field_0; + if ( parsed_field.uPropCount < 10 ) + { + if (! _stricmp(parsed_field.pProperties[0], "shot") ) + { + pInfos[curr_rec_num].uSpecialAbilityType=1; + pInfos[curr_rec_num].uSpecialAbilityDamageDiceBonus=atoi((char *)(parsed_field.pProperties[1] + 1)); + } + else if (!_stricmp(parsed_field.pProperties[0], "summon") ) + { + pInfos[curr_rec_num].uSpecialAbilityType=2; + if ( parsed_field.uPropCount > 1 ) + { + pTmpBuf[0] = 0; + strcpy(pTmpBuf.data(), parsed_field.pProperties[2]); + if ( parsed_field.uPropCount > 2 ) + { + int prop_cnt = 3; + if ( parsed_field.uPropCount > 3 ) + { + do + { + strcat(pTmpBuf.data(), " "); + char test_char = parsed_field.pProperties[prop_cnt][0]; + strcat(pTmpBuf.data(), parsed_field.pProperties[prop_cnt]); + if ( prop_cnt == (parsed_field.uPropCount - 1) ) + { + switch (tolower(test_char)) + { + case 'a': pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls = 1; break; + case 'b': pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls = 2; break; + case 'c': pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls = 3; break; + default: + pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls = 0; + } + + } + ++prop_cnt; + } + while ( prop_cnt < parsed_field.uPropCount ); + } + } + else + { + pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls = 0; + } + if ( pMonsterList->uNumMonsters ) + { + pInfos[curr_rec_num].field_3C_some_special_attack = pMonsterList->GetMonsterIDByName(pTmpBuf.data()) + 1; + if ( pInfos[curr_rec_num].field_3C_some_special_attack == -1 ) + { + sprintf(Src, "Can't create random monster: '%s' See MapStats!", pTmpBuf.data()); + MessageBoxA(nullptr, Src, "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Itemdata.cpp:2239", 0); + } + } + pInfos[curr_rec_num].uSpecialAbilityDamageDiceSides = 0; + if ( !_stricmp(parsed_field.pProperties[1], "ground") ) + pInfos[curr_rec_num].uSpecialAbilityDamageDiceSides = 1; + if ( pInfos[curr_rec_num].field_3C_some_special_attack == -1 ) + pInfos[curr_rec_num].uSpecialAbilityType = 0; + } + } + else if (!_stricmp(parsed_field.pProperties[0], "explode") ) + { + pInfos[curr_rec_num].uSpecialAbilityType = 3; + ParseDamage((char*)parsed_field.pProperties[1], &pInfos[curr_rec_num].uSpecialAbilityDamageDiceRolls, + &pInfos[curr_rec_num].uSpecialAbilityDamageDiceSides, + &pInfos[curr_rec_num].uSpecialAbilityDamageDiceBonus); + pInfos[curr_rec_num].field_3C_some_special_attack = ParseAttackType(test_string); + } + } + } + } + break; + } + } + else + { + break_loop = true; + } + ++decode_step; + test_string=tmp_pos+1; + } while ((decode_step<39)&&!break_loop); + } + uNumMonsters = i; +} + + +//----- (0044FA08) -------------------------------------------------------- +signed __int16 MonsterList::GetMonsterIDByName( const char *pMonsterName ) + { + if (!pMonsterName) + return -1; + for (signed __int16 i=1; i<=uNumMonsters; ++i) + { + if( (!_stricmp(pMonsters[i].pMonsterName, pMonsterName))) + return i; + } + Error("Monster not found: %s", pMonsterName); +} +//----- (00438BDF) -------------------------------------------------------- +bool MonsterStats::BelongsToSupertype(unsigned int uMonsterInfoID, enum MONSTER_SUPERTYPE eSupertype) +{ + switch ( eSupertype ) + { + case MONSTER_SUPERTYPE_UNDEAD: + if ( (signed int)uMonsterInfoID >= MONSTER_GHOST_1 && (signed int)uMonsterInfoID <= MONSTER_GHOST_3 //70<=id<=72 + || (signed int)uMonsterInfoID >= MONSTER_LICH_1 && (signed int)uMonsterInfoID <= MONSTER_LICH_3 //91-93 + || (signed int)uMonsterInfoID >= MONSTER_SKELETON_1 && (signed int)uMonsterInfoID <= MONSTER_SKELETON_3 //199-201 + || (signed int)uMonsterInfoID >= MONSTER_VAMPIRE_1 && (signed int)uMonsterInfoID <= MONSTER_VAMPIRE_3 //217-219 + || (signed int)uMonsterInfoID >= MONSTER_WIGHT_1 && (signed int)uMonsterInfoID <= MONSTER_WIGHT_3 //223-225 + || (signed int)uMonsterInfoID >= MONSTER_ZOMBIE_1 && (signed int)uMonsterInfoID <= MONSTER_ZOMBIE_3 //229-231 + || (signed int)uMonsterInfoID >= MONSTER_GHOUL_1 && (signed int)uMonsterInfoID <= MONSTER_GHOUL_3) //256-258 + return true; + return false; + case MONSTER_SUPERTYPE_KREEGAN: + if ( (signed int)uMonsterInfoID >= MONSTER_DEVIL_1 && (signed int)uMonsterInfoID <= MONSTER_DEVIL_3 )//22-24 + return true; + return false; + case MONSTER_SUPERTYPE_ELF: + if ( (signed int)uMonsterInfoID >= MONSTER_PEASANT_ELF_FEMALE_1_1 && (signed int)uMonsterInfoID <= MONSTER_PEASANT_ELF_MALE_3_3//133 - 150 + || (signed int)uMonsterInfoID >= MONSTER_ELF_ARCHER_1 && (signed int)uMonsterInfoID <= MONSTER_ELF_ARCHER_3//49-51 + || (signed int)uMonsterInfoID >= MONSTER_ELF_SPEARMAN_1 && (signed int)uMonsterInfoID <= MONSTER_ELF_SPEARMAN_3)//52-54 + return true; + return false; + case MONSTER_SUPERTYPE_DRAGON: + if ( (signed int)uMonsterInfoID >= MONSTER_DRAGON_1 && (signed int)uMonsterInfoID <= MONSTER_DRAGON_3 )//25-27 + return true; + return false; + case MONSTER_SUPERTYPE_WATER_ELEMENTAL: + if ( (signed int)uMonsterInfoID >= MONSTER_ELEMENTAL_WATER_1 && (signed int)uMonsterInfoID <= MONSTER_ELEMENTAL_WATER_3)//46-48 + return true; + return false; + case MONSTER_SUPERTYPE_TREANT: + if ( (signed int)uMonsterInfoID >= MONSTER_TREANT_1 && (signed int)uMonsterInfoID <= MONSTER_TREANT_3 )//253-255 + return true; + return false; + case MONSTER_SUPERTYPE_TITAN: + if ( (signed int)uMonsterInfoID >= MONSTER_TITAN_1 && (signed int)uMonsterInfoID <= MONSTER_TITAN_3 )//211-213 + return true; + return false; + default: + return false; + } + return false; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Monsters.h Fri Sep 19 00:03:04 2014 +0600 @@ -0,0 +1,261 @@ +#pragma once + + + +/* 334 */ +enum MONSTER_TYPE +{ + MONSTER_DEVIL_1 = 0x16, + MONSTER_DEVIL_2 = 0x17, + MONSTER_DEVIL_3 = 0x18, + MONSTER_DRAGON_1 = 0x19, + MONSTER_DRAGON_2 = 0x1A, + MONSTER_DRAGON_3 = 0x1B, + MONSTER_ELEMENTAL_WATER_1 = 0x2E, + MONSTER_ELEMENTAL_WATER_3 = 0x30, + MONSTER_ELF_ARCHER_1 = 0x31, + MONSTER_ELF_ARCHER_3 = 0x33, + MONSTER_ELF_SPEARMAN_1 = 0x34, + MONSTER_ELF_SPEARMAN_3 = 0x36, + MONSTER_GHOST_1 = 0x46, + MONSTER_GHOST_3 = 0x48, + MONSTER_HARPY_1 = 0x55, + MONSTER_HARPY_2 = 0x56, + MONSTER_HARPY_3 = 0x57, + MONSTER_LICH_1 = 0x5B, + MONSTER_LICH_3 = 0x5D, + MONSTER_OOZE_1 = 0x70, + MONSTER_OOZE_2 = 0x71, + MONSTER_OOZE_3 = 0x72, + MONSTER_PEASANT_ELF_FEMALE_1_1 = 0x85, + MONSTER_PEASANT_ELF_MALE_3_3 = 0x96, + MONSTER_SKELETON_1 = 0xC7, + MONSTER_SKELETON_3 = 0xC9, + MONSTER_TITAN_1 = 0xD3, + MONSTER_TITAN_3 = 0xD5, + MONSTER_VAMPIRE_1 = 0xD9, + MONSTER_VAMPIRE_3 = 0xDB, + MONSTER_WIGHT_1 = 0xDF, + MONSTER_WIGHT_3 = 0xE1, + MONSTER_ZOMBIE_1 = 0xE5, + MONSTER_ZOMBIE_3 = 0xE7, + MONSTER_PEASANT_GOBLIN_MALE_3_3 = 0xF9, + MONSTER_TROLL_1 = 0xFA, + MONSTER_TROLL_2 = 0xFB, + MONSTER_TROLL_3 = 0xFC, + MONSTER_TREANT_1 = 0xFD, + MONSTER_TREANT_3 = 0xFF, + MONSTER_GHOUL_1 = 0x100, + MONSTER_GHOUL_3 = 0x102, +}; + +/* 335 */ +enum MONSTER_SPECIAL_ABILITY_TYPE +{ + MONSTER_SPECIAL_ABILITY_NONE = 0x0, + MONSTER_SPECIAL_ABILITY_SHOT = 0x1, + MONSTER_SPECIAL_ABILITY_SUMMON = 0x2, + MONSTER_SPECIAL_ABILITY_EXPLODE = 0x3, +}; + +enum MONSTER_MOVEMENT_TYPE + { + MONSTER_MOVEMENT_TYPE_SHORT = 0x0, + MONSTER_MOVEMENT_TYPE_MEDIUM = 0x1, + MONSTER_MOVEMENT_TYPE_LONG = 0x2, + MONSTER_MOVEMENT_TYPE_GLOBAL = 0x3, + MONSTER_MOVEMENT_TYPE_FREE = 0x4, + MONSTER_MOVEMENT_TYPE_STAIONARY = 0x5, + }; + + +/* 336 */ +enum MONSTER_SUPERTYPE +{ + MONSTER_SUPERTYPE_UNDEAD = 0x1, + MONSTER_SUPERTYPE_KREEGAN = 0x2, + MONSTER_SUPERTYPE_DRAGON = 0x3, + MONSTER_SUPERTYPE_ELF = 0x4, + MONSTER_SUPERTYPE_WATER_ELEMENTAL = 0x5, + MONSTER_SUPERTYPE_TREANT = 0x6, + MONSTER_SUPERTYPE_TITAN = 0x7, + MONSTER_SUPERTYPE_8 = 0x8, +}; + +enum SPECIAL_ATTACK_TYPE : unsigned __int8 +{ + SPECIAL_ATTACK_NONE = 0, + SPECIAL_ATTACK_CURSE = 1, + SPECIAL_ATTACK_WEAK = 2, + SPECIAL_ATTACK_SLEEP = 3, + SPECIAL_ATTACK_DRUNK = 4, + SPECIAL_ATTACK_INSANE = 5, + SPECIAL_ATTACK_POISON_WEAK = 6, + SPECIAL_ATTACK_POISON_MEDIUM = 7, + SPECIAL_ATTACK_POISON_SEVERE = 8, + SPECIAL_ATTACK_DISEASE_WEAK = 9, + SPECIAL_ATTACK_DISEASE_MEDIUM = 10, + SPECIAL_ATTACK_DISEASE_SEVERE = 11, + SPECIAL_ATTACK_PARALYZED = 12, + SPECIAL_ATTACK_UNCONSCIOUS = 13, + SPECIAL_ATTACK_DEAD = 14, + SPECIAL_ATTACK_PETRIFIED = 15, + SPECIAL_ATTACK_ERADICATED = 16, + SPECIAL_ATTACK_BREAK_ANY = 17, + SPECIAL_ATTACK_BREAK_ARMOR = 18, + SPECIAL_ATTACK_BREAK_WEAPON = 19, + SPECIAL_ATTACK_STEAL = 20, + SPECIAL_ATTACK_AGING = 21, + SPECIAL_ATTACK_MANA_DRAIN = 22, + SPECIAL_ATTACK_FEAR = 23, +}; + + +/* 187 */ +#pragma pack(push, 1) +struct MonsterInfo +{ + enum HostilityRadius: unsigned __int8 + { + Hostility_Friendly = 0, + Hostility_Close = 1, + Hostility_Short = 2, + Hostility_Medium = 3, + Hostility_Long = 4 + }; + + inline MonsterInfo(): + pName(nullptr), pPictureName(nullptr) + {} + + char *pName; + char *pPictureName; + unsigned __int8 uLevel; + unsigned __int8 uTreasureDropChance; + unsigned __int8 uTreasureDiceRolls; + unsigned __int8 uTreasureDiceSides; + unsigned __int8 uTreasureLevel; + unsigned __int8 uTreasureType; + unsigned __int8 uFlying; + unsigned __int8 uMovementType; + unsigned __int8 uAIType; + HostilityRadius uHostilityType; + char field_12; + SPECIAL_ATTACK_TYPE uSpecialAttackType; + unsigned __int8 uSpecialAttackLevel; + unsigned __int8 uAttack1Type; + unsigned __int8 uAttack1DamageDiceRolls; + unsigned __int8 uAttack1DamageDiceSides; + unsigned __int8 uAttack1DamageBonus; + unsigned __int8 uMissleAttack1Type; + unsigned __int8 uAttack2Chance; + unsigned __int8 uAttack2Type; + unsigned __int8 uAttack2DamageDiceRolls; + unsigned __int8 uAttack2DamageDiceSides; + unsigned __int8 uAttack2DamageBonus; + unsigned __int8 uMissleAttack2Type; + unsigned __int8 uSpell1UseChance; + unsigned __int8 uSpell1ID; + unsigned __int8 uSpell2UseChance; + unsigned __int8 uSpell2ID; + unsigned __int8 uResFire; + unsigned __int8 uResAir; + unsigned __int8 uResWater; + unsigned __int8 uResEarth; + unsigned __int8 uResMind; + unsigned __int8 uResSpirit; + unsigned __int8 uResBody; + unsigned __int8 uResLight; + unsigned __int8 uResDark; + unsigned __int8 uResPhysical; + unsigned __int8 uSpecialAbilityType; // 0 SPECIAL_ABILITY_TYPE_NONE + // 1 SPECIAL_ABILITY_TYPE_SHOT + // 2 SPECIAL_ABILITY_TYPE_SUMMON + // 3 SPECIAL_ABILITY_TYPE_EXPLODE + unsigned __int8 uSpecialAbilityDamageDiceRolls; + unsigned __int8 uSpecialAbilityDamageDiceSides; + unsigned __int8 uSpecialAbilityDamageDiceBonus; + unsigned __int8 uNumCharactersAttackedPerSpecialAbility; + char field_33; + unsigned __int16 uID; + unsigned __int16 bQuestMonster; + unsigned __int16 uSpellSkillAndMastery1; + unsigned __int16 uSpellSkillAndMastery2; + __int16 field_3C_some_special_attack; + __int16 field_3E; + unsigned int uHP; + unsigned int uAC; + unsigned int uExp; + unsigned int uBaseSpeed; + signed int uRecoveryTime; + unsigned int uAttackPreference; +}; +#pragma pack(pop) + + + +/* 189 */ +#pragma pack(push, 1) +struct MonsterStats +{ + void Initialize(); + void InitializePlacements(); + signed int FindMonsterByTextureName(const char *Str2); + + static bool BelongsToSupertype(unsigned int uMonsterInfoID, enum MONSTER_SUPERTYPE eSupertype); + + MonsterInfo pInfos[265]; //0 - 5b18h + char *pPlaceStrings[31]; //5B18h placement counts from 1 + unsigned int uNumMonsters; //5B94h + unsigned int uNumPlacements; //5B98h + int field_5B9C; +}; +#pragma pack(pop) + + + +#pragma pack(push, 1) +struct MonsterDesc_mm6 +{ + unsigned __int16 uMonsterHeight; + unsigned __int16 uMonsterRadius; + unsigned __int16 uMovementSpeed; + __int16 uToHitRadius; + unsigned __int16 pSoundSampleIDs[4]; + char pMonsterName[32]; + char pSpriteNames[10][10]; +}; + +struct MonsterDesc +{ + unsigned __int16 uMonsterHeight; + unsigned __int16 uMonsterRadius; + unsigned __int16 uMovementSpeed; + __int16 uToHitRadius; + signed int sTintColor; + unsigned __int16 pSoundSampleIDs[4]; + char pMonsterName[32]; + char pSpriteNames[10][10]; +}; +#pragma pack(pop) + + +#pragma pack(push, 1) +struct MonsterList +{ + inline MonsterList(): //----- (00458429) + uNumMonsters(0), pMonsters(nullptr) + {} + signed __int16 GetMonsterIDByName(const char *pMonsterName); + void ToFile(); + void FromFile(void *data_mm6, void *data_mm7, void *data_mm8); + bool FromFileTxt(const char *Args); + + signed int uNumMonsters; + struct MonsterDesc *pMonsters; +}; +#pragma pack(pop) + + +extern struct MonsterStats *pMonsterStats; +extern struct MonsterList *pMonsterList; \ No newline at end of file
--- a/NPC.cpp Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1762 +0,0 @@ -#define _CRTDBG_MAP_ALLOC -#include <stdlib.h> -#include <crtdbg.h> - -#define _CRT_SECURE_NO_WARNINGS -#include "texts.h" -#include "LOD.h" -#include "Autonotes.h" -#include "Awards.h" -#include "Party.h" -#include "NPC.h" -#include "GUIWindow.h" -#include "Events.h" -#include "UI\UIHouses.h" -#include "Engine/Graphics/Indoor.h" -#include "MapInfo.h" -#include "Actor.h" -#include "AudioPlayer.h" -#include "CastSpellInfo.h" -#include "Engine/Graphics/Overlays.h" - -int pDialogueNPCCount; -std::array<struct Texture *, 6> pDialogueNPCPortraits; -int uNumDialogueNPCPortraits; // weak -struct NPCStats *pNPCStats = nullptr; - -int NPCStats::dword_AE336C_LastMispronouncedNameFirstLetter = -1; -int NPCStats::dword_AE3370_LastMispronouncedNameResult = -1; - -void InitializeAwards(); -void InitializeScrolls(); -void InitializeMerchants(); -void InitializeTransitions(); -void InitializeAutonotes(); -void InitializeQuests(); -bool CheckPortretAgainstSex(int portret_num, int sex); - -//----- (004459F9) -------------------------------------------------------- -NPCData *__fastcall GetNPCData(signed int npcid) -{ - unsigned int v1; // esi@1 - NPCData *result; // eax@5 - int v3; // esi@9 - int v4; // ecx@9 - //int v5; // edx@9 - //NPCData *v6; // eax@9 -// char *v7; // ebx@14 -// NPCData *v8; // edi@14 - char v9; // al@22 -// char v10; - //std::string v10; // [sp-18h] [bp-2Ch]@4 -// int v11; - //const char *v11; // [sp-8h] [bp-1Ch]@4 -// int v12; // [sp-4h] [bp-18h]@4 -// int v13; -// char *v14; - //std::string *v13; // [sp+Ch] [bp-8h]@4 -// int a3; // [sp+13h] [bp-1h]@4 - int i; - - /*v1 = npcid; - if ( (npcid & 0x80000000u) == 0 ) - { - if ( (signed int)npcid < 5000 ) - { - if ( (signed int)npcid >= 501 ) - { - MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0); - } - return &pNPCStats->pNewNPCData[v1]; - } - return &pNPCStats->array_13EF4[npcid - 5000]; - } - if ( (signed int)npcid >= 5000 ) - return &pNPCStats->array_13EF4[npcid - 5000]; - if ( (sDialogue_SpeakingActorNPC_ID & 0x80000000u) == 0 ) - { - result = 0; - } - else - { - v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1; - v4 = 0; - v5 = 0; - v6 = pParty->pHirelings; - do - { - if ( v6->pName ) - pTmpBuf[v4++] = v5; - ++v6; - ++v5; - } - while ( (signed int)v6 < (signed int)&pParty->pPickedItem ); - v13 = 0; - if ( (signed int)pNPCStats->uNumNewNPCs > 0 ) - { - v7 = &pTmpBuf[v4]; - v8 = pNPCStats->pNewNPCData; - do - { - if ( v8->uFlags & 0x80 - && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) - && (!pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName)) ) - *v7++ = (char)v13 + 2; - v13 = (std::string *)((char *)v13 + 1); - ++v8; - } - while ( (signed int)v13 < (signed int)pNPCStats->uNumNewNPCs ); - } - v9 = pTmpBuf[v3]; - if ( (unsigned __int8)v9 >= 2u ) - result = &pNPCStats->pNPCData[(unsigned __int8)v9 + 499]; - else - result = &pParty->pHirelings[(unsigned __int8)v9]; - } - return result;*/ - v1 = npcid; - if ( npcid >= 0 ) - { - if ( npcid < 5000 ) - { - if ( npcid >= 501 ) - { - MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:1984", 0); - } - return &pNPCStats->pNewNPCData[v1];// - 1]; - } - return &pNPCStats->pAdditionalNPC[npcid - 5000]; - } - - - if ( npcid >= 5000 ) - return &pNPCStats->pAdditionalNPC[npcid - 5000]; - if (sDialogue_SpeakingActorNPC_ID >= 0) - { - result = 0; - } - else - { - v3 = abs(sDialogue_SpeakingActorNPC_ID) - 1; - v4 = 0; - - for (i = 0; i < 2; ++i) - { - if (pParty->pHirelings[i].pName) - pTmpBuf[v4++] = i; - } - - if (pNPCStats->uNumNewNPCs > 0) - { - for (i = 0; i < pNPCStats->uNumNewNPCs; ++i) - { - if (pNPCStats->pNewNPCData[i].Hired()) - { - if (!pParty->pHirelings[0].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[0].pName)) - { - if (!pParty->pHirelings[1].pName || strcmp((char *)pNPCStats->pNewNPCData[i].pName, (char *)pParty->pHirelings[1].pName)) - pTmpBuf[v4++] = i + 2; - } - } - } - } - - v9 = pTmpBuf[v3]; - if ( v9 >= 2 ) - result = &pNPCStats->pNPCData[499 + v9]; - else - result = &pParty->pHirelings[v9]; - } - return result; -} - -//----- (00445B2C) -------------------------------------------------------- -struct NPCData * GetNewNPCData( signed int npcid, int* npc_indx ) - { - - int* v3; // edi@1 - NPCData *result; // eax@5 - int v5; // esi@9 - int v6; // ecx@9 - char v11; // al@23 - - v3 = npc_indx; - if ( npcid >= 0 ) - { - if ( npcid < 5000 ) - { - if ( npcid >= 501 ) - { - MessageBoxW(nullptr, L"NPC id exceeds MAX_DATA!", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Events.cpp:2040", 0); - } - *v3 = npcid; - return &pNPCStats->pNewNPCData[npcid]; - } - *npc_indx = npcid - 5000; - return &pNPCStats->pAdditionalNPC[npcid - 5000]; - } - if ( npcid >= 5000 ) - { - *npc_indx = npcid - 5000; - return &pNPCStats->pAdditionalNPC[npcid - 5000]; - } - if ( sDialogue_SpeakingActorNPC_ID >= 0 ) - { - *npc_indx = 0; - result = nullptr; - } - else - { - v5 = abs(sDialogue_SpeakingActorNPC_ID) - 1; - v6 = 0; - for (int i=0; i<2; ++i) - { - if ( pParty->pHirelings[i].pName ) - pTmpBuf[v6++] = i; - - } - for (int i=0; i< pNPCStats->uNumNewNPCs; ++i) - { - if ( pNPCStats->pNewNPCData[i].Hired() - && (!pParty->pHirelings[0].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[0].pName)) - && (!pParty->pHirelings[1].pName || strcmp(pNPCStats->pNewNPCData[i].pName, pParty->pHirelings[1].pName)) ) - { - pTmpBuf[v6++]=i+2; - } - } - v11 = pTmpBuf[v5]; - - if ( v11 >= 2u ) - { - *v3 = v11 - 2; - result = &pNPCStats->pNewNPCData[v11 - 2]; - } - else - { - *v3 = v11; - result = &pParty->pHirelings[v11]; - } - } - return result; -} - -//----- (00476977) -------------------------------------------------------- -void NPCStats::InitializeNPCText() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pNPCTextTXT_Raw); - pNPCTextTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctext.txt", 0); - strtok(pNPCTextTXT_Raw, "\r"); - - for (i=0; i<789; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ( decode_step == 1) - pNPCTopics[i].pText =RemoveQuotes(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - free(pNPCTopicTXT_Raw); - pNPCTopicTXT_Raw = (char *)pEvents_LOD->LoadRaw("npctopic.txt", 0); - strtok(pNPCTopicTXT_Raw, "\r"); - - for ( i = 1; i <= 579; ++i )//NPC topics count limit - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ( decode_step == 1) - pNPCTopics[i].pTopic = RemoveQuotes(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - - free(pNPCDistTXT_Raw); - pNPCDistTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdist.txt", 0); - strtok(pNPCDistTXT_Raw, "\r"); - strtok(NULL, "\r"); - - for (i=1; i<59; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ((decode_step>0)&&(decode_step<77)) - { - pProfessionChance[decode_step].professionChancePerArea[i]=atoi(test_string); - } - else if (decode_step==0) - { - pProfessionChance[0].professionChancePerArea[i]=10; - } - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<78)&&!break_loop); - } - - for ( i = 0; i < 77; ++i ) - { - pProfessionChance[i].uTotalprofChance=0; - for ( int ii = 1; ii < 59; ++ii ) - { - pProfessionChance[i].uTotalprofChance+=pProfessionChance[i].professionChancePerArea[ii]; - } - pProfessionChance[i].professionChancePerArea[0]=0; - pProfessionChance[i].professionChancePerArea[59]=0; - } - - free(pNPCDistTXT_Raw); - pNPCDistTXT_Raw = nullptr; - } - -//----- (00476C60) -------------------------------------------------------- -void NPCStats::_476C60() - { - for (unsigned int i = 1; i < uNumNewNPCs; ++i) - pNewNPCData[i].pName = pNPCUnicNames[i - 1]; - - if (pParty->pHirelings[0].pName) - pParty->pHirelings[0].pName = pParty->pHireling1Name; - if (pParty->pHirelings[1].pName) - pParty->pHirelings[1].pName = pParty->pHireling2Name; - } - -//----- (00476CB5) -------------------------------------------------------- -void NPCStats::InitializeNPCData() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - pNPCDataTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcdata.txt", 0); - strtok(pNPCDataTXT_Raw, "\r"); - strtok(NULL, "\r"); - - for (i=0; i<500; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { //i+1 - switch (decode_step) - { - case 1: - pNPCUnicNames[i] = RemoveQuotes(test_string); - pNPCData[i+1].pName=pNPCUnicNames[i]; - break; - case 2: - pNPCData[i+1].uPortraitID = atoi(test_string); - break; - case 6: - pNPCData[i+1].Location2D = atoi(test_string); - break; - case 7: - pNPCData[i+1].uProfession = atoi(test_string); - break; - case 8: - pNPCData[i+1].greet = atoi(test_string); - break; - case 9: - pNPCData[i+1].joins = (*test_string == 'y')?1:0; - break; - case 10: - pNPCData[i+1].evt_A = atoi(test_string); - break; - case 11: - pNPCData[i+1].evt_B = atoi(test_string); - break; - case 12: - pNPCData[i+1].evt_C = atoi(test_string); - break; - case 13: - pNPCData[i+1].evt_D = atoi(test_string); - break; - case 14: - pNPCData[i+1].evt_E = atoi(test_string); - break; - case 15: - pNPCData[i+1].evt_F = atoi(test_string); - break; - } - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<16)&&!break_loop); - } - uNumNewNPCs = 501; - pNPCGreetTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgreet.txt", 0); - strtok(pNPCGreetTXT_Raw, "\r"); - for ( i = 1; i <= 205; ++i ) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { //i+1 - switch (decode_step) - { - case 1: - pNPCGreetings[i].pGreetings[0] = RemoveQuotes(test_string); - break; - case 2: - pNPCGreetings[i].pGreetings[1] = RemoveQuotes(test_string); - break; - } - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<3)&&!break_loop); - } - - pNCPGroupTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcgroup.txt", 0); - strtok(pNCPGroupTXT_Raw, "\r"); - - for (i=0; i<51; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { //i+1 - if (decode_step==1) - { - pGroups[i] = atoi(test_string); - } - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - - pNPCNewsTXT_Raw = (char*)pEvents_LOD->LoadRaw("npcnews.txt", 0); - strtok(pNPCNewsTXT_Raw, "\r"); - - - for (i=0; i<51; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { //i+1 - if (decode_step==1) - pCatchPhrases[i] = RemoveQuotes(test_string); - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - } - -//----- (0047702F) -------------------------------------------------------- -void NPCStats::Initialize() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - InitializeNPCData(); - InitializeNPCText(); - InitializeQuests(); - InitializeAutonotes(); - InitializeAwards(); - InitializeTransitions(); - InitializeMerchants(); - InitializeScrolls(); - - pNPCNamesTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcnames.txt", 0); - strtok(pNPCNamesTXT_Raw, "\r"); - - uNewlNPCBufPos = 0; - - for (i=0; i<540; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - if (c=='\t') - { - if ( (decode_step == 1)&&(!uNumNPCNames[1])) - uNumNPCNames[1]=i; - } - else - { - while((c!='\n')&&(c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - - if (temp_str_len) - { - *tmp_pos = 0; - if ( decode_step == 0) - pNPCNames[i][0] =RemoveQuotes(test_string); - else if ( decode_step == 1) - pNPCNames[i][1] =RemoveQuotes(test_string); - } - else - { - if ( (decode_step == 1)&&(!uNumNPCNames[1])) - uNumNPCNames[1]=i; - } - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - uNumNPCNames[0] = i; - - pNPCProfTXT_Raw = (char *)pEvents_LOD->LoadRaw("npcprof.txt", 0); - strtok(pNPCProfTXT_Raw, "\r"); - strtok(NULL, "\r"); - strtok(NULL, "\r"); - strtok(NULL, "\r"); - - for (i=1; i<59; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - //while (*test_string == '\t') // some steps are separated by multiple \t's - //++test_string; - - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - switch(decode_step) - { - case 2: - pProfessions[i].uHirePrice = atoi(test_string); - break; - case 3: - pProfessions[i].pActionText = RemoveQuotes(test_string); - break; - case 4: - pProfessions[i].pBenefits= RemoveQuotes(test_string); - break; - case 5: - pProfessions[i].pJoinText = RemoveQuotes(test_string); - break; - case 6: - pProfessions[i].pDismissText = RemoveQuotes(test_string); - } - } - else - { - if (!decode_step) - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<7)&&!break_loop); - } - uNumNPCProfessions = 59; - } - -//----- (00477266) -------------------------------------------------------- -void NPCStats::Release() - { - free(pNPCTopicTXT_Raw); - pNPCTopicTXT_Raw = nullptr; - free(pNPCTextTXT_Raw); - pNPCTextTXT_Raw = nullptr; - free(pNPCNewsTXT_Raw); - pNPCNewsTXT_Raw = nullptr; - free(pNPCProfTXT_Raw); - pNPCProfTXT_Raw = nullptr; - free(pNPCNamesTXT_Raw); - pNPCNamesTXT_Raw = nullptr; - free(pNPCDataTXT_Raw); - pNPCDataTXT_Raw = nullptr; - free(pNPCDistTXT_Raw); - pNPCDistTXT_Raw = nullptr; - free(pNPCGreetTXT_Raw); - pNPCGreetTXT_Raw = nullptr; - free(pNCPGroupTXT_Raw); - pNCPGroupTXT_Raw = nullptr; - } - -//----- (0047730C) -------------------------------------------------------- -bool CheckPortretAgainstSex(int a1, int) - { - return true; - } -// 47730C: using guessed type int __stdcall const_1(int); - -//----- (0047732C) -------------------------------------------------------- -void NPCStats::InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId) - { - int rep_gen; - int uNPCSex; // esi@1 - int uGeneratedPortret; // ecx@23 - int test_prof_summ; // ecx@37 - int gen_profession; // eax@37 - int max_prof_cap; // edx@37 -// signed int result; // eax@39 - int uRace; // [sp+Ch] [bp-Ch]@1 - bool break_gen; // [sp+10h] [bp-8h]@1 - signed int gen_attempts; // [sp+14h] [bp-4h]@1 - int uPortretMin; // [sp+24h] [bp+Ch]@1 - int uPortretMax; - - static const unsigned __int8 NPCSexGenTable[86] ={ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; - static const unsigned __int8 NPCRaceGenTable[86] ={ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0}; - - unsigned __int8 seed = (unsigned __int8)((double)(npc_uid - 1)/3.0); - uNPCSex = NPCSexGenTable[seed]; - uRace = NPCRaceGenTable[seed]; - pNPCDataBuff->uSex = uNPCSex; - pNPCDataBuff->pName = pNPCNames[rand() % uNumNPCNames[uNPCSex]][uNPCSex]; - - gen_attempts = 0; - break_gen = false; - - do - { - switch ( uRace ) - { - case 0: - if ( uNPCSex == 0 ) - { - uPortretMin = 2; - uPortretMax = 100; - } - else - { - uPortretMin = 201; - uPortretMax = 250; - } - case 1: - if ( uNPCSex == 0 ) - { - uPortretMin = 400; - uPortretMax = 430; - } - else - { - uPortretMin = 460; - uPortretMax = 490; - } - break; - case 2: - if ( uNPCSex == 0 ) - { - uPortretMin = 500; - uPortretMax = 520; - } - else - { - uPortretMin = 530; - uPortretMax = 550; - } - break; - case 3: - if ( uNPCSex == 0 ) - { - uPortretMin = 300; - uPortretMax = 330; - } - else - { - uPortretMin = 360; - uPortretMax = 387; - } - - break; - } - - uGeneratedPortret = uPortretMin + rand() % (uPortretMax - uPortretMin + 1); - if ( CheckPortretAgainstSex(uGeneratedPortret, uNPCSex)) - break_gen = true; - ++gen_attempts; - if ( gen_attempts >= 4 ) - { - uGeneratedPortret = uPortretMin; - break_gen = true; - } - } - while(!break_gen); - - pNPCDataBuff->uPortraitID = uGeneratedPortret; - pNPCDataBuff->uFlags = 0; - pNPCDataBuff->fame = 0; - //generate reputation - rep_gen = rand() % 100 + 1; - - if ( rep_gen >= 60 ) - { - if ( rep_gen >= 90 ) - { - if ( rep_gen >= 95 ) - { - if ( rep_gen >= 98 ) - pNPCDataBuff->rep = -600; - else - pNPCDataBuff->rep = 400; - } - else - pNPCDataBuff->rep = -300; - } - else - pNPCDataBuff->rep = 200; - } - else - pNPCDataBuff->rep = 0; - - max_prof_cap = rand() % pProfessionChance[uMapId].uTotalprofChance+1; - test_prof_summ = 0; - gen_profession = 0; - - if ( max_prof_cap > 0 ) - { - do - test_prof_summ += pProfessionChance[uMapId].professionChancePerArea[gen_profession++]; - while ( test_prof_summ < max_prof_cap ); - } - pNPCDataBuff->uProfession = gen_profession - 1; - pNPCDataBuff->Location2D = uLocation2D; - pNPCDataBuff->field_24 = 1; - pNPCDataBuff->joins = 1; - pNPCDataBuff->evt_A = 0; - pNPCDataBuff->evt_B = 0; - pNPCDataBuff->evt_C = 0; - pNPCDataBuff->evt_D = 0; - pNPCDataBuff->evt_E = 0; - pNPCDataBuff->evt_F = 0; - } - - -//----- (00495366) -------------------------------------------------------- -char *NPCStats::sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId) -{ - int pickedName; // edx@2 - - if ( firstLetter == dword_AE336C_LastMispronouncedNameFirstLetter) - pickedName = dword_AE3370_LastMispronouncedNameResult; - else - { - dword_AE336C_LastMispronouncedNameFirstLetter = firstLetter; - if ( this->uNumNPCNames[genderId] == 0 ) - pickedName = rand() % this->uNumNPCNames[(genderId + 1) % 2]; //originally without " + 1) % 2", but that would yield a div by zero - else - { - int rangeBottom = 0; - int rangeTop = 0; - for ( uint i = 0; i < this->uNumNPCNames[genderId]; ++i ) - { - if (tolower(this->pNPCNames[i][genderId][0])) - { - if ( rangeBottom ) - rangeTop = i; - else - rangeBottom = i; - } - } - if ( rangeTop != 0 ) - pickedName = rangeBottom + rand() % (rangeTop - rangeBottom); - else - pickedName = rand() % this->uNumNPCNames[genderId]; - } - } - dword_AE3370_LastMispronouncedNameResult = pickedName; - return this->pNPCNames[pickedName][genderId]; -} - -//----- (00476387) -------------------------------------------------------- -bool PartyHasDragon() -{ - return pNPCStats->pNewNPCData[57].Hired(); -} - -//----- (00476395) -------------------------------------------------------- -//0x26 Wizard eye at skill level 2 -bool CheckHiredNPCSpeciality(unsigned int uProfession) - { - - if ( bNoNPCHiring == 1 ) - return 0; - - for (uint i=0; i<pNPCStats->uNumNewNPCs; ++i ) - { - if ( pNPCStats->pNewNPCData[i].uProfession == uProfession && - (pNPCStats->pNewNPCData[i].uFlags & 0x80) )//Uninitialized memory access - return true; - } - if ( pParty->pHirelings[0].uProfession == uProfession || - pParty->pHirelings[1].uProfession == uProfession) - return true; - else - return false; - - } - -//----- (004763E0) -------------------------------------------------------- -void InitializeAwards() -{ - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pAwardsTXT_Raw); - pAwardsTXT_Raw = (char *)pEvents_LOD->LoadRaw("awards.txt", 0); - strtok(pAwardsTXT_Raw, "\r"); - - for (i=1; i<105; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if (decode_step==1) - pAwards[i].pText=RemoveQuotes(test_string); - else if (decode_step==2) - pAwards[i].uPriority = atoi(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<3)&&!break_loop); - } - } -// 7241C8: using guessed type int dword_7241C8; - -//----- (004764C2) -------------------------------------------------------- -void InitializeScrolls() - { - - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pScrollsTXT_Raw); - pScrollsTXT_Raw = (char *)pEvents_LOD->LoadRaw("scroll.txt", 0); - strtok(pScrollsTXT_Raw, "\r"); - for (i=0; i<82; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ( decode_step == 1) - pScrolls[i]=RemoveQuotes(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - } - -//----- (00476590) -------------------------------------------------------- -void InitializeMerchants() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pMerchantsTXT_Raw); - pMerchantsTXT_Raw = (char *)pEvents_LOD->LoadRaw("merchant.txt", 0); - strtok(pMerchantsTXT_Raw, "\r"); - - for (i=0; i<7; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - switch (decode_step) - { - case 1: - pMerchantsBuyPhrases[i]=RemoveQuotes(test_string); - break; - case 2: - pMerchantsSellPhrases[i]=RemoveQuotes(test_string); - break; - case 3: - pMerchantsRepairPhrases[i]=RemoveQuotes(test_string); - break; - case 4: - pMerchantsIdentifyPhrases[i]=RemoveQuotes(test_string); - break; - } - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<5)&&!break_loop); - } - - } - -//----- (00476682) -------------------------------------------------------- -void InitializeTransitions() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pTransitionsTXT_Raw); - pTransitionsTXT_Raw = (char *)pEvents_LOD->LoadRaw("trans.txt", 0); - strtok(pTransitionsTXT_Raw, "\r"); - - for (i=0; i<464; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ( decode_step == 1) - pTransitionStrings[i + 1]=RemoveQuotes(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - } - -//----- (00476750) -------------------------------------------------------- -void InitializeAutonotes() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pAutonoteTXT_Raw); - pAutonoteTXT_Raw = (char *)pEvents_LOD->LoadRaw("autonote.txt", 0); - strtok(pAutonoteTXT_Raw, "\r"); - - for (i=0; i<195; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - switch (decode_step) - { - case 1: - pAutonoteTxt[i+1].pText=RemoveQuotes(test_string); - break; - case 2: - { - if ( !_stricmp(test_string, "potion")) - { - pAutonoteTxt[i+1].eType = AUTONOTE_POTION_RECEPIE; - break; - } - if ( !_stricmp(test_string, "stat") ) - { - pAutonoteTxt[i+1].eType = AUTONOTE_STAT_HINT; - break; - } - if ( !_stricmp(test_string, "seer") ) - { - pAutonoteTxt[i+1].eType = AUTONOTE_SEER; - break; - } - if ( !_stricmp(test_string, "obelisk") ) - { - pAutonoteTxt[i+1].eType = AUTONOTE_OBELISK; - break; - } - if ( !_stricmp(test_string, "teacher") ) - { - pAutonoteTxt[i+1].eType = AUTONOTE_TEACHER; - break; - } - pAutonoteTxt[i+1].eType =AUTONOTE_MISC; - break; - } - } - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<3)&&!break_loop); - } - } - - -//----- (004768A9) -------------------------------------------------------- -void InitializeQuests() - { - int i; - char* test_string; - unsigned char c; - bool break_loop; - unsigned int temp_str_len; - char* tmp_pos; - int decode_step; - - free(pQuestsTXT_Raw); - pQuestsTXT_Raw = (char *)pEvents_LOD->LoadRaw("quests.txt", 0); - strtok(pQuestsTXT_Raw, "\r"); - memset(pQuestTable.data(),0, sizeof(pQuestTable)); - for (i=0; i<512; ++i) - { - test_string = strtok(NULL, "\r") + 1; - break_loop = false; - decode_step=0; - do - { - c = *(unsigned char*)test_string; - temp_str_len = 0; - while((c!='\t')&&(c>0)) - { - ++temp_str_len; - c=test_string[temp_str_len]; - } - tmp_pos=test_string+temp_str_len; - if (*tmp_pos == 0) - break_loop = true; - *tmp_pos = 0; - if (temp_str_len) - { - if ( decode_step == 1) - pQuestTable[i+1] =RemoveQuotes(test_string); - } - else - { - break_loop = true; - } - ++decode_step; - test_string=tmp_pos+1; - } while ((decode_step<2)&&!break_loop); - } - } - -//----- (004B29F2) -------------------------------------------------------- -const char * ContractSelectText( int pEventCode ) -{ - static const int dialogue_base=110; - contract_approved = 0; - dword_F8B1AC_award_bit_number = pEventCode + 50; - gold_transaction_amount = price_for_membership[pEventCode]; - if ( pPlayers[uActiveCharacter]->CanAct() ) - { - if ( (unsigned __int16)_449B57_test_bit((unsigned __int8 *)pPlayers[uActiveCharacter]->_achieved_awards_bits, dword_F8B1AC_award_bit_number) ) - return pNPCTopics[dialogue_base+13].pText; - else - { - if ( (unsigned int)gold_transaction_amount <= pParty->uNumGold ) - { - contract_approved = 1; - return pNPCTopics[pEventCode + dialogue_base].pText; - } - else - return pNPCTopics[dialogue_base+14].pText; - } - } - else - return pNPCTopics[dialogue_base+12].pText; -} -//----- (004B40E6) -------------------------------------------------------- -void NPCHireableDialogPrepare() - { - signed int v0; // ebx@1 - NPCData *v1; // edi@1 - - v0 = 0; - v1 = HouseNPCData[(unsigned int)((char *)pDialogueNPCCount + -(dword_591080 != 0) )];//- 1 - pDialogueWindow->Release(); - pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 350, WINDOW_MainMenu, 0, 0); - pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 0x1BDu, 0xA9u, 0x23u, 1, 0, UIMSG_Escape, 0, 0, - pGlobalTXT_LocalizationStrings[34], //"Cancel" - pIcons_LOD->GetTexture(uExitCancelTextureId), - 0); - pDialogueWindow->CreateButton(0, 0, 0, 0, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0); - if ( pNPCStats->pProfessions[v1->uProfession].pBenefits)//*(&pNPCStats->field_13A5C + 5 * v1->uProfession) ) - { - pDialogueWindow->CreateButton( 480, 0xA0u, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Du, 0, - pGlobalTXT_LocalizationStrings[407], 0);//"More Information" - v0 = 1; - } - pDialogueWindow->CreateButton( 0x1E0u, 30 * v0 + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x4Cu, 0, - pGlobalTXT_LocalizationStrings[406], 0); //"Hire" - pDialogueWindow->_41D08F_set_keyboard_control_group(v0 + 1, 1, 0, 2); - dialog_menu_id = HOUSE_DIALOGUE_OTHER; -} - -//----- (004B4224) -------------------------------------------------------- -void _4B4224_UpdateNPCTopics( int _this ) - { - int num_menu_buttons; // ebx@1 - int i; // ebp@5 - // signed int v4; // ebp@9 - int v6; // eax@16 - int v8; // eax@21 - int v10; // eax@26 - int v12; // eax@31 - int v14; // eax@36 - int v16; // eax@41 - NPCData *v17; // [sp+10h] [bp-4h]@4 - - num_menu_buttons = 0; - pDialogueNPCCount = (_this + 1); - if ( _this + 1 == uNumDialogueNPCPortraits && uHouse_ExitPic ) - { - pDialogueWindow->Release(); - pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_MainMenu, 0, 0); - sprintfex(sHouseName.data(), pGlobalTXT_LocalizationStrings[LOCSTR_ENTER_S], pMapStats->pInfos[uHouse_ExitPic].pName); - pBtn_ExitCancel = pDialogueWindow->CreateButton(566, 445, 75, 33, 1, 0, UIMSG_Escape, 0, 'N', pGlobalTXT_LocalizationStrings[34], pIcons_LOD->GetTexture(uTextureID_BUTTDESC2), 0);// "Cancel" - pBtn_YES = pDialogueWindow->CreateButton(486, 445, 75, 33, 1, 0, UIMSG_BF, 1, 'Y', sHouseName.data(), pIcons_LOD->GetTexture(uTextureID_BUTTYES2), 0); - pDialogueWindow->CreateButton( pNPCPortraits_x[0][0], pNPCPortraits_y[0][0], 63u, 73u, 1, 0, UIMSG_BF, 1u, 0x20u, sHouseName.data(), 0); - pDialogueWindow->CreateButton(8, 8, 460, 344, 1, 0, UIMSG_BF, 1, 0x59u, sHouseName.data(), 0); - } - else - { - v17 = HouseNPCData[_this + 1 - ((dword_591080 != 0)?1:0 )];//+ 1 - if ( dialog_menu_id == HOUSE_DIALOGUE_OTHER ) - { - pDialogueWindow->Release(); - } - else - { - for ( i = 0; i < uNumDialogueNPCPortraits; ++i ) - HouseNPCPortraitsButtonsList[i]->Release(); - } - pDialogueWindow = GUIWindow::Create(0, 0, window->GetWidth(), 345, WINDOW_MainMenu, 0, 0); - pBtn_ExitCancel = pDialogueWindow->CreateButton( 471, 445, 169, 35, 1, 0, UIMSG_Escape, 0, 0, - pGlobalTXT_LocalizationStrings[74],// "End Conversation" - pIcons_LOD->GetTexture(uExitCancelTextureId), 0); - pDialogueWindow->CreateButton(8, 8, 450, 320, 1, 0, UIMSG_BuyInShop_Identify_Repair, 0, 0, "", 0); - if ( pDialogueNPCCount == 1 && dword_591080 ) - { - InitializaDialogueOptions(in_current_building_type); - } - else - { - if ( v17->joins ) - { - num_menu_buttons = 1; - pDialogueWindow->CreateButton(480u, 160u, 140u, 30, 1, 0, UIMSG_ClickNPCTopic, 0xDu, 0, "", 0); - } - if ( v17->evt_A) - { - if ( num_menu_buttons < 4 ) - { - v6 = NPC_EventProcessor(v17->evt_A); - if ( v6 == 1 || v6 == 2 ) - pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x13u, 0, "", 0); - } - } - if ( v17->evt_B ) - { - if ( num_menu_buttons < 4 ) - { - v8 = NPC_EventProcessor(v17->evt_B); - if ( v8 == 1 || v8 == 2 ) - pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x14u, 0, "", 0); - } - } - if ( v17->evt_C ) - { - if ( num_menu_buttons < 4 ) - { - v10 = NPC_EventProcessor(v17->evt_C); - if ( v10 == 1 || v10 == 2 ) - pDialogueWindow->CreateButton( 480u, 30 * num_menu_buttons++ + 160, 140u, 30u, 1, 0, UIMSG_ClickNPCTopic, 0x15u, 0, "", 0); - } - } - - if ( v17->evt_D ) - { - if ( num_menu_buttons < 4 ) - { - v12 = NPC_EventProcessor(v17->evt_D); - if ( v12 == 1 || v12 == 2 ) - pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x16u, 0, "", 0); - } - } - if ( v17->evt_E ) - { - if ( num_menu_buttons < 4 ) - { - v14 = NPC_EventProcessor(v17->evt_E); - if ( v14 == 1 || v14 == 2 ) - pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x17u, 0, "", 0); - } - } - if ( v17->evt_F ) - { - if ( num_menu_buttons < 4 ) - { - v16 = NPC_EventProcessor(v17->evt_F); - if ( v16 == 1 || v16 == 2 ) - pDialogueWindow->CreateButton( 0x1E0u, 30 * num_menu_buttons++ + 160, 0x8Cu, 0x1Eu, 1, 0, UIMSG_ClickNPCTopic, 0x18u, 0, "", 0); - } - } - pDialogueWindow->_41D08F_set_keyboard_control_group(num_menu_buttons, 1, 0, 2); - dword_F8B1E0 = pDialogueWindow->pNumPresenceButton; - } - dialog_menu_id = HOUSE_DIALOGUE_MAIN; - } - -} -//----- (004466C4) -------------------------------------------------------- -int NPC_EventProcessor(int npc_event_id, int entry_line) - { - signed int event_index; // ebp@1 - int evt_seq_num; // esi@3 - bool ready_to_exit; // [sp+Ch] [bp-Ch]@3 - signed int npc_activity; // [sp+10h] [bp-8h]@3 - int result; - - event_index = 0; - if ( !npc_event_id ) - return 0; - evt_seq_num = entry_line; - pSomeOtherEVT = pGlobalEVT.data(); - uSomeOtherEVT_NumEvents = uGlobalEVT_NumEvents; - memcpy(pSomeOtherEVT_Events.data(), pGlobalEVT_Index.data(), sizeof(EventIndex)*4400); - npc_activity = 1; - ready_to_exit = false; - if ( uSomeOtherEVT_NumEvents <= 0 ) - return 2; - do - { - if ( (pSomeOtherEVT_Events[event_index].uEventID == npc_event_id) && (pSomeOtherEVT_Events[event_index].event_sequence_num == evt_seq_num) ) - { - _evt_raw *_evt = (_evt_raw *)&pSomeOtherEVT[pSomeOtherEVT_Events[event_index].uEventOffsetInEVT]; - switch(_evt->_e_type) - { - case EVENT_Exit: - //exit - if ( ready_to_exit ) - result = npc_activity != 0; - else - result = 2; - return result; - break; - case EVENT_OnCanShowDialogItemCmp: - ready_to_exit = true; - //v8 = (unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + (((unsigned __int8)v7[9] + ((unsigned __int8)v7[10] << 8)) << 8)) << 8); - for(int i=0; i<4; ++i) - { - // if (pParty->pPlayers[i].CompareVariable((enum VariableType)((unsigned __int8)pSomeOtherEVT[v6 + 5] + ((unsigned __int8)pSomeOtherEVT[v6 + 6] << 8)), - // v8)) - if (pParty->pPlayers[i].CompareVariable((enum VariableType)EVT_WORD(_evt->v5), EVT_DWORD(_evt->v7))) - { - event_index = -1; - evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1; - break; - } - } - break; - case EVENT_EndCanShowDialogItem : - if ( ready_to_exit ) - result = npc_activity != 0; - else - result = 2; - return result; - break; - case EVENT_SetCanShowDialogItem : - ready_to_exit = true; - npc_activity = EVT_BYTE(_evt->v5); //(unsigned __int8)v7[5]; - break; - case EVENT_IsActorAssasinated : - // if (IsActorAlive( (unsigned __int8)v7[5], - // (unsigned __int8)v7[6] + (((unsigned __int8)v7[7] + (((unsigned __int8)v7[8] + ((unsigned __int8)v7[9] << 8)) << 8)) << 8), - // (unsigned __int8)v7[10]) ) - if (IsActorAlive( EVT_BYTE(_evt->v5), EVT_DWORD(_evt->v6), EVT_BYTE(_evt->v10))) - { // drop linear sequense, going to new seq - event_index = -1; - evt_seq_num = EVT_BYTE(_evt->v11)-1;//(unsigned __int8)pSomeOtherEVT[v6 + 11] - 1; - } - break; - } - ++evt_seq_num; - } - ++event_index; - } - while ( event_index < uSomeOtherEVT_NumEvents ); - if ( ready_to_exit ) - result = npc_activity != 0; - else - result = 2; - return result; -} -//----- (00445C8B) -------------------------------------------------------- -int __fastcall GetGreetType(signed int SpeakingNPC_ID) -{ - signed int v1; // ebx@1 - int v3; // edi@6 - int v4; // ecx@6 - int v5; // edx@6 - NPCData *v6; // eax@6 - char *v7; // ebp@11 - NPCData *v8; // esi@11 - - v1 = 0; - if ( SpeakingNPC_ID >= 0 ) - { - if ( SpeakingNPC_ID < 5000 ) - return 1;//QuestNPC_greet - return 2;//HiredNPC_greet - } - if ( SpeakingNPC_ID >= 5000 ) - return 2; - v3 = abs((int)sDialogue_SpeakingActorNPC_ID) - 1; - v4 = 0; - v5 = 0; - v6 = pParty->pHirelings.data(); - do - { - if ( v6->pName ) - pTmpBuf[v4++] = v5; - ++v6; - ++v5; - } - while ( (signed int)v6 < (signed int)&pParty->pPickedItem ); - if ( (signed int)pNPCStats->uNumNewNPCs > 0 ) - { - v7 = &pTmpBuf[v4]; - v8 = pNPCStats->pNewNPCData; - do - { - if (v8->Hired() && (!pParty->pHirelings[0].pName || strcmp(v8->pName, pParty->pHirelings[0].pName)) ) - { - if ( !pParty->pHirelings[1].pName || strcmp(v8->pName, pParty->pHirelings[1].pName) ) - *v7++ = v1 + 2; - } - ++v1; - ++v8; - } - while ( v1 < (signed int)pNPCStats->uNumNewNPCs ); - } - return ((unsigned __int8)pTmpBuf[v3] < 2) + 1; -} -//----- (00445308) -------------------------------------------------------- -const char *GetProfessionActionText(int a1) -{ - if ( a1 == 10 - || a1 == 11 - || a1 == 12 - || a1 == 33 - || a1 == 34 - || a1 == 39 - || a1 == 40 - || a1 == 41 - || a1 == 42 - || a1 == 43 - || a1 == 52 ) - return pNPCStats->pProfessions[a1 - 1].pActionText; - else - return pNPCTopics[407].pTopic; -} - -//----- (004BB756) -------------------------------------------------------- -int UseNPCSkill(NPCProf profession) -{ - switch (profession) - { - case Healer: - { - for (int i = 0; i < 4; ++i) - pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); - } - break; - - case ExpertHealer: - { - for (int i = 0; i < 4; ++i) - { - __debugbreak(); - pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); - - for (int j = 0; j < 14; ++j) - pParty->pPlayers[i].pConditions[j] = 0; - pParty->pPlayers[i].pConditions[Condition_Good] = 0; - } - } - break; - - case MasterHealer: - { - for (int i = 0; i < 4; ++i) - { - __debugbreak(); //Ritor1:needed cleaned(Íåîáõîäèìî ïî÷èñòèòü) - Player* player = &pParty->pPlayers[i]; - pParty->pPlayers[i].sHealth = pParty->pPlayers[i].GetMaxHealth(); - - int v5 = LODWORD(player->pConditions[19]);//*((int *)v4 - 32); - int v6 = HIDWORD(player->pConditions[19]);//*((int *)v4 - 31); - memset(&pParty->pPlayers[i].pConditions, 0, sizeof(pParty->pPlayers[i].pConditions)); - - *(int *)&player->pActiveSkills[PLAYER_SKILL_SHIELD] = v5; - *(int *)&player->pActiveSkills[PLAYER_SKILL_CHAIN] = v6; - } - } - break; - - case Cook://Ïîâàð - { - if (pParty->uNumFoodRations >= 13) - return 1; - - Party::GiveFood(1); - } - break; - - case Chef: - { - if (pParty->uNumFoodRations >= 13) - return 1; - - if (pParty->uNumFoodRations == 13) - Party::GiveFood(1); - else - Party::GiveFood(2); - } - break; - - case WindMaster: - { - if (uCurrentlyLoadedLevelType == LEVEL_Indoor) - { - ShowStatusBarString(pGlobalTXT_LocalizationStrings[494], 2);//Íåëüçÿ ïðèìåíèòü çíàíèå Ïîëåò â ïîìåùåíèè! - pAudioPlayer->PlaySound(SOUND_203, 0, 0, -1, 0, 0, 0, 0); - } - else - { - int v19 = pOtherOverlayList->_4418B1(10008, 203, 0, 65536); - pParty->pPartyBuffs[PARTY_BUFF_FLY].Apply(pParty->uTimePlayed + 60 * (256 * 2), 3, 1, v19, 0); - pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags |= 1; - pAudioPlayer->PlaySound(SOUND_11090, 0, 0, -1, 0, 0, 0, 0); - } - } - break; - - case WaterMaster: - { - int v20 = pOtherOverlayList->_4418B1(10005, 201, 0, 65536); - pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].Apply(pParty->uTimePlayed + 60 * (256 * (2 + 1)), 3, 0, v20, 0); - pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags |= 1; - pAudioPlayer->PlaySound(SOUND_12040, 0, 0, -1, 0, 0, 0, 0); - } - break; - - case GateMaster: - { - pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); - dword_50C9DC = 195; - ptr_50C9E0 = GetNPCData(sDialogue_SpeakingActorNPC_ID); - } - break; - - case Acolyte: _42777D_CastSpell_UseWand_ShootArrow(46, 0, 133, 0, 0); break; - case Piper: _42777D_CastSpell_UseWand_ShootArrow(51, 0, 133, 0, 0); break; - case FallenWizard: _42777D_CastSpell_UseWand_ShootArrow(86, 0, 133, 0, 0); break; - - case Teacher: - case Instructor: - case Armsmaster: - case Weaponsmaster: - case Apprentice: - case Mystic: - case Spellmaster: - case Trader: - case Merchant: - case Scout: - case Herbalist: - case Apothecary: - case Tinker: - case Locksmith: - case Fool: - case ChimneySweep: - case Porter: - case QuarterMaster: - case Factor: - case Banker: - case Horseman: - case Bard: - case Enchanter: - case Cartographer: - case Explorer: - case Pirate: - case Squire: - case Psychic: - case Gypsy: - case Diplomat: - case Duper: - case Burglar: - case Acolyte2: - case Initiate: - case Prelate: - case Monk: - case Sage: - case Hunter: - break; - - default: - assert(false && "Invalid enum value"); - } - return 0; -} \ No newline at end of file
--- a/NPC.h Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -#pragma once - -enum NPCProf -{ - Smith = 1, // GM Weapon Repair; - Armorer = 2, // GM Armor Repair; - Alchemist = 3, // GM Potion Repair; - Scholar = 4, // GM Item ID; Learning: +5 - Guide = 5, // Travel by foot: -1 day; - Tracker = 6, // Travel by foot: -2 days; - Pathfinder = 7, // Travel by foot: -3 days; - Sailor = 8, // Travel by sea: -2 days; - Navigator = 9, // Travel by sea: -3 days; - Healer = 10, - ExpertHealer = 11, - MasterHealer = 12, - Teacher = 13, // Learning: +10; - Instructor = 14, // Learning: +15; - Armsmaster = 15, // Armsmaster: +2; - Weaponsmaster = 16, // Armsmaster: +3; - Apprentice = 17, // Fire: +2; Air: +2; Water: +2; Earth: +2; - Mystic = 18, // Fire: +3; Air: +3; Water: +3; Earth: +3; - Spellmaster = 19, // Fire: +4; Air: +4; Water: +4; Earth: +4; - Trader = 20, // Merchant: +4; - Merchant = 21, // Merchant: +6; - Scout = 22, // Perception: +6; - Herbalist = 23, // Alchemy: +4; - Apothecary = 24, // Alchemy: +8; - Tinker = 25, // Traps: +4; - Locksmith = 26, // Traps: +6; - Fool = 27, // Luck: +5; - ChimneySweep = 28, // Luck: +20; - Porter = 29, // Food for rest: -1; - QuarterMaster = 30, // Food for rest: -2; - Factor = 31, // Gold finds: +10%; - Banker = 32, // Gold finds: +20%; - Cook = 33, - Chef = 34, - Horseman = 35, // Travel by foot: -2 days; - Bard = 36, - Enchanter = 37, // Resist All: +20; - Cartographer = 38, // Wizard Eye level 2; - WindMaster = 39, - WaterMaster = 40, - GateMaster = 41, - Acolyte = 42, - Piper = 43, - Explorer = 44, // Travel by foot -1 day; Travel by sea: -1 day; - Pirate = 45, // Travel by sea: -2 days; Gold finds: +10%; Reputation: +5; - Squire = 46, - Psychic = 47, // Perception: +5; Luck: +10; - Gypsy = 48, // Food for rest: -1; Merchant: +3; Reputation: +5; - Diplomat = 49, - Duper = 50, // Merchant: +8; Reputation: +5; - Burglar = 51, // Traps: +8; Stealing: +8; Reputation: +5; - FallenWizard = 52, // Reputation: +5; - Acolyte2 = 53, // Spirit: +2; Mind: +2; Body: +2; - Initiate = 54, // Spirit: +3; Mind: +3; Body: +3; - Prelate = 55, // Spirit: +4; Mind: +4; Body: +4; - Monk = 56, // Unarmed: +2; Dodge: +2; - Sage = 57, // Monster ID: +6 - Hunter = 58 // Monster ID: +6 -}; - - - -struct NPCTopic -{ - const char *pTopic; - const char *pText; -}; - -extern std::array<NPCTopic, 789> pNPCTopics; - - -/* 136 */ -#pragma pack(push, 1) -struct NPCData //4Ch -{ - inline bool Hired() {return (uFlags & 0x80) != 0;} - - char *pName; //0 - unsigned int uPortraitID; //4 - unsigned int uFlags; //8 // & 0x80 no greeting on dialogue start; looks like hired - int fame; //c - int rep; //10 - unsigned int Location2D; //14 - unsigned int uProfession; //18 - int greet; //1c - int joins; //20 - int field_24; - unsigned int evt_A; //28 - unsigned int evt_B; //2c evtb - unsigned int evt_C; // 30 evtc - unsigned int evt_D; //34 - unsigned int evt_E; //38 - unsigned int evt_F; //3c - unsigned int uSex; //40 - int bHasUsedTheAbility; //44 - int news_topic; //48 -}; -#pragma pack(pop) - - -/* 138 */ -#pragma pack(push, 1) -struct NPCProfession -{ - inline NPCProfession(): - uHirePrice(0), pBenefits(nullptr), pActionText(nullptr), pJoinText(nullptr), pDismissText(nullptr) - {} - - unsigned int uHirePrice; - char *pBenefits; - char *pActionText; - char *pJoinText; - char *pDismissText; -}; -#pragma pack(pop) - - -/* 139 */ -#pragma pack(push, 1) -struct NPCProfessionChance -{ - unsigned int uTotalprofChance; //summ - char professionChancePerArea[60]; //prof position -}; -#pragma pack(pop) - -/* 140 */ -#pragma pack(push, 1) -struct NPCGreeting -{ - union - { - struct - { - char *pGreeting1; //at first meet - char *pGreeting2; // at latest meets - }; - char *pGreetings[2]; - }; -}; -#pragma pack(pop) - - -/* 137 */ -#pragma pack(push, 1) -struct NPCStats -{ - inline NPCStats(): - pNPCTextTXT_Raw(nullptr), pNPCTopicTXT_Raw(nullptr), pNPCDistTXT_Raw(nullptr) - { - uNumNPCNames[0] = uNumNPCNames[1] = 0; - } - - void InitializeNPCText(); - void InitializeNPCData(); - void Initialize(); - void Release(); - void InitializeAdditionalNPCs(NPCData *pNPCDataBuff, int npc_uid, int uLocation2D, int uMapId); - void _476C60(); - char * sub_495366_MispronounceName(unsigned __int8 firstLetter, unsigned __int8 genderId); - - - NPCData pNPCData[501]; //0 - 94BCh count from 1 - NPCData pNewNPCData[501]; //94BCh- 12978h count from 1 - char *pNPCNames[540][2]; - NPCProfession pProfessions[59]; //count from 1 - NPCData pAdditionalNPC[100]; - char *pCatchPhrases[52]; //15CA4h - char *pNPCUnicNames[500]; //from first batch - NPCProfessionChance pProfessionChance[77]; //16544h profession chance in each area - int field_17884; - int field_17888; - NPCGreeting pNPCGreetings[205]; - unsigned __int16 pGroups[51]; - unsigned __int16 pGroups_copy[51]; - unsigned int uNewlNPCBufPos; - unsigned int uNumNewNPCs; - int field_17FC8; - unsigned int uNumNPCProfessions; - unsigned int uNumNPCNames[2]; //0 male 1 female - char *pNPCDataTXT_Raw; - char *pNPCNamesTXT_Raw; - char *pNPCProfTXT_Raw; - char *pNPCNewsTXT_Raw; - char *pNPCTopicTXT_Raw; - char *pNPCTextTXT_Raw; - char *pNPCDistTXT_Raw; - char *pNPCGreetTXT_Raw; - char *pNCPGroupTXT_Raw; - - static int dword_AE336C_LastMispronouncedNameFirstLetter; - static int dword_AE3370_LastMispronouncedNameResult; -}; -#pragma pack(pop) - -extern int pDialogueNPCCount; -extern std::array<struct Texture *, 6> pDialogueNPCPortraits; -extern int uNumDialogueNPCPortraits; // weak -extern struct NPCStats *pNPCStats; - -bool PartyHasDragon(); -bool CheckHiredNPCSpeciality(unsigned int uProfession); - -int UseNPCSkill(NPCProf profession); -const char *ContractSelectText(int pEventCode); -void NPCHireableDialogPrepare(); -void _4B4224_UpdateNPCTopics(int _this); -const char *GetProfessionActionText(int a1); -struct NPCData *__fastcall GetNPCData(signed int npcid); -struct NPCData * GetNewNPCData(signed int npcid, int* npc_indx); -int __fastcall GetGreetType(signed int SpeakingNPC_ID); -int NPC_EventProcessor(int npc_event_id, int entry_line = 0);
--- a/ObjectList.cpp Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,280 +0,0 @@ -#define _CRTDBG_MAP_ALLOC -#include <stdlib.h> -#include <crtdbg.h> - -#define _CRT_SECURE_NO_WARNINGS -#include "ObjectList.h" -#include "mm7_data.h" -#include "Engine/Graphics/Sprites.h" -#include "FrameTableInc.h" -#include "ErrorHandling.h" - -//----- (0042EB42) -------------------------------------------------------- -__int16 ObjectList::ObjectIDByItemID(unsigned __int16 uItemID) -{ - unsigned int v2; // edx@1 - signed int v3; // eax@1 - char *v4; // ecx@2 - - v2 = this->uNumObjects; - v3 = 0; - if ( (signed int)this->uNumObjects <= 0 ) - { -LABEL_5: - LOWORD(v3) = 0; - } - else - { - v4 = (char *)&this->pObjects->uObjectID; - while ( uItemID != *(short *)v4 ) - { - ++v3; - v4 += 56; - if ( v3 >= (signed int)v2 ) - goto LABEL_5; - } - } - return v3; -} -//----- (00459064) -------------------------------------------------------- -void ObjectList::InitializeSprites() -{ - for (uint i = 0; i < uNumObjects; ++i) - pSpriteFrameTable->InitializeSprite(pObjects[i].uSpriteID); -} - -//----- (00459090) -------------------------------------------------------- -void ObjectList::ToFile() -{ - ObjectList *v1; // esi@1 - FILE *v2; // eax@1 - FILE *v3; // edi@1 - - v1 = this; - v2 = fopen("data\\dobjlist.bin", "wb"); - v3 = v2; - if ( !v2 ) - Error("Unable to save dobjlist.bin!"); - fwrite(v1, 4u, 1u, v2); - fwrite(v1->pObjects, 0x38u, v1->uNumObjects, v3); - fclose(v3); -} - -//----- (004590DC) -------------------------------------------------------- -void ObjectList::FromFile(void *data_mm6, void *data_mm7, void *data_mm8) -{ - uint num_mm6_objs = data_mm6 ? *(int *)data_mm6 : 0, - num_mm7_objs = data_mm7 ? *(int *)data_mm7 : 0, - num_mm8_objs = data_mm8 ? *(int *)data_mm8 : 0; - - uNumObjects = num_mm6_objs + num_mm7_objs + num_mm8_objs; - Assert(uNumObjects); - Assert(!num_mm8_objs); - - pObjects = (ObjectDesc *)malloc(uNumObjects * sizeof(ObjectDesc)); - memcpy(pObjects, (char *)data_mm7 + 4, num_mm7_objs * sizeof(ObjectDesc)); - for (uint i = 0; i < num_mm6_objs; ++i) - { - auto src = (ObjectDesc_mm6 *)((char *)data_mm6 + 4) + i; - ObjectDesc* dst = &pObjects[num_mm7_objs + i]; - memcpy(dst->field_0, src->field_0, sizeof(dst->field_0)); - dst->uObjectID = src->uObjectID; - dst->uRadius = src->uRadius; - dst->uHeight = src->uHeight; - dst->uFlags = src->uFlags; - dst->uSpriteID = src->uSpriteID; - dst->uLifetime = src->uLifetime; - dst->uParticleTrailColor = src->uParticleTrailColor; - dst->uSpeed = src->uSpeed; - dst->uParticleTrailColorR = src->uParticleTrailColorR; - dst->uParticleTrailColorG = src->uParticleTrailColorG; - dst->uParticleTrailColorB = src->uParticleTrailColorB; - dst->field_35_clr = src->field_35_clr; - dst->field_36_clr = 0; - dst->field_37_clr = 0; - } -} - -//----- (00459123) -------------------------------------------------------- -bool ObjectList::FromFileTxt(const char *Args) -{ - ObjectList *v2; // ebx@1 - __int32 v3; // edi@1 - FILE *v4; // eax@1 - unsigned int v5; // esi@3 - void *v6; // eax@9 - FILE *v7; // ST0C_4@11 - char *i; // eax@11 - unsigned __int16 v9; // ax@14 - const char *v10; // ST20_4@14 - __int16 v11; // ax@14 - const char *v12; // ST1C_4@14 - __int16 v13; // ax@14 - const char *v14; // ST18_4@14 - __int16 v15; // ax@14 - const char *v16; // ST14_4@14 - __int16 v17; // ax@14 - const char *v18; // ST10_4@14 - __int16 v19; // ax@14 - const char *v20; // ST0C_4@14 - int v21; // esi@16 - const char *v22; // edi@16 - int v23; // eax@17 - int v24; // eax@19 - int v25; // eax@21 - int v26; // eax@21 - int v27; // eax@21 - int v28; // eax@23 - int v29; // eax@25 - int v30; // eax@27 - int v31; // eax@29 - const char *v32; // edi@30 - const char *v33; // ST20_4@35 - int v34; // eax@35 - char v35; // al@35 - const char *v36; // ST1C_4@35 - char v37; // al@35 - const char *v38; // ST18_4@35 - FrameTableTxtLine v40; // [sp+8h] [bp-460h]@14 - FrameTableTxtLine v41; // [sp+84h] [bp-3E4h]@12 - char Dest; // [sp+100h] [bp-368h]@14 - char Buf; // [sp+178h] [bp-2F0h]@3 - FrameTableTxtLine v44; // [sp+36Ch] [bp-FCh]@4 - FrameTableTxtLine v45; // [sp+3E8h] [bp-80h]@4 - FILE *File; // [sp+464h] [bp-4h]@1 - unsigned int Argsa; // [sp+470h] [bp+8h]@3 - int Argsb; // [sp+470h] [bp+8h]@15 - - v2 = this; - free(this->pObjects); - v3 = 0; - v2->pObjects = nullptr; - v2->uNumObjects = 0; - v4 = fopen(Args, "r"); - File = v4; - if ( !v4 ) - Error("ObjectDescriptionList::load - Unable to open file: %s."); - - v5 = 0; - Argsa = 0; - if ( fgets(&Buf, 490, v4) ) - { - do - { - *strchr(&Buf, 10) = 0; - memcpy(&v45, frame_table_txt_parser(&Buf, &v44), sizeof(v45)); - if ( v45.uPropCount && *v45.pProperties[0] != '/' ) - ++Argsa; - } - while ( fgets(&Buf, 490, File) ); - v5 = Argsa; - v3 = 0; - } - v2->uNumObjects = v5; - v6 = malloc(56 * v5); - v2->pObjects = (ObjectDesc *)v6; - if ( v6 == (void *)v3 ) - Error("ObjectDescriptionList::load - Out of Memory!"); - - memset(v6, v3, 56 * v2->uNumObjects); - v7 = File; - v2->uNumObjects = v3; - fseek(v7, v3, v3); - for ( i = fgets(&Buf, 490, File); i; i = fgets(&Buf, 490, File) ) - { - *strchr(&Buf, 10) = 0; - memcpy(&v45, frame_table_txt_parser(&Buf, &v41), sizeof(v45)); - if ( v45.uPropCount && *v45.pProperties[0] != 47 ) - { - strcpy(v2->pObjects[v2->uNumObjects].field_0, v45.pProperties[0]); - v9 = pSpriteFrameTable->FastFindSprite((char *)v45.pProperties[1]); - v10 = v45.pProperties[2]; - v2->pObjects[v2->uNumObjects].uSpriteID = v9; - v11 = atoi(v10); - v12 = v45.pProperties[3]; - v2->pObjects[v2->uNumObjects].uObjectID = v11; - v13 = atoi(v12); - v14 = v45.pProperties[4]; - v2->pObjects[v2->uNumObjects].uRadius = v13; - v15 = atoi(v14); - v16 = v45.pProperties[5]; - v2->pObjects[v2->uNumObjects].uHeight = v15; - v17 = atoi(v16); - v18 = v45.pProperties[6]; - v2->pObjects[v2->uNumObjects].uLifetime = v17; - v19 = atoi(v18); - v20 = v45.pProperties[7]; - v2->pObjects[v2->uNumObjects].uSpeed = v19; - strcpy(&Dest, v20); - memcpy(&v44, frame_table_txt_parser(&Dest, &v40), sizeof(v44)); - if ( v45.uPropCount > 7 ) - { - for ( Argsb = 0; Argsb < v44.uPropCount; ++Argsb ) - { - v21 = Argsb; - v22 = v44.pProperties[Argsb]; - if ( !_stricmp(v44.pProperties[Argsb], "NoDraw") ) - { - v23 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v23 |= 1u; - } - if ( !_stricmp(v22, "Lifetime") ) - { - v24 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v24 |= 4u; - } - if ( !_stricmp(v22, "FTLifetime") ) - { - v25 = (int)&v2->pObjects[v2->uNumObjects]; - *(short *)(v25 + 42) = 8 * pSpriteFrameTable->pSpriteSFrames[*(short *)(v25 + 40)].uAnimLength; - v26 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v26 |= 8u; - v27 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v27 |= 4u; - } - if ( !_stricmp(v22, "NoPickup") ) - { - v28 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v28 |= 0x10u; - } - if ( !_stricmp(v22, "NoGravity") ) - { - v29 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v29 |= 0x20u; - } - if ( !_stricmp(v22, "FlagOnIntercept") ) - { - v30 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v30 |= 0x40u; - } - if ( !_stricmp(v22, "Bounce") ) - { - v31 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)v31 |= 0x80u; - } - v32 = v45.pProperties[v21]; - if ( !_stricmp(v45.pProperties[v21], "Fire") ) - HIBYTE(v2->pObjects[v2->uNumObjects].uFlags) |= 2u; - if ( !_stricmp(v32, "Lines") ) - HIBYTE(v2->pObjects[v2->uNumObjects].uFlags) |= 4u; - if ( !_stricmp(v44.pProperties[v21], "bits") ) - { - v33 = v44.pProperties[v21 + 1]; - v34 = (int)&v2->pObjects[v2->uNumObjects].uFlags; - *(char *)(v34 + 1) |= 1u; - v35 = atoi(v33); - v36 = v44.pProperties[v21 + 2]; - v2->pObjects[v2->uNumObjects].uParticleTrailColorR = v35; - v37 = atoi(v36); - v38 = v44.pProperties[v21 + 3]; - v2->pObjects[v2->uNumObjects].uParticleTrailColorG = v37; - v2->pObjects[v2->uNumObjects].uParticleTrailColorB = atoi(v38); - } - } - } - ++v2->uNumObjects; - } - } - fclose(File); - return 1; -} \ No newline at end of file
--- a/ObjectList.h Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -#pragma once - - - - -/* 324 */ -enum OBJECT_DESC_FLAGS -{ - OBJECT_DESC_NO_SPRITE = 0x1, - OBJECT_DESC_NO_COLLISION = 0x2, - OBJECT_DESC_TEMPORARY = 0x4, - OBJECT_DESC_SFT_LIFETIME = 0x8, - OBJECT_DESC_UNPICKABLE = 0x10, - OBJECT_DESC_NO_GRAVITY = 0x20, - OBJECT_DESC_INTERACTABLE = 0x40, - OBJECT_DESC_BOUNCE = 0x80, - OBJECT_DESC_TRIAL_PARTICLE = 0x100, - OBJECT_DESC_TRIAL_FIRE = 0x200, - OBJECT_DESC_TRIAL_LINE = 0x400, -}; - - - - -/* 56 */ -#pragma pack(push, 1) -struct ObjectDesc_mm6 -{ - inline bool NoSprite() const {return uFlags & OBJECT_DESC_NO_SPRITE;} - - char field_0[32]; - __int16 uObjectID; - __int16 uRadius; - __int16 uHeight; - __int16 uFlags; - unsigned __int16 uSpriteID; - __int16 uLifetime; - unsigned short uParticleTrailColor; - __int16 uSpeed; - char uParticleTrailColorR; - char uParticleTrailColorG; - char uParticleTrailColorB; - char field_35_clr; -}; - -struct ObjectDesc -{ - inline bool NoSprite() const {return uFlags & OBJECT_DESC_NO_SPRITE;} - - char field_0[32]; - __int16 uObjectID; - __int16 uRadius; - __int16 uHeight; - __int16 uFlags; - unsigned __int16 uSpriteID; - __int16 uLifetime; - unsigned int uParticleTrailColor; - __int16 uSpeed; - unsigned char uParticleTrailColorR; - unsigned char uParticleTrailColorG; - unsigned char uParticleTrailColorB; - char field_35_clr; - char field_36_clr; - char field_37_clr; -}; -#pragma pack(pop) - -/* 57 */ -#pragma pack(push, 1) -struct ObjectList -{ - inline ObjectList(): //----- (004583D5) - uNumObjects(0), pObjects(nullptr) - {} - - void ToFile(); - void FromFile(void *data_mm6, void *data_mm7, void *data_mm8); - bool FromFileTxt(const char *Args); - void InitializeSprites(); - __int16 ObjectIDByItemID(unsigned __int16 uItemID); - - - unsigned int uNumObjects; - struct ObjectDesc *pObjects; -}; -#pragma pack(pop) - -extern struct ObjectList *pObjectList; \ No newline at end of file
--- a/Player.cpp Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8199 +0,0 @@ -#define _CRTDBG_MAP_ALLOC -#include <stdlib.h> -#include <crtdbg.h> - -#define _CRT_SECURE_NO_WARNINGS -#include "stru6.h" - -#include "ErrorHandling.h" - -#include "Player.h" -#include "PlayerFrameTable.h" -#include "AudioPlayer.h" -#include "Party.h" -#include "LOD.h" -#include "GUIWindow.h" -#include "Engine/Graphics/Viewport.h" -#include "Actor.h" -#include "Game.h" -#include "Mouse.h" -#include "TurnEngine.h" -#include "Events.h" -#include "Events2D.h" -#include "Engine/Graphics/Outdoor.h" -#include "StorylineTextTable.h" -#include "Autonotes.h" -#include "Awards.h" -#include "texts.h" - -#include "stru123.h" -#include "stru298.h" -#include "ObjectList.h" -#include "MM7.h" -#include "SpriteObject.h" -#include "Engine/Graphics/DecalBuilder.h" -#include "CastSpellInfo.h" -#include "OurMath.h" -#include "UI\UIPartyCreation.h" - - - - -NZIArray<struct Player *, 5> pPlayers; - - -/* 381 */ -#pragma pack(push, 1) -struct PlayerCreation_AttributeProps -{ - unsigned __int8 uBaseValue; - char uMaxValue; - char uDroppedStep; - char uBaseStep; -}; -#pragma pack(pop) - - -#pragma pack(push, 1) - - - -#pragma pack(pop) -PlayerCreation_AttributeProps StatTable[4][7] = //0x4ED7B0 -{ - {{11, 25, 1, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, { 9, 25, 1, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, {9, 25, 1, 1},}, - {{ 7, 15, 2, 1}, {14, 30, 1, 2}, {11, 25, 1, 1}, { 7, 15, 2, 1}, {14, 30, 1, 2}, {11, 25, 1, 1}, {9, 20, 1, 1},}, - {{14, 30, 1, 2}, { 7, 15, 2, 1}, { 7, 15, 2, 1}, {11, 25, 1, 1}, {11, 25, 1, 1}, {14, 30, 1, 2}, {9, 20, 1, 1},}, - {{14, 30, 1, 2}, {11, 25, 1, 1}, {11, 25, 1, 1}, {14, 30, 1, 2}, { 7, 15, 2, 1}, { 7, 15, 2, 1}, {9, 20, 1, 1}} -}; - - - -std::array<int, 5> StealingMasteryBonuses = {0, 100, 200, 300, 500}; //dword_4EDEA0 //the zeroth element isn't accessed, it just helps avoid -1 indexing, originally 4 element array off by one -std::array<int, 5> StealingRandomBonuses = {-200, -100, 0, 100, 200}; //dword_4EDEB4 -std::array<int, 5> StealingEnchantmentBonusForSkill = {0, 2, 4, 6, 10}; //dword_4EDEC4 //the zeroth element isn't accessed, it just helps avoid -1 indexing, originally 4 element array off by one - - - - // available skills per class ( 9 classes X 37 skills ) - // 0 - not available - // 1 - available - // 2 - primary skill -unsigned char pSkillAvailabilityPerClass[9][37] = // byte[] @ MM7.exe::004ED820 -{ - {0, 2, 0, 1, 1, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 2, 1, 0}, - {1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 1, 0, 1, 1, 2, 0, 0, 0, 1, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, - {0, 1, 1, 2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, - {0, 0, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, - {2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0} // some of these are started at 4ED94C, but needs to be here -}; - - -unsigned char pEquipTypeToBodyAnchor[21] = // 4E8398 -{ - 1, // EQUIP_SINGLE_HANDED - 1, // EQUIP_TWO_HANDED - 2, // EQUIP_BOW - 3, // EQUIP_ARMOUR - 0, // EQUIP_SHIELD - 4, // EQUIP_HELMET - 5, // EQUIP_BELT - 6, // EQUIP_CLOAK - 7, // EQUIP_GAUNTLETS - 8, // EQUIP_BOOTS - 10, // EQUIP_RING - 9, // EQUIP_AMULET - 1, // EQUIP_WAND - 0, // EQUIP_REAGENT - 0, // EQUIP_POTION - 0, // EQUIP_SPELL_SCROLL - 0, // EQUIP_BOOK - 0, // EQUIP_MESSAGE_SCROLL - 0, // EQUIP_GOLD - 0, // EQUIP_GEM - 0 // EQUIP_NONE -}; - - -unsigned char pBaseHealthByClass[12] = {40, 35, 35, 30, 30, 30, 25, 20, 20, 0, 0, 0}; -unsigned char pBaseManaByClass[12] = { 0, 0, 0, 5, 5, 0, 10, 10, 15, 0, 0, 0}; -unsigned char pBaseHealthPerLevelByClass[36] = {5, 7, 9, 9, 4, 6, 8, 8, 5, 6, 8, 8, 4, 5, 6, 6, 3, 4, 6, 6, 4, 5, 6, 6, 2, 3, 4, 4, 2, 3, 4, 4, 2, 3, 3, 3}; -unsigned char pBaseManaPerLevelByClass[36] = {0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 2, 3, 3, 1, 2, 3, 3, 0, 2, 3, 3, 3, 4, 5, 5, 3, 4, 5, 5, 3, 4, 6, 6}; - -unsigned char pConditionAttributeModifier[7][19] = -{{100, 100, 100, 120, 50, 200, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 100, 100}, //Might - {100, 100, 100, 50, 25, 10, 100, 100, 75, 60, 50, 30, 100, 100, 100, 100, 100, 1, 100}, //Intelligence - {100, 100, 100, 50, 25, 10, 100, 100, 75, 60, 50, 30, 100, 100, 100, 100, 100, 1, 100}, //Willpower - {100, 100, 100, 100, 50, 150, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 100, 100}, //Endurance - {100, 100, 100, 50, 10, 100, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 50, 100}, //Accuracy - {100, 100, 100, 120, 20, 120, 75, 60, 50, 30, 25, 10, 100, 100, 100, 100, 100, 50, 100}, //Speed - {100, 100, 100, 100, 200, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100}}; //Luck - -unsigned char pAgingAttributeModifier[7][4] = -{{100, 75, 40, 10}, //Might - {100, 150, 100, 10}, //Intelligence - {100, 150, 100, 10}, //Willpower - {100, 75, 40, 10}, //Endurance - {100, 100, 40, 10}, //Accuracy - {100, 100, 40, 10}, //Speed - {100, 100, 100, 100}}; //Luck - -unsigned int pAgeingTable[4] = {50, 100, 150, 0xFFFF}; - -std::array<unsigned int, 18> pConditionImportancyTable = {{16, 15, 14, 17, 13, 2, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1, 0}}; - -short param_to_bonus_table[29] = {500, 400, 350, 300, 275, 250, 225, 200, 175, - 150, 125, 100, 75, 50, 40, 35, 30, 25, 21, - 19, 17, 15, 13, 11, 9, 7, 5, 3, 0}; -signed int parameter_to_bonus_value[29] = {30, 25, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6}; - - -unsigned short base_recovery_times_per_weapon_type[12] = -{ - 100, // PLAYER_SKILL_STAFF && Unarmed withoud skill - 90, // PLAYER_SKILL_SWORD && Unarmed with skill - 60, // PLAYER_SKILL_DAGGER - 100, // PLAYER_SKILL_AXE - 80, // PLAYER_SKILL_SPEAR - 100, // PLAYER_SKILL_BOW - 80, // PLAYER_SKILL_MACE - 30, // PLAYER_SKILL_BLASTER - 10, // PLAYER_SKILL_SHIELD - 10, // PLAYER_SKILL_LEATHER - 20, // PLAYER_SKILL_CHAIN - 30 // PLAYER_SKILL_PLATE -}; - -//----- (00490913) -------------------------------------------------------- -int PlayerCreation_GetUnspentAttributePointCount() -{ - signed int v0; // edi@1 - int raceId; // ebx@2 - signed int v4; // eax@17 - int v5; // edx@18 - signed int v6; // ecx@18 - signed int remainingStatPoints; // [sp+Ch] [bp-8h]@1 - - remainingStatPoints = 50; - v0 = 50; - for (int playerNum = 0; playerNum < 4; playerNum++) - { - raceId = pParty->pPlayers[playerNum].GetRace(); - for (int statNum = 0; statNum <= 6; statNum++) - { - switch ( statNum ) - { - case 0: - v0 = pParty->pPlayers[playerNum].uMight; - break; - case 1: - v0 = pParty->pPlayers[playerNum].uIntelligence; - break; - case 2: - v0 = pParty->pPlayers[playerNum].uWillpower; - break; - case 3: - v0 = pParty->pPlayers[playerNum].uEndurance; - break; - case 4: - v0 = pParty->pPlayers[playerNum].uAccuracy; - break; - case 5: - v0 = pParty->pPlayers[playerNum].uSpeed; - break; - case 6: - v0 = pParty->pPlayers[playerNum].uLuck; - break; - } - v4 = StatTable[raceId][statNum].uBaseValue; - if ( v0 >= v4 ) - { - v5 = StatTable[raceId][statNum].uDroppedStep; - v6 = StatTable[raceId][statNum].uBaseStep; - } - else - { - v5 = StatTable[raceId][statNum].uBaseStep; - v6 = StatTable[raceId][statNum].uDroppedStep; - } - remainingStatPoints += v5 * (v4 - v0) / v6; - } - } - return remainingStatPoints; -} - -//----- (00427730) -------------------------------------------------------- -bool Player::CanCastSpell(unsigned int uRequiredMana) -{ - if (sMana >= (signed int)uRequiredMana) - { - sMana -= (signed int)uRequiredMana; - return true; - } - - pAudioPlayer->PlaySound(SOUND_PlayerCantCastSpell, 0, 0, -1, 0, 0, 0, 0); - return false; -} - -//----- (004BE2DD) -------------------------------------------------------- -void Player::SalesProcess( unsigned int inventory_idnx, int item_index, int _2devent_idx ) - { - float v6; // ST04_4@1 - signed int item_value; // eax@1 - signed int sell_price; // ebx@1 - - item_value =pOwnItems[item_index].GetValue(); - v6 = p2DEvents[ _2devent_idx - 1].fPriceMultiplier; - sell_price = GetPriceSell(item_value, v6); - if ( pOwnItems[item_index].IsBroken() ) - sell_price = 1; - if ( sell_price < 1 ) - sell_price = 1; - RemoveItemAtInventoryIndex(inventory_idnx); - Party::SetGold(pParty->uNumGold + sell_price); -} - -//----- (0043EEF3) -------------------------------------------------------- -bool Player::NothingOrJustBlastersEquipped() -{ - signed int item_idx; // esi@1 - signed int item_id; // esi@1 - for (int i = 0; i < 16; ++i) - { - item_idx = pEquipment.pIndices[i]; - if (item_idx) - { - item_id = pOwnItems[item_idx - 1].uItemID; - if ( item_id != ITEM_BLASTER && item_id != ITEM_LASER_RIFLE ) //blaster& blaster rifle - return false; - } - } - return true; -} - -//----- (004B8040) -------------------------------------------------------- -int Player::GetConditionDayOfWeek( unsigned int uCondition ) - { - return (unsigned int)(((signed __int64)((double)this->pConditions[uCondition] * 0.234375) / 60 / 60) / 24) % 7 + 1; -} - -//----- (004B807C) -------------------------------------------------------- -int Player::GetTempleHealCostModifier(float a2) -{ - unsigned int conditionIdx; // eax@1 - int conditionTimeMultiplier; // esi@1 - int v6; // eax@8 - signed int result; // qax@13 - signed int baseConditionMultiplier; // [sp+8h] [bp-8h]@4 - - conditionIdx = GetMajorConditionIdx(); - if ( conditionIdx >= 14 && conditionIdx <= 16) - { - if ( conditionIdx <= 15 ) - baseConditionMultiplier = 5; - else //if ( conditionIdx == 16 ) - baseConditionMultiplier = 10; - conditionTimeMultiplier = GetConditionDayOfWeek(conditionIdx); - } - else - { - conditionTimeMultiplier = 1; - baseConditionMultiplier = 1; - if (conditionIdx < 14) - { - for (int i = 0; i <= 13; i++) - { - v6 = GetConditionDayOfWeek(i); - if ( v6 > conditionTimeMultiplier ) - conditionTimeMultiplier = v6; - } - } - } - result = (int)((double)conditionTimeMultiplier * (double)baseConditionMultiplier * a2); - if ( result < 1 ) - result = 1; - return result; -} - -//----- (004B8102) -------------------------------------------------------- -int Player::GetPriceSell(int uRealValue, float price_multiplier) -{ - signed int v3; // esi@1 - signed int result; // eax@3 - - v3 = (signed int)((signed __int64)((double)uRealValue / (price_multiplier + 2.0)) + uRealValue * GetMerchant() / 100); - if ( v3 > uRealValue ) - v3 = uRealValue; - result = 1; - if ( v3 >= 1 ) - result = v3; - return result; -} - -//----- (004B8142) -------------------------------------------------------- -int Player::GetBuyingPrice(unsigned int uRealValue, float price_multiplier) -{ - uint price = (uint)(((100 - GetMerchant()) * (uRealValue * price_multiplier)) / 100); - - if (price < uRealValue) - price = uRealValue; - return price; -} - -//----- (004B8179) -------------------------------------------------------- -int Player::GetPriceIdentification(float a2) -{ - signed int v2; // esi@1 - int v3; // ecx@1 - signed int result; // eax@3 - - v2 = (signed int)(a2 * 50.0); - v3 = v2 * (100 - GetMerchant()) / 100; - if ( v3 < v2 / 3 ) - v3 = v2 / 3; - result = 1; - if ( v3 >= 1 ) - result = v3; - return result; -} - -//----- (004B81C3) -------------------------------------------------------- -int Player::GetPriceRepair(int a2, float a3) -{ - signed int v3; // esi@1 - int v4; // ecx@1 - signed int result; // eax@3 - - v3 = (signed int)((double)a2 / (6.0 - a3)); - v4 = v3 * (100 - GetMerchant()) / 100; - if ( v4 < v3 / 3 ) - v4 = v3 / 3; - result = 1; - if ( v4 >= 1 ) - result = v4; - return result; -} - -//----- (004B8213) -------------------------------------------------------- -int Player::GetBaseSellingPrice(int a2, float a3) -{ - signed int v3; // qax@1 - - v3 = (signed int)((double)a2 / (a3 + 2.0)); - if ( v3 < 1 ) - v3 = 1; - return v3; -} - -//----- (004B8233) -------------------------------------------------------- -int Player::GetBaseBuyingPrice(int a2, float a3) -{ - signed int v3; // qax@1 - - v3 = (signed int)((double)a2 * a3); - if ( v3 < 1 ) - v3 = 1; - return v3; -} - -//----- (004B824B) -------------------------------------------------------- -int Player::GetBaseIdentifyPrice(float a2) -{ - signed int v2; // qax@1 - - v2 = (signed int)(a2 * 50.0); - if ( v2 < 1 ) - v2 = 1; - return v2; -} - -//----- (004B8265) -------------------------------------------------------- -int Player::GetBaseRepairPrice(int a2, float a3) -{ - signed int v3; // qax@1 - - v3 = (signed int)((double)a2 / (6.0 - a3)); - if ( v3 < 1 ) - v3 = 1; - return v3; -} - -//----- (004B6FF9) -------------------------------------------------------- -bool Player::IsPlayerHealableByTemple() -{ - if (this->sHealth >= GetMaxHealth() && this->sMana >= GetMaxMana() && GetMajorConditionIdx() == Condition_Good) - return false; - else - { - if (GetMajorConditionIdx() == Condition_Zombie) - { - if (((signed int)window_SpeakInHouse->ptr_1C == 78 || (signed int)window_SpeakInHouse->ptr_1C == 81 || (signed int)window_SpeakInHouse->ptr_1C == 82)) - return false; - else - return true; - } - else - return true; - } -} - -//----- (00421E75) -------------------------------------------------------- -unsigned int Player::GetItemIDAtInventoryIndex(int *pitem_index) -{ - int item_idx; // eax@1 - int inv_index; // eax@3 - - item_idx = *pitem_index; - if ( item_idx >125 || item_idx < 0 ) - return 0; - inv_index = this->pInventoryMatrix[item_idx]; - if ( inv_index < 0 ) - { - *pitem_index = -1 - inv_index; - inv_index = this->pInventoryMatrix[-1 - inv_index]; - } - return inv_index; -} - -//----- (004160CA) -------------------------------------------------------- -void Player::ItemsEnchant( int enchant_count ) - { - int avalible_items; // ebx@1 - int i; // edx@8 - __int16 item_index_tabl[138]; // [sp+Ch] [bp-118h]@1 - - avalible_items = 0; - memset (item_index_tabl,0,sizeof(item_index_tabl)); - - for (i = 0; i < 138; ++i) - { - if (( pOwnItems[i].uItemID>0)&&(pOwnItems[i].uItemID <= 134)) - item_index_tabl[avalible_items++] = i; - } - - if ( avalible_items ) - { - if ( enchant_count ) - { - for ( i = 0; i < enchant_count; ++i ) - { - if (!(pInventoryItemList[item_index_tabl[i]].uAttributes&ITEM_HARDENED)) - pInventoryItemList[item_index_tabl[rand() % avalible_items]].uAttributes |= ITEM_HARDENED; - } - } - else - { - for ( i = 0; i < avalible_items; ++i ) - { - pInventoryItemList[item_index_tabl[i]].uAttributes |= ITEM_HARDENED; - } - } - } -} - -//----- (004948B1) -------------------------------------------------------- -void Player::PlaySound(PlayerSpeech speech, int a3) -{ - signed int speechCount = 0; // esi@4 - signed int expressionCount = 0; // esi@4 - int pickedVariant; // esi@10 - CHARACTER_EXPRESSION_ID expression; // ebx@17 - signed int pSoundID; // ecx@19 - int speechVariantArray[5]; // [sp+Ch] [bp-1Ch]@7 - int expressionVariantArray[5]; - unsigned int pickedSoundID; // [sp+30h] [bp+8h]@4 - unsigned int expressionDuration = 0; - - pickedSoundID = 0; - if (uVoicesVolumeMultiplier) - { - for (int i = 0; i < 2; i++) - { - if ( SoundSetAction[speech][i] ) - { - speechVariantArray[speechCount] = SoundSetAction[speech][i]; - speechCount++; - } - } - if ( speechCount ) - { - pickedVariant = speechVariantArray[rand() % speechCount]; - int numberOfSubvariants = byte_4ECF08[pickedVariant - 1][uVoiceID]; - if (numberOfSubvariants > 0) - { - pickedSoundID = rand() % numberOfSubvariants + 2 * (pickedVariant + 50 * uVoiceID) + 4998; - pAudioPlayer->PlaySound((SoundID)pickedSoundID, PID(OBJECT_Player, uActiveCharacter + 39), 0, -1, 0, 0, (int)(pSoundVolumeLevels[uVoicesVolumeMultiplier] * 128.0f), 0); - } - } - } - - for (int i = 0; i < 5; i++) - { - if ( SoundSetAction[speech][i + 3] ) - { - expressionVariantArray[expressionCount] = SoundSetAction[speech][i + 3]; - expressionCount++; - } - } - if ( expressionCount ) - { - expression = (CHARACTER_EXPRESSION_ID)expressionVariantArray[rand() % expressionCount]; - if (expression == CHARACTER_EXPRESSION_21 && pickedSoundID ) - { - pSoundID = 0; - if ( pSoundList->sNumSounds ) - { - for (int i = 0; i < pSoundList->sNumSounds; i++) - { - if (pSoundList->pSL_Sounds[i].uSoundID == pickedSoundID) - pSoundID = i; - } - } - if ( pSoundList->pSL_Sounds[pSoundID].pSoundData[0] ) - expressionDuration = (sLastTrackLengthMS << 7) / 1000; - } - PlayEmotion(expression, expressionDuration); - } -} -// 4948B1: using guessed type int var_1C[5]; - -//----- (00494A25) -------------------------------------------------------- -void Player::PlayEmotion(CHARACTER_EXPRESSION_ID new_expression, int a3) -{ - unsigned int v3 = expression; - if (expression == CHARACTER_EXPRESSION_DEAD || expression == CHARACTER_EXPRESSION_ERADICATED) - { - return; - } - else if (expression == CHARACTER_EXPRESSION_PERTIFIED && new_expression != CHARACTER_EXPRESSION_FALLING) - { - return; - } - else - { - if (expression != CHARACTER_EXPRESSION_SLEEP || new_expression != CHARACTER_EXPRESSION_FALLING) - { - if (v3 >= 2 && v3 <= 11 && v3 != 8 && !(new_expression == CHARACTER_EXPRESSION_DMGRECVD_MINOR || new_expression == CHARACTER_EXPRESSION_DMGRECVD_MODERATE || new_expression == CHARACTER_EXPRESSION_DMGRECVD_MAJOR)) - { - return; - } - } - } - this->uExpressionTimePassed = 0; - if ( !a3 ) - { - this->uExpressionTimeLength = 8 * pPlayerFrameTable->pFrames[a3].uAnimLength; - } - else - { - this->uExpressionTimeLength = 0; - } - expression = new_expression; - viewparams->bRedrawGameUI = 1; -} - -//----- (0049327B) -------------------------------------------------------- -bool Player::ProfessionOrGuildFlagsCorrect( unsigned int uClass, int a3 ) -{ - if ( this->classType == uClass ) - { - return true; - } - else - { - if (!a3) - { - return false; - } - switch ( uClass ) - { - case 0x1Au: - return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 65)); - case 0x1Bu: - return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 67)); - case 0x22u: - return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 77)); - case 0x23u: - return(_449B57_test_bit((unsigned __int8 *)this->_achieved_awards_bits, 79)); - break; - default: - Error("Should not be able to get here (%u)", uClass); - break; - } - return false; - } -} - - -//----- (00492C0B) -------------------------------------------------------- -bool Player::CanAct() -{ - if ( this->IsAsleep() || this->IsParalyzed() || - this->IsUnconcious() || this->IsDead() || - this->IsPertified() || this->IsEradicated() ) - return false; - else - return true; -} - -//----- (00492C40) -------------------------------------------------------- -bool Player::CanSteal() -{ - return GetActualSkillLevel(PLAYER_SKILL_STEALING) != 0; -} - -//----- (00492C4E) -------------------------------------------------------- -bool Player::CanEquip_RaceAndAlignmentCheck(unsigned int uItemID) -{ - switch (uItemID) - { - case ITEM_RELIC_ETHRICS_STAFF: - case ITEM_RELIC_OLD_NICK: - case ITEM_RELIC_TWILIGHT: return pParty->IsPartyEvil(); break; - case ITEM_RELIC_TALEDONS_HELM: - case ITEM_RELIC_JUSTICE: return pParty->IsPartyGood(); break; - case ITEM_ARTIFACT_ELFBANE: return IsRaceGoblin(); break; - case ITEM_ARTIFACT_MINDS_EYE: return IsRaceHuman(); break; - case ITEM_ELVEN_CHAINMAIL: return IsRaceElf(); break; - case ITEM_FORGE_GAUNTLETS: return IsRaceDwarf(); break; - case ITEM_ARTIFACT_HEROS_BELT: return IsMale(); break; - case ITEM_ARTIFACT_LADYS_ESCORT: return IsFemale(); break; - case ITEM_WETSUIT: return NothingOrJustBlastersEquipped(); break; - default: return 1; break; - } -} - -//----- (00492D65) -------------------------------------------------------- -void Player::SetCondition( unsigned int uConditionIdx, int a3 ) -{ - signed int player_sex; // ecx@77 - signed int remainig_player; // ebx@82 - int players_before; // [sp+10h] [bp-4h]@2 - int players_after; // [sp+20h] [bp+Ch]@82 - - if ( pConditions[uConditionIdx] ) - return; - - if (!ConditionProcessor::IsPlayerAffected(this, uConditionIdx, a3)) - { - return; - } - - switch ( uConditionIdx ) - { - case Condition_Cursed: PlaySound(SPEECH_30, 0); break; - case Condition_Weak: PlaySound(SPEECH_25, 0); break; - case Condition_Sleep: break; //nosound - case Condition_Fear: PlaySound(SPEECH_26, 0); break; - case Condition_Drunk: PlaySound(SPEECH_31, 0); break; - case Condition_Insane: PlaySound(SPEECH_29, 0); break; - case Condition_Poison_Weak: - case Condition_Poison_Medium: - case Condition_Poison_Severe: PlaySound(SPEECH_27, 0); break; - case Condition_Disease_Weak: - case Condition_Disease_Medium: - case Condition_Disease_Severe: PlaySound(SPEECH_28, 0);break; - case Condition_Paralyzed: break; //nosound - case Condition_Unconcious: - PlaySound(SPEECH_32, 0); - if ( sHealth > 0 ) - sHealth = 0; - break; - case Condition_Dead: - PlaySound(SPEECH_33, 0); - if ( sHealth > 0 ) - sHealth = 0; - if ( sMana > 0 ) - sMana = 0; - break; - case Condition_Pertified: - PlaySound(SPEECH_34, 0); - break; - case Condition_Eradicated: - PlaySound(SPEECH_35, 0); - if (sHealth > 0 ) - sHealth = 0; - if ( sMana > 0 ) - sMana = 0; - break; - case Condition_Zombie: - if ( classType == PLAYER_CLASS_LICH || IsEradicated() || IsZombie() || !IsDead()) - return; - pConditions.fill(0); - sHealth = GetMaxHealth(); - sMana = 0; - player_sex = 0; - uPrevFace = uCurrentFace; - uPrevVoiceID = uVoiceID; - if (IsMale()) - { - uCurrentFace = 23; - uVoiceID = 23; - } - else - { - uCurrentFace = 24; - uVoiceID = 24; - } - PlaySound(SPEECH_99, 0); - break; - } - - players_before = 0; - for (int i = 1; i < 5; ++i) - { - if ( pPlayers[i]->CanAct() ) - ++players_before; - } - - pConditions[uConditionIdx] = pParty->uTimePlayed; - - remainig_player = 0; - players_after = 0; - for (int i = 1; i < 5; ++i) - { - if ( pPlayers[i]->CanAct() ) - { - remainig_player = i; - ++players_after; - } - } - if (( players_before == 2 ) && ( players_after == 1 )) - pPlayers[remainig_player]->PlaySound(SPEECH_107, 0);//ñêîðåå âñåãî îáíàä¸æûâàþùèé âîçãëàñ ïîñëåäíåãî - return; -} - -//----- (00492528) -------------------------------------------------------- -bool Player::CanFitItem(unsigned int uSlot, unsigned int uItemID) -{ - Texture *texture; // esi@1 - unsigned int slotWidth; // ebx@1 - unsigned int slotHeight; // [sp+1Ch] [bp+Ch]@1 - - texture = pIcons_LOD->LoadTexturePtr(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE); - slotWidth = GetSizeInInventorySlots(texture->uTextureWidth); - slotHeight = GetSizeInInventorySlots(texture->uTextureHeight); - if ( !areWeLoadingTexture ) - { - texture->Release(); - pIcons_LOD->SyncLoadedFilesCount(); - } - Assert(slotHeight > 0 && slotWidth > 0, "Items should have nonzero dimensions"); - if ( (slotWidth + uSlot % INVETORYSLOTSWIDTH) <= INVETORYSLOTSWIDTH && (slotHeight + uSlot / INVETORYSLOTSWIDTH) <= INVETORYSLOTSHEIGHT ) - { - for (unsigned int x = 0; x < slotWidth; x++) - { - for (unsigned int y = 0; y < slotHeight; y++) - { - if (pInventoryMatrix[y * INVETORYSLOTSWIDTH + x + uSlot] != 0) - { - return false; - } - } - } - return true; - } - return false; -} -// 506128: using guessed type int areWeLoadingTexture; - -//----- (004925E6) -------------------------------------------------------- -int Player::FindFreeInventoryListSlot() -{ - for (int i = 0; i < 126; i++ ) - { - if (pInventoryItemList[i].uItemID == 0) - { - return i; - } - } - return -1; -} - -//----- (00492600) -------------------------------------------------------- -int Player::CreateItemInInventory(unsigned int uSlot, unsigned int uItemID) -{ - int result; // eax@8 - signed int freeSlot; // [sp+8h] [bp-4h]@4 - - freeSlot = FindFreeInventoryListSlot(); - if ( freeSlot == -1 ) - { - if ( uActiveCharacter ) - pPlayers[uActiveCharacter]->PlaySound(SPEECH_NoRoom, 0); - return 0; - } - else - { - PutItemArInventoryIndex(uItemID, freeSlot, uSlot); - result = freeSlot + 1; - this->pInventoryItemList[freeSlot].uItemID = uItemID; - } - return result; -} -// 506128: using guessed type int areWeLoadingTexture; - -//----- (00492700) -------------------------------------------------------- -int Player::HasSkill(unsigned int uSkillType) -{ - if ( uSkillType >= 37 || this->pActiveSkills[uSkillType] ) - { - return 1; - } - else - { - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[67], this->pName); - ShowStatusBarString(pTmpBuf.data(), 2u); - return 0; - } -} - -//----- (00492745) -------------------------------------------------------- -void Player::WearItem( unsigned int uItemID ) -{ - int item_body_anch; // edi@6 - int item_indx; - item_indx = FindFreeInventoryListSlot(); - - if ( item_indx != -1 ) - { - pInventoryItemList[item_indx].uItemID = uItemID; - item_body_anch = pEquipTypeToBodyAnchor[pItemsTable->pItems[uItemID].uEquipType]; - pEquipment.pIndices[item_body_anch] = item_indx + 1; - pInventoryItemList[item_indx].uBodyAnchor = item_body_anch + 1; - } -} - -//----- (004927A8) -------------------------------------------------------- -int Player::AddItem(int index, unsigned int uItemID) -{ - if ( index == -1 ) - { - for (int xcoord = 0; xcoord < INVETORYSLOTSWIDTH; xcoord++) - { - for (int ycoord = 0; ycoord < INVETORYSLOTSHEIGHT; ycoord++) - { - if ( CanFitItem(ycoord * INVETORYSLOTSWIDTH + xcoord, uItemID) ) - { - return CreateItemInInventory(ycoord * INVETORYSLOTSWIDTH + xcoord, uItemID); - } - } - } - return 0; - } - if ( !CanFitItem(index, uItemID) ) - { - pAudioPlayer->PlaySound(SOUND_error, 0, 0, -1, 0, 0, 0, 0); - return 0; - } - return CreateItemInInventory(index, uItemID); -} - -//----- (00492826) -------------------------------------------------------- -int Player::AddItem2(int index, ItemGen *Src) -{ - pItemsTable->SetSpecialBonus(Src); - - if ( index == -1 ) - { - for (int xcoord = 0; xcoord < INVETORYSLOTSWIDTH; xcoord++) - { - for (int ycoord = 0; ycoord < INVETORYSLOTSHEIGHT; ycoord++) //TODO: change pInventoryMatrix to 2 dimensional array. - { - if ( CanFitItem(ycoord * INVETORYSLOTSWIDTH + xcoord, Src->uItemID) ) - { - return CreateItemInInventory2(ycoord * INVETORYSLOTSWIDTH + xcoord, Src); - } - } - } - return 0; - } - if ( !CanFitItem(index, Src->uItemID) ) - return 0; - return CreateItemInInventory2(index, Src); -} - -//----- (0049289C) -------------------------------------------------------- -int Player::CreateItemInInventory2( unsigned int index, ItemGen *Src ) -{ - signed int freeSlot; // ebx@1 - int result; // eax@6 - - freeSlot = FindFreeInventoryListSlot(); - if ( freeSlot == -1 ) - { - result = 0; - } - else - { - PutItemArInventoryIndex(Src->uItemID, freeSlot, index); - memcpy(&pInventoryItemList[freeSlot], Src, sizeof(ItemGen)); - result = freeSlot + 1; - } - return result; -} -// 506128: using guessed type int areWeLoadingTexture; - -//----- (0049298B) -------------------------------------------------------- -void Player::PutItemArInventoryIndex( int uItemID, int itemListPos, int index ) //originally accepted ItemGen* but needed only its uItemID -{ - Texture *item_texture; // esi@1 - int *pInvPos; // esi@4 - unsigned int slot_width; // [sp+Ch] [bp-4h]@1 - unsigned int slot_height; // [sp+18h] [bp+8h]@1 - - item_texture = pIcons_LOD->LoadTexturePtr(pItemsTable->pItems[uItemID].pIconName, TEXTURE_16BIT_PALETTE); - slot_width = GetSizeInInventorySlots(item_texture->uTextureWidth); - slot_height = GetSizeInInventorySlots(item_texture->uTextureHeight); - if ( !areWeLoadingTexture ) - { - item_texture->Release(); - pIcons_LOD->SyncLoadedFilesCount(); - } - if ( slot_width > 0 ) - { - pInvPos = &pInventoryMatrix[index]; - for (unsigned int i = 0; i < slot_height; i++) - { - memset32(pInvPos, -1 - index, slot_width);//TODO: try to come up with a better solution. negative values are used when drawing the inventory - nothing is drawn - pInvPos += INVETORYSLOTSWIDTH; - } - } - pInventoryMatrix[index] = itemListPos + 1; -} - -// 506128: using guessed type int areWeLoadingTexture; - -//----- (00492A36) -------------------------------------------------------- -void Player::RemoveItemAtInventoryIndex( unsigned int index ) -{ - ItemGen *item_in_slot; // ecx@1 - Texture *item_texture; // esi@1 - unsigned int slot_height; // ebp@1 - int *pInvPos; // edx@4 - unsigned int slot_width; // [sp+14h] [bp+4h]@1 - - item_in_slot = &this->pInventoryItemList[pInventoryMatrix[index]-1]; - item_texture = pIcons_LOD->LoadTexturePtr(item_in_slot->GetIconName(), TEXTURE_16BIT_PALETTE); - item_in_slot->Reset(); - slot_width = GetSizeInInventorySlots(item_texture->uTextureWidth); - slot_height = GetSizeInInventorySlots(item_texture->uTextureHeight); - if ( !areWeLoadingTexture ) - { - item_texture->Release(); - pIcons_LOD->SyncLoadedFilesCount(); - } - if ( slot_width > 0 ) - { - pInvPos = &pInventoryMatrix[index]; - for (unsigned int i = 0; i < slot_height; i++) - { - memset32(pInvPos, 0, slot_width); - pInvPos += INVETORYSLOTSWIDTH; - } - } -} -// 506128: using guessed type int areWeLoadingTexture; - -//----- (00490EEE) -------------------------------------------------------- -int Player::SelectPhrasesTransaction(ItemGen *pItem, int building_type, int BuildID_2Events, int ShopMenuType) //TODO: probably move this somewhere else, not really Player:: stuff -{ - unsigned int idemId; // edx@1 - signed int equipType; // esi@1 - float multiplier; // ST04_4@26 - int price; // edi@26 - int merchantLevel; // [sp+10h] [bp-8h]@1 - int itemValue; - - merchantLevel = GetActualSkillLevel(PLAYER_SKILL_MERCHANT); - idemId = pItem->uItemID; - equipType = pItem->GetItemEquipType(); - itemValue = pItem->GetValue(); - - switch (building_type) - { - case BuildingType_WeaponShop: - if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) - return 5; - if (equipType > EQUIP_BOW) - return 4; - break; - case BuildingType_ArmorShop: - if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) - return 5; - if ( equipType < EQUIP_ARMOUR || equipType > EQUIP_BOOTS) - return 4; - break; - case BuildingType_MagicShop: - if (idemId >= ITEM_ARTIFACT_HERMES_SANDALS) - return 5; - if ( pItemsTable->pItems[idemId].uSkillType != PLAYER_SKILL_MISC ) - return 4; - break; - case BuildingType_AlchemistShop: - if ((idemId >= ITEM_ARTIFACT_HERMES_SANDALS && idemId < ITEM_RECIPE_REJUVENATION) || idemId > ITEM_RECIPE_BODY_RESISTANCE) - return 5; - if ( !(equipType == EQUIP_REAGENT || equipType == EQUIP_POTION || equipType == EQUIP_MESSAGE_SCROLL)) - return 4; - break; - default: - Error("(%u)", building_type); - break; - } - if (pItem->IsStolen()) - return 6; - - multiplier = p2DEvents[BuildID_2Events - 1].fPriceMultiplier; - switch (ShopMenuType) - { - case 2: - price = GetBuyingPrice(itemValue, multiplier); - break; - case 3: - if (pItem->IsBroken()) - price = 1; - else - price = this->GetPriceSell(itemValue, multiplier); - break; - case 4: - price = this->GetPriceIdentification(multiplier); - break; - case 5: - price = this->GetPriceRepair(itemValue, multiplier); - break; - default: - Error("(%u)", ShopMenuType); - break; - } - if ( merchantLevel ) - { - if (price == itemValue) - { - return 3; - } - else - { - return 2; - } - } - else - { - return 1; - } -} - -//----- (0049107D) -------------------------------------------------------- -int Player::GetBodybuilding() -{ - int v1; // al@1 - - v1 = GetActualSkillLevel(PLAYER_SKILL_BODYBUILDING); - int multiplier = GetMultiplierForSkillLevel(v1, 1, 2, 3, 5); - return multiplier * (v1 & 0x3F); -} - -//----- (004910A8) -------------------------------------------------------- -int Player::GetMeditation() -{ - int v1; // al@1 - - v1 = GetActualSkillLevel(PLAYER_SKILL_MEDITATION); - int multiplier = GetMultiplierForSkillLevel(v1, 1, 2, 3, 5); - return multiplier * (v1 & 0x3F); -} - -//----- (004910D3) -------------------------------------------------------- -bool Player::CanIdentify( ItemGen *pItem ) -{ - unsigned __int16 v2; // ax@1 - int v5; // edi@7 - if (CheckHiredNPCSpeciality(Scholar)) - return true; - - v2 = GetActualSkillLevel(PLAYER_SKILL_ITEM_ID); - if ( (signed int)SkillToMastery(v2) >= 4 ) - return true; - - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - v5 = multiplier * (v2 & 0x3F); - return v5 >= pItemsTable->pItems[pItem->uItemID].uItemID_Rep_St; -} - -//----- (00491151) -------------------------------------------------------- -bool Player::CanRepair( ItemGen *pItem ) -{ - unsigned __int16 v2; // ax@1 - int v5; // edi@7 - - ITEM_EQUIP_TYPE equipType = pItem->GetItemEquipType(); - if (CheckHiredNPCSpeciality(Smith) && equipType <= 2 || - CheckHiredNPCSpeciality(Armorer) && equipType >= 3 && equipType <= 9 || - CheckHiredNPCSpeciality(Alchemist) && equipType >= 9 ) - return true; - - v2 = GetActualSkillLevel(PLAYER_SKILL_REPAIR); - if ( (signed int)SkillToMastery(v2) >= 4 ) - return true; - - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - v5 = multiplier * (v2 & 0x3F); - return v5 >= pItemsTable->pItems[pItem->uItemID].uItemID_Rep_St; -} - -//----- (004911F3) -------------------------------------------------------- -int Player::GetMerchant() -{ - unsigned __int16 v2; // ax@1 - int v5; // edi@1 - int v7; // eax@3 - - v2 = GetActualSkillLevel(PLAYER_SKILL_MERCHANT); - if ( SkillToMastery(v2) >= 4 ) - return 10000; - - v7 = pParty->GetPartyReputation(); - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - v5 = multiplier * (v2 & 0x3F); - if (v5 == 0) - { - return -v7; - } - return v5 - v7 + 7; -} - -//----- (0049125A) -------------------------------------------------------- -int Player::GetPerception() -{ - unsigned __int16 v2; // ax@1 - int v5; // edi@1 - - v2 = GetActualSkillLevel(PLAYER_SKILL_PERCEPTION); - if ( SkillToMastery(v2) >= 4 ) - return 10000; - - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - v5 = multiplier * (v2 & 0x3F); - return v5; -} - -//----- (004912B0) -------------------------------------------------------- -int Player::GetDisarmTrap() -{ - unsigned __int16 v2; // ax@1 - int v5; // edi@1 - - v2 = GetActualSkillLevel(PLAYER_SKILL_TRAP_DISARM); - if ( (signed int)SkillToMastery(v2) >= 4 ) - return 10000; - - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - if ( HasEnchantedItemEquipped(35) ) //only the real skill level is supposed to be added again, not the multiplied value - multiplier++; - v5 = multiplier * (v2 & 0x3F); - return v5; -} - -//----- (00491317) -------------------------------------------------------- -char Player::GetLearningPercent() -{ - int v2; // eax@1 - - v2 = GetActualSkillLevel(PLAYER_SKILL_LEARNING); - int multiplier = GetMultiplierForSkillLevel(v2, 1, 2, 3, 5); - return multiplier * v2 + 9; -} - -//----- (0048C6AF) -------------------------------------------------------- -Player::Player() -{ - memset(&pEquipment, 0, sizeof(PlayerEquipment)); - pInventoryMatrix.fill(0); - for (uint i = 0; i < 126; ++i) - pInventoryItemList[i].Reset(); - for (uint i = 0; i < 12; ++i) - pEquippedItems[i].Reset(); - - - for (uint i = 0; i < 24; ++i) - { - pPlayerBuffs[i].uSkill = 0; - pPlayerBuffs[i].uSkill = 0; - pPlayerBuffs[i].uPower = 0; - pPlayerBuffs[i].uExpireTime = 0; - pPlayerBuffs[i].uCaster = 0; - pPlayerBuffs[i].uFlags = 0; - } - - pName[0] = 0; - uCurrentFace = 0; - uVoiceID = 0; - pConditions.fill(0); - - field_BB = 0; - - uMight = uMightBonus = 0; - uIntelligence = uIntelligenceBonus = 0; - uWillpower = uWillpowerBonus = 0; - uEndurance = uEnduranceBonus = 0; - uSpeed = uSpeedBonus = 0; - uAccuracy = uAccuracyBonus = 0; - uLuck = uLuckBonus = 0; - uLevel = sLevelModifier = 0; - sAgeModifier = 0; - sACModifier = 0; - -// memset(field_1F5, 0, 30); - pure_luck_used=0; - pure_speed_used=0; - pure_intellect_used=0; - pure_endurance_used=0; - pure_willpower_used=0; - pure_accuracy_used=0; - pure_might_used=0; - - sResFireBase = sResFireBonus = 0; - sResAirBase = sResAirBonus = 0; - sResWaterBase = sResWaterBonus = 0; - sResEarthBase = sResEarthBonus = 0; - sResMagicBase = sResMagicBonus = 0; - sResSpiritBase = sResSpiritBonus = 0; - sResMindBase = sResMindBonus = 0; - sResBodyBase = sResBodyBonus = 0; - sResLightBase = sResLightBonus = 0; - sResDarkBase = sResDarkBonus = 0; - - uTimeToRecovery = 0; - - uSkillPoints = 0; - - sHealth = 0; - uFullHealthBonus = 0; - _health_related = 0; - - sMana = 0; - uFullManaBonus = 0; - _mana_related = 0; - - uQuickSpell = 0; - memset(pInstalledBeacons.data(), 0, 5 * sizeof(LloydBeacon)); - - _some_attack_bonus = 0; - field_1A91 = 0; - _melee_dmg_bonus = 0; - field_1A93 = 0; - _ranged_atk_bonus = 0; - field_1A95 = 0; - _ranged_dmg_bonus = 0; - field_1A97 = 0; - - expression = CHARACTER_EXPRESSION_INVALID; - uExpressionTimePassed = 0; - uExpressionTimeLength = 0; - - uNumDivineInterventionCastsThisDay = 0; - uNumArmageddonCasts = 0; - uNumFireSpikeCasts = 0; - - memset(field_1988, 0, sizeof(field_1988)); - memset(playerEventBits, 0, sizeof(playerEventBits)); - - field_E0 = 0; - field_E4 = 0; - field_E8 = 0; - field_EC = 0; - field_F0 = 0; - field_F4 = 0; - field_F8 = 0; - field_FC = 0; - field_100 = 0; - field_104 = 0; - - _expression21_animtime = 0; - _expression21_frameset = 0; - - lastOpenedSpellbookPage = 0; -} - - -//----- (0048C855) -------------------------------------------------------- -int Player::GetBaseStrength() -{ - return this->uMight + GetItemsBonus(CHARACTER_ATTRIBUTE_STRENGTH); -} - -//----- (0048C86C) -------------------------------------------------------- -int Player::GetBaseIntelligence() -{ - return this->uIntelligence + GetItemsBonus(CHARACTER_ATTRIBUTE_INTELLIGENCE); -} - -//----- (0048C883) -------------------------------------------------------- -int Player::GetBaseWillpower() -{ - return this->uWillpower + GetItemsBonus(CHARACTER_ATTRIBUTE_WILLPOWER); -} - -//----- (0048C89A) -------------------------------------------------------- -int Player::GetBaseEndurance() -{ - return this->uEndurance + GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE); -} - -//----- (0048C8B1) -------------------------------------------------------- -int Player::GetBaseAccuracy() -{ - return this->uAccuracy + GetItemsBonus(CHARACTER_ATTRIBUTE_ACCURACY); -} - -//----- (0048C8C8) -------------------------------------------------------- -int Player::GetBaseSpeed() -{ - return this->uSpeed + GetItemsBonus(CHARACTER_ATTRIBUTE_SPEED); -} - -//----- (0048C8DF) -------------------------------------------------------- -int Player::GetBaseLuck() -{ - return this->uLuck + GetItemsBonus(CHARACTER_ATTRIBUTE_LUCK); -} - -//----- (0048C8F6) -------------------------------------------------------- -int Player::GetBaseLevel() -{ - return this->uLevel + GetItemsBonus(CHARACTER_ATTRIBUTE_LEVEL); -} - -//----- (0048C90D) -------------------------------------------------------- -int Player::GetActualLevel() -{ - return uLevel + sLevelModifier + - GetMagicalBonus(CHARACTER_ATTRIBUTE_LEVEL) + - GetItemsBonus(CHARACTER_ATTRIBUTE_LEVEL); -} - -//----- (0048C93C) -------------------------------------------------------- -int Player::GetActualMight() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_STRENGTH, &Player::uMight, &Player::uMightBonus); -} - -//----- (0048C9C2) -------------------------------------------------------- -int Player::GetActualIntelligence() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_INTELLIGENCE, &Player::uIntelligence, &Player::uIntelligenceBonus); -} - -//----- (0048CA3F) -------------------------------------------------------- -int Player::GetActualWillpower() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_WILLPOWER, &Player::uWillpower, &Player::uWillpowerBonus); -} - -//----- (0048CABC) -------------------------------------------------------- -int Player::GetActualEndurance() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_ENDURANCE, &Player::uEndurance, &Player::uEnduranceBonus); -} - -//----- (0048CB39) -------------------------------------------------------- -int Player::GetActualAccuracy() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_ACCURACY, &Player::uAccuracy, &Player::uAccuracyBonus); -} - -//----- (0048CBB6) -------------------------------------------------------- -int Player::GetActualSpeed() -{ - return GetActualAttribute(CHARACTER_ATTRIBUTE_SPEED, &Player::uSpeed, &Player::uSpeedBonus); -} - -//----- (0048CC33) -------------------------------------------------------- -int Player::GetActualLuck() -{ - signed int npc_luck_bonus; // [sp+10h] [bp-4h]@1 - - npc_luck_bonus = 0; - if ( CheckHiredNPCSpeciality(Fool) ) - npc_luck_bonus = 5; - if ( CheckHiredNPCSpeciality(ChimneySweep) ) - npc_luck_bonus += 20; - if ( CheckHiredNPCSpeciality(Psychic) ) - npc_luck_bonus += 10; - - return GetActualAttribute(CHARACTER_ATTRIBUTE_LUCK, &Player::uLuck, &Player::uLuckBonus) - + npc_luck_bonus; -} - -//----- (new function) -------------------------------------------------------- -int Player::GetActualAttribute( CHARACTER_ATTRIBUTE_TYPE attrId, unsigned short Player::* attrValue, unsigned short Player::* attrBonus ) -{ - uint uActualAge = this->sAgeModifier + GetBaseAge(); - uint uAgeingMultiplier = 100; - for (uint i = 0; i < 4; ++i) - { - if (uActualAge >= pAgeingTable[i]) - uAgeingMultiplier = pAgingAttributeModifier[attrId][i]; - else - break; - } - - uchar uConditionMult = pConditionAttributeModifier[attrId][GetMajorConditionIdx()]; - int magicBonus = GetMagicalBonus(attrId); - int itemBonus = GetItemsBonus(attrId); - return uConditionMult * uAgeingMultiplier * this->*attrValue / 100 / 100 - + magicBonus - + itemBonus - + this->*attrBonus; -} - -//----- (0048CCF5) -------------------------------------------------------- -int Player::GetActualAttack( bool a2 ) -{ - int v3; // eax@1 - int v4; // edi@1 - int v5; // ebx@1 - int v6; // ebp@1 - - v3 = GetActualAccuracy(); - v4 = GetParameterBonus(v3); - v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_ATTACK); - v6 = GetItemsBonus(CHARACTER_ATTRIBUTE_ATTACK, a2); - return v4 + v5 + v6 + GetMagicalBonus(CHARACTER_ATTRIBUTE_ATTACK) + this->_some_attack_bonus; -} - -//----- (0048CD45) -------------------------------------------------------- -int Player::GetMeleeDamageMinimal() -{ - int v2; // eax@1 - int v3; // esi@1 - int v4; // esi@1 - int v5; // esi@1 - signed int result; // eax@1 - - v2 = GetActualMight(); - v3 = GetParameterBonus(v2); - v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN) + v3; - v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v4; - result = _melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v5; - if ( result < 1 ) - result = 1; - return result; -} - -//----- (0048CD90) -------------------------------------------------------- -int Player::GetMeleeDamageMaximal() -{ - int v2; // eax@1 - int v3; // esi@1 - int v4; // esi@1 - int v5; // esi@1 - int v6; // esi@1 - signed int result; // eax@1 - - v2 = GetActualMight(); - v3 = GetParameterBonus(v2); - v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX) + v3; - v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v4; - v6 = this->_melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + v5; - result = 1; - if ( v6 >= 1 ) - result = v6; - return result; -} - -//----- (0048CDDB) -------------------------------------------------------- -int Player::CalculateMeleeDamageTo( bool ignoreSkillBonus, bool ignoreOffhand, unsigned int uTargetActorID ) -{ - int dmgSum; // esi@62 - signed int result; // eax@64 - int mainWpnDmg; // [sp+18h] [bp-8h]@1 - int offHndWpnDmg; // [sp+1Ch] [bp-4h]@1 - - offHndWpnDmg = 0; - mainWpnDmg = 0; - if ( IsUnarmed() ) - { - mainWpnDmg = rand() % 3 + 1; - } - else - { - if ( HasItemEquipped(EQUIP_TWO_HANDED) ) - { - ItemGen *mainHandItemGen = this->GetMainHandItem(); - int itemId = mainHandItemGen->uItemID; - bool addOneDice = false; - if ( pItemsTable->pItems[itemId].uSkillType == PLAYER_SKILL_SPEAR && !this->pEquipment.uShield ) - addOneDice = true; - mainWpnDmg = CalculateMeleeDmgToEnemyWithWeapon(mainHandItemGen, uTargetActorID, addOneDice); - } - if ( !ignoreOffhand ) - { - if ( this->HasItemEquipped(EQUIP_SINGLE_HANDED) ) - { - ItemGen *offHandItemGen = (ItemGen *)&this->pInventoryItemList[this->pEquipment.uShield - 1]; - if ( offHandItemGen->GetItemEquipType() != EQUIP_SHIELD ) - { - offHndWpnDmg = CalculateMeleeDmgToEnemyWithWeapon(offHandItemGen, uTargetActorID, false); - } - } - } - } - dmgSum = mainWpnDmg + offHndWpnDmg; - if ( !ignoreSkillBonus ) - { - int might = GetActualMight(); - int mightBonus = GetParameterBonus(might); - int mightAndSkillbonus = GetSkillBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + mightBonus; - dmgSum += this->_melee_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS) + mightAndSkillbonus; - } - result = 1; - if ( dmgSum >= 1 ) - result = dmgSum; - return result; -} - - -int Player::CalculateMeleeDmgToEnemyWithWeapon( ItemGen * weapon, unsigned int uTargetActorID , bool addOneDice ) -{ - int itemId = weapon->uItemID; - int diceCount = pItemsTable->pItems[itemId].uDamageDice; - if (addOneDice) - { - diceCount++; - } - int diceSides = pItemsTable->pItems[itemId].uDamageRoll; - int diceResult = 0; - for (int i = 0; i < diceCount; i++) - { - diceResult += rand() % diceSides + 1; - } - int totalDmg = pItemsTable->pItems[itemId].uDamageMod + diceResult; - if ( uTargetActorID > 0) - { - int enchType = weapon->uSpecEnchantmentType; - if ( MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_UNDEAD) && (enchType == 64 || itemId == ITEM_ARTIFACT_GHOULSBANE || itemId == ITEM_ARTIFACT_GIBBET || itemId == ITEM_RELIC_JUSTICE) ) - { - totalDmg *= 2; - } - else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_KREEGAN) && ( enchType == 39 || itemId == ITEM_ARTIFACT_GIBBET)) - { - totalDmg *= 2; - } - else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_DRAGON) && ( enchType == 40 || itemId == ITEM_ARTIFACT_GIBBET)) - { - totalDmg *= 2; - } - else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_ELF) && ( enchType == 63 || itemId == ITEM_RELIC_OLD_NICK)) - { - totalDmg *= 2; - } - else if (MonsterStats::BelongsToSupertype(uTargetActorID, MONSTER_SUPERTYPE_TITAN) && ( enchType == 65 )) - { - totalDmg *= 2; - } - } - if ( (signed int)SkillToMastery(this->pActiveSkills[PLAYER_SKILL_DAGGER]) >= 3 - && pItemsTable->pItems[itemId].uSkillType == 2 - && rand() % 100 < 10 ) - totalDmg *= 3; - return totalDmg; -} - - -//----- (0048D0B9) -------------------------------------------------------- -int Player::GetRangedAttack() -{ - int v3; // edi@3 - //int v4; // eax@4 - //int v5; // edi@4 - int v6; // edi@4 - int v7; // edi@4 - - ItemGen* mainHandItem = GetMainHandItem(); - if ( mainHandItem != nullptr && ( mainHandItem->uItemID < ITEM_BLASTER || mainHandItem->uItemID > ITEM_LASER_RIFLE )) - { - //v4 = GetActualAccuracy(); - //v5 = GetParameterBonus(GetActualAccuracy()); - v6 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + GetParameterBonus(GetActualAccuracy()); - v7 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + v6; - v3 = this->_ranged_atk_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_ATTACK) + v7; - } - else - { - v3 = GetActualAttack(true); - } - return v3; -} - -//----- (0048D124) -------------------------------------------------------- -int Player::GetRangedDamageMin() -{ - int v2; // edi@1 - int v3; // edi@1 - int v4; // edi@1 - int result; // eax@6 - - v2 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_MIN); - v3 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v2; - v4 = this->_ranged_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v3; - if ( v4 >= 1 ) - result = v4; - else - result = 0; - return result; -} - -//----- (0048D191) -------------------------------------------------------- -int Player::GetRangedDamageMax() -{ - int v2; // edi@1 - int v3; // edi@1 - int v4; // edi@1 - int result; // eax@6 - - v2 = GetItemsBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_MAX); - v3 = GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v2; - v4 = this->_ranged_dmg_bonus + GetMagicalBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS) + v3; - if ( v4 >= 1 ) - result = v4; - else - result = 0; - return result; -} - -//----- (0048D1FE) -------------------------------------------------------- -int Player::CalculateRangedDamageTo( int a2 ) -{ - ItemGen *v4; // ebx@2 - unsigned int v5; // edi@2 - int v9; // esi@5 - int v10; // ebx@6 - signed int v15; // [sp+8h] [bp-Ch]@2 - int v17; // [sp+10h] [bp-4h]@1 - - v17 = 0; - if ( !HasItemEquipped(EQUIP_BOW) ) - return 0; - v4 = (ItemGen *)&this->pInventoryItemList[this->pEquipment.uBow-1]; - v5 = v4->uItemID; - v15 = pItemsTable->pItems[v5].uDamageRoll; - for( int i = 0; i < pItemsTable->pItems[v5].uDamageDice; i++ ) - { - int v7 = rand() % v15; - v17 += v7 + 1; - } - v9 = pItemsTable->pItems[v5].uDamageMod + v17; - if ( a2 ) - { - v10 = v4->uSpecEnchantmentType; - if ( v10 == 64 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_UNDEAD)) - { - v9 *= 2; - } - else if ( v10 == 39 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_KREEGAN)) - { - v9 *= 2; - } - else if ( v10 == 40 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_DRAGON)) - { - v9 *= 2; - } - else if ( v10 == 63 && MonsterStats::BelongsToSupertype(a2, MONSTER_SUPERTYPE_ELF)) - { - v9 *= 2; - } - } - return v9 + this->GetSkillBonus(CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS); -} - -//----- (0048D2EA) -------------------------------------------------------- -char *Player::GetMeleeDamageString() -{ - int min_damage; // edi@3 - int max_damage; // eax@3 - - static char player__getmeleedamagestring_static_buff[40]; // idb - - ItemGen* mainHandItem = GetMainHandItem(); - - if (mainHandItem != nullptr && ( mainHandItem->uItemID >= 135 ) && ( mainHandItem->uItemID <= 159 )) - { - strcpy(player__getmeleedamagestring_static_buff, pGlobalTXT_LocalizationStrings[595]); //"Wand" - return player__getmeleedamagestring_static_buff; - } - else if (mainHandItem != nullptr && (mainHandItem->uItemID == ITEM_BLASTER || mainHandItem->uItemID == ITEM_LASER_RIFLE)) - { - min_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN, true); - max_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX, true); - } - else - { - min_damage = GetMeleeDamageMinimal(); - max_damage = GetMeleeDamageMaximal(); - } - if ( min_damage == max_damage ) - { - sprintf(player__getmeleedamagestring_static_buff, "%d", min_damage); - } - else - { - sprintf(player__getmeleedamagestring_static_buff, "%d - %d", min_damage, max_damage); - } - return player__getmeleedamagestring_static_buff; -} - -//----- (0048D396) -------------------------------------------------------- -char *Player::GetRangedDamageString() -{ - int min_damage; // edi@3 - int max_damage; // eax@3 - - static char player__getrangeddamagestring_static_buff[40]; // idb - - ItemGen* mainHandItem = GetMainHandItem(); - - if (mainHandItem != nullptr && ( mainHandItem->uItemID >= 135 ) && ( mainHandItem->uItemID <= 159 )) - { - strcpy(player__getrangeddamagestring_static_buff, pGlobalTXT_LocalizationStrings[595]); //"Wand" - return player__getrangeddamagestring_static_buff; - } - else if (mainHandItem != nullptr && (mainHandItem->uItemID == ITEM_BLASTER || mainHandItem->uItemID == ITEM_LASER_RIFLE)) - { - min_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MIN, true); - max_damage = GetItemsBonus(CHARACTER_ATTRIBUTE_MELEE_DMG_MAX, true); - } - else - { - min_damage = GetRangedDamageMin(); - max_damage = GetRangedDamageMax(); - } - if ( max_damage > 0) - { - if ( min_damage == max_damage ) - { - sprintf(player__getrangeddamagestring_static_buff, "%d", min_damage); - } - else - { - sprintf(player__getrangeddamagestring_static_buff, "%d - %d", min_damage, max_damage); - } - } - else - { - strcpy(player__getrangeddamagestring_static_buff, "N/A"); - } - return player__getrangeddamagestring_static_buff; -} - -//----- (0048D45A) -------------------------------------------------------- -bool Player::CanTrainToNextLevel() -{ - int lvl = this->uLevel + 1; - int neededExp = ((lvl * (lvl - 1)) / 2 * 1000); - return this->uExperience >= neededExp; -} - -//----- (0048D498) -------------------------------------------------------- -unsigned int Player::GetExperienceDisplayColor() -{ - if ( CanTrainToNextLevel() ) - return ui_character_bonus_text_color; - else - return ui_character_default_text_color; -} - -//----- (0048D4B3) -------------------------------------------------------- -int Player::CalculateIncommingDamage( DAMAGE_TYPE dmg_type, int dmg ) -{ - int resist_value; // edi@8 - int player_luck; // eax@21 - signed int res_rand_divider; // ebx@2 - int armor_skill; // eax@29 - - if ( classType == PLAYER_CLASS_LICH && (dmg_type == CHARACTER_ATTRIBUTE_RESIST_MIND || dmg_type == CHARACTER_ATTRIBUTE_RESIST_BODY || dmg_type == CHARACTER_ATTRIBUTE_RESIST_SPIRIT )) //TODO: determine if spirit resistance should be handled by body res. modifier - return 0; - - resist_value = 0; - switch(dmg_type) - { - case DMGT_FIRE: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_FIRE); break; - case DMGT_ELECTR: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_AIR); break; - case DMGT_COLD: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_WATER); break; - case DMGT_EARTH: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_EARTH); break; - - case DMGT_SPIRIT: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_SPIRIT);break; - case DMGT_MIND: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_MIND); break; - case DMGT_BODY: resist_value = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_BODY); break; - } - - player_luck = GetActualLuck(); - res_rand_divider = GetParameterBonus(player_luck) + resist_value + 30; - - if ( GetParameterBonus(player_luck) + resist_value > 0 ) - { - for (int i = 0; i < 4; i++) - { - if ( rand() % res_rand_divider >= 30 ) - dmg >>= 1; - else - break; - } - } - ItemGen* equippedArmor = GetArmorItem(); - if (( dmg_type == DMGT_PHISYCAL ) && ( equippedArmor != nullptr )) - { - if (!equippedArmor->IsBroken()) - { - armor_skill = equippedArmor->GetPlayerSkillType(); - if ( armor_skill==PLAYER_SKILL_PLATE ) - { - if ( SkillToMastery(pActiveSkills[PLAYER_SKILL_PLATE]) >= 3 ) - return dmg / 2; - } - if (armor_skill==PLAYER_SKILL_CHAIN ) - { - if (SkillToMastery(pActiveSkills[PLAYER_SKILL_CHAIN]) == 4) - return dmg * 2 / 3; - } - } - } - return dmg; -} - -//----- (0048D62C) -------------------------------------------------------- -ITEM_EQUIP_TYPE Player::GetEquippedItemEquipType(ITEM_EQUIP_TYPE uEquipSlot) -{ - return GetNthEquippedIndexItem(uEquipSlot)->GetItemEquipType(); -} - -//----- (0048D651) -------------------------------------------------------- -PLAYER_SKILL_TYPE Player::GetEquippedItemSkillType(ITEM_EQUIP_TYPE uEquipSlot) -{ - return (PLAYER_SKILL_TYPE)GetNthEquippedIndexItem(uEquipSlot)->GetPlayerSkillType(); -} - -//----- (0048D676) -------------------------------------------------------- -bool Player::IsUnarmed() -{ - return !HasItemEquipped(EQUIP_TWO_HANDED) && - (!HasItemEquipped(EQUIP_SINGLE_HANDED) || GetOffHandItem()->GetItemEquipType() == EQUIP_SHIELD); -} - -//----- (0048D6AA) -------------------------------------------------------- -bool Player::HasItemEquipped(ITEM_EQUIP_TYPE uEquipIndex) -{ - uint i = pEquipment.pIndices[uEquipIndex]; - if (i) - return !pOwnItems[i - 1].IsBroken(); - else - return false; -} - -//----- (0048D6D0) -------------------------------------------------------- -bool Player::HasEnchantedItemEquipped(int uEnchantment) -{ - for (uint i = 0; i < 16; ++i) - { - if (HasItemEquipped((ITEM_EQUIP_TYPE)i) && - GetNthEquippedIndexItem(i)->uSpecEnchantmentType == uEnchantment) - return true; - } - return false; -} - -//----- (0048D709) -------------------------------------------------------- -bool Player::WearsItem( int item_id, ITEM_EQUIP_TYPE equip_type ) -{ - return ( HasItemEquipped(equip_type) && GetNthEquippedIndexItem(equip_type)->uItemID == item_id ); -} - -bool Player::WearsItemAnyWhere(int item_id) -{ - for (int i = 0; i < 16; i++) - { - if (WearsItem(item_id, (ITEM_EQUIP_TYPE) i)) - { - return true; - } - } - return false; -} - -//----- (0048D76C) -------------------------------------------------------- -int Player::StealFromShop( ItemGen *itemToSteal, int extraStealDifficulty, int reputation, int a5, int *fineIfFailed ) //returns an int, but is the return value is compared to zero, so might change to bool -{ - unsigned __int16 v6; // cx@8 - int v7; // edi@8 - unsigned int v8; // ebx@8 - unsigned int itemvalue; // esi@8 - int v10; // eax@8 - int currMaxItemValue; // edi@12 - - if ( !itemToSteal - || this->IsEradicated() - || this->IsDead() - || this->IsPertified() - || this->IsDrunk() - || this->IsUnconcious() - || this->IsAsleep() ) - { - return 0; - } - else - { - v6 = this->pActiveSkills[PLAYER_SKILL_STEALING]; - v7 = v6 & 0x3F; - v8 = SkillToMastery(v6); - itemvalue = itemToSteal->GetValue(); - v10 = itemToSteal->GetItemEquipType(); - if ( v10 == EQUIP_SINGLE_HANDED || v10 == EQUIP_TWO_HANDED || v10 == EQUIP_BOW ) - itemvalue *= 3; - currMaxItemValue = StealingRandomBonuses[rand() % 5] + v7 * StealingMasteryBonuses[v8]; - *fineIfFailed = 100 * (reputation + extraStealDifficulty) + itemvalue; - if (a5) - { - *fineIfFailed += 500; - } - if ( rand() % 100 >= 5 ) - { - if ( *fineIfFailed > currMaxItemValue ) - if (*fineIfFailed - currMaxItemValue < 500) - { - return 1; - } - else - { - return 0; - } - else - return 2; - } - else - { - return 0; - } - } -} - -//----- (0048D88B) -------------------------------------------------------- -int Player::StealFromActor(unsigned int uActorID, int _steal_perm, int reputation) -{ - Actor *actroPtr; // edi@1 - int v7; // ebx@10 - unsigned int stealingMastery; // esi@10 - int fineIfFailed; // esi@10 - int v11; // eax@13 - bool HasFullItemSlots; // ebx@15 - unsigned __int16 carriedItemId; // si@21 - unsigned int enchBonusSum; // esi@31 - int *enchTypePtr; // eax@34 - ItemGen tempItem; // [sp+8h] [bp-34h]@15 - int currMaxItemValue; - - actroPtr = &pActors[uActorID]; - if ( !actroPtr - || this->IsEradicated() - || this->IsDead() - || this->IsPertified() - || this->IsDrunk() - || this->IsUnconcious() - || this->IsAsleep() ) - { - return 0; - } - if ( !actroPtr->ActorHasItem() ) - actroPtr->SetRandomGoldIfTheresNoItem(); - unsigned __int16 v6 = this->pActiveSkills[PLAYER_SKILL_STEALING]; - v7 = v6 & 0x3F; - stealingMastery = SkillToMastery(v6); - int v30 = StealingMasteryBonuses[stealingMastery]; - int v29 = StealingRandomBonuses[rand() % 5]; - fineIfFailed = actroPtr->pMonsterInfo.uLevel + 100 * (_steal_perm + reputation); - currMaxItemValue = v29 + v7 * v30; - if ( rand() % 100 < 5 || fineIfFailed > currMaxItemValue || actroPtr->ActorEnemy() ) - { - Actor::AggroSurroundingPeasants(uActorID, 1); - sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[376], this->pName);//"%s was caught stealing!" - ShowStatusBarString(pTmpBuf2.data(), 2); - return 0; - } - else - { - v11 = rand(); - if ( v11 % 100 >= 70 ) //stealing gold - { - enchBonusSum = 0; - for (int i = 0; i < v7; i++) - enchBonusSum += rand() % StealingEnchantmentBonusForSkill[stealingMastery] + 1; - if ( actroPtr->ActorHasItems[3].GetItemEquipType() != EQUIP_GOLD ) - return 2; - enchTypePtr = &actroPtr->ActorHasItems[3].uSpecEnchantmentType; - if ( (int)enchBonusSum >= *enchTypePtr ) - { - actroPtr->ActorHasItems[3].uItemID = 0; - *enchTypePtr = 0; - } - else - *enchTypePtr -= enchBonusSum; - if ( enchBonusSum ) - { - pParty->PartyFindsGold(enchBonusSum, 2); - sprintf(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[302], this->pName, enchBonusSum); //%stole %d gold - } - else - sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[377], this->pName); //%s failed to steal anything - ShowStatusBarString(pTmpBuf2.data(), 2); - return 2; - } - else if ( v11 % 100 >= 40 ) //stealing an item - { - tempItem.Reset(); - HasFullItemSlots = false; - int i; - for (i = 0; i < 4; i++) - { - if ( actroPtr->ActorHasItems[i].uItemID != 0 && actroPtr->ActorHasItems[i].GetItemEquipType() != EQUIP_GOLD ) - break; - } - if (i == 4) - HasFullItemSlots = true; - carriedItemId = actroPtr->uCarriedItemID; - if ( carriedItemId != 0 || HasFullItemSlots ) - { - tempItem.Reset(); - if ( carriedItemId != 0 ) - { - actroPtr->uCarriedItemID = 0; - tempItem.uItemID = carriedItemId; - if ( pItemsTable->pItems[carriedItemId].uEquipType == EQUIP_WAND ) - tempItem.uNumCharges = rand() % 6 + pItemsTable->pItems[carriedItemId].uDamageMod + 1; - else if ( pItemsTable->pItems[carriedItemId].uEquipType == EQUIP_POTION && carriedItemId != ITEM_POTION_BOTTLE) - tempItem.uEnchantmentType = 2 * rand() % 4 + 2; - } - else - { - ItemGen* itemToSteal = &actroPtr->ActorHasItems[rand() % 4]; - memcpy(&tempItem, itemToSteal, sizeof(tempItem)); - itemToSteal->Reset(); - carriedItemId = tempItem.uItemID; - } - if (carriedItemId != 0) // looks odd in current context, but avoids accessing zeroth element of pItemsTable->pItems - { - pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); - sprintf( - pTmpBuf2.data(), - pGlobalTXT_LocalizationStrings[304], // Official //TODO: add a normal "%d stole %d" message - this->pName, - pItemsTable->pItems[carriedItemId].pUnidentifiedName); - ShowStatusBarString(pTmpBuf2.data(), 2u); - pParty->sub_421B2C_PlaceInInventory_or_DropPickedItem(); - memcpy(&pParty->pPickedItem, &tempItem, sizeof(ItemGen)); - pMouse->SetCursorBitmapFromItemID(carriedItemId); - return 2; - } - } - } - sprintfex(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[377], this->pName); //%s failed to steal anything - ShowStatusBarString(pTmpBuf2.data(), 2); - return 2; - } -} -// 4EDEA0: using guessed type int dword_4EDEA0[]; -// 4EDEB4: using guessed type int dword_4EDEB4[]; -// 4EDEC4: using guessed type int dword_4EDEC4[]; - -//----- (0048DBB9) -------------------------------------------------------- -void Player::Heal(int amount) -{ - signed int max_health; // eax@3 - - if ( !IsEradicated() && !IsDead() ) - { - max_health = GetMaxHealth(); - if ( IsZombie() ) - max_health /= 2; - sHealth += amount; - if ( sHealth > max_health ) - sHealth = max_health; - if ( IsUnconcious() ) - { - if ( sHealth > 0 ) - { - SetUnconcious(false); - } - } - } -} - -//----- (0048DC1E) -------------------------------------------------------- -int Player::ReceiveDamage( signed int amount, DAMAGE_TYPE dmg_type ) - { - signed int recieved_dmg; // eax@1 - bool broke_armor; - - SetAsleep(false); - recieved_dmg = CalculateIncommingDamage(dmg_type, amount); - sHealth -= recieved_dmg; - broke_armor = sHealth <= -10; - if ( sHealth < 1 ) // - { - if ( (sHealth + uEndurance + GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE) >= 1) - || pPlayerBuffs[PLAYER_BUFF_PRESERVATION].uExpireTime > 0 ) - { - SetCondUnconsciousWithBlockCheck(false); - } - else - { - SetCondDeadWithBlockCheck(false); - if ( sHealth > 0 ) - sHealth = 0; - } - if (broke_armor ) - { - ItemGen* equippedArmor = GetArmorItem(); - if ( equippedArmor != nullptr ) - { - if ( !(equippedArmor->uAttributes & ITEM_HARDENED)) - { - equippedArmor->SetBroken(); - } - } - } - } - if ( recieved_dmg && CanAct() ) - PlaySound(SPEECH_24, 0); - return recieved_dmg; -} - -//----- (0048DCF6) -------------------------------------------------------- -int Player::ReceiveSpecialAttackEffect( int attType, struct Actor *pActor ) -{ - SPECIAL_ATTACK_TYPE attTypeCast = (SPECIAL_ATTACK_TYPE) attType; - signed int v3; // edi@1 - signed int v4; // ebx@1 - int v6; // eax@2 - int v8; // eax@8 - int v10; // eax@8 - int v11; // ebx@8 - ItemGen *v13; // eax@9 - int v22; // eax@49 - signed int v23; // ebx@49 - void *v27; // ecx@76 - char v46[140]; // [sp+Ch] [bp-94h]@13 - unsigned int v47; // [sp+98h] [bp-8h]@1 - ItemGen* v48; // [sp+9Ch] [bp-4h]@1 - - v4 = 0; - v47 = 0; - v48 = nullptr; - switch ( attTypeCast ) - { - case SPECIAL_ATTACK_CURSE: - v6 = GetActualWillpower(); - v11 = GetParameterBonus(v6); - break; - case SPECIAL_ATTACK_WEAK: - case SPECIAL_ATTACK_SLEEP: - case SPECIAL_ATTACK_DRUNK: - case SPECIAL_ATTACK_DISEASE_WEAK: - case SPECIAL_ATTACK_DISEASE_MEDIUM: - case SPECIAL_ATTACK_DISEASE_SEVERE: - case SPECIAL_ATTACK_UNCONSCIOUS: - case SPECIAL_ATTACK_AGING: - v6 = GetActualEndurance(); - v11 = GetParameterBonus(v6); - break; - case SPECIAL_ATTACK_INSANE: - case SPECIAL_ATTACK_PARALYZED: - case SPECIAL_ATTACK_FEAR: - v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_MIND); - break; - case SPECIAL_ATTACK_PETRIFIED: - v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_EARTH); - break; - case SPECIAL_ATTACK_POISON_WEAK: - case SPECIAL_ATTACK_POISON_MEDIUM: - case SPECIAL_ATTACK_POISON_SEVERE: - case SPECIAL_ATTACK_DEAD: - case SPECIAL_ATTACK_ERADICATED: - v11 = GetActualResistance(CHARACTER_ATTRIBUTE_RESIST_BODY); - break; - case SPECIAL_ATTACK_MANA_DRAIN: - v8 = GetActualWillpower(); - v10 = GetActualIntelligence(); - v11 = (GetParameterBonus(v10) + GetParameterBonus(v8)) / 2; - break; - case SPECIAL_ATTACK_BREAK_ANY: - for (int i = 0; i < 138; i++) - { - v13 = &this->pInventoryItemList[i]; - if ( v13->uItemID > 0 && v13->uItemID <= 134 && !v13->IsBroken()) - v46[v4++] = i; - } - if ( !v4 ) - return 0; - v48 = &this->pInventoryItemList[v46[rand() % v4]]; - v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); - break; - case SPECIAL_ATTACK_BREAK_ARMOR: - for (int i = 0; i < 16; i++ ) - { - if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - if ( i == EQUIP_ARMOUR ) - v46[v4++] = this->pEquipment.uArmor - 1; - if ( (i == EQUIP_SINGLE_HANDED || i == EQUIP_TWO_HANDED) && GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_SHIELD ) - v46[v4++] = this->pEquipment.pIndices[i] - 1; - } - } - if ( !v4 ) - return 0; - v48 = &this->pInventoryItemList[v46[rand() % v4]]; - v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); - break; - case SPECIAL_ATTACK_BREAK_WEAPON: - for (int i = 0; i < 16; i++ ) - { - if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - if ( i == EQUIP_BOW ) - v46[v4++] = LOBYTE(this->pEquipment.uBow) - 1; - if ( (i == EQUIP_SINGLE_HANDED || i == EQUIP_TWO_HANDED) - && (GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_SINGLE_HANDED || GetEquippedItemEquipType((ITEM_EQUIP_TYPE)i) == EQUIP_TWO_HANDED) ) - v46[v4++] = this->pEquipment.pIndices[i] - 1; - } - } - if ( !v4 ) - return 0; - v48 = &this->pInventoryItemList[v46[rand() % v4]]; - v11 = 3 * (pItemsTable->pItems[v48->uItemID].uMaterial + v48->GetDamageMod()); - break; - case SPECIAL_ATTACK_STEAL: - for ( int i = 0; i < 126; i++ ) - { - int ItemPosInList = this->pInventoryMatrix[i]; - if (ItemPosInList > 0) - { - ItemGen* v21 = &this->pInventoryItemList[ItemPosInList - 1]; - if ( v21->uItemID > 0 && v21->uItemID <= 134 ) - { - v46[v4++] = i; - } - } - } - if ( !v4 ) - return 0; - v47 = v46[rand() % v4]; - v6 = GetActualAccuracy(); - v11 = GetParameterBonus(v6); - break; - default: - v11 = 0; - break; - } - v22 = GetActualLuck(); - v23 = GetParameterBonus(v22) + v11 + 30; - if ( rand() % v23 >= 30 ) - { - return 0; - } - else - { - for ( v3 = 0; v3 < 4; v3++ ) - { - if ( this == pPlayers[v3 + 1] ) - break; - } - - switch ( attTypeCast ) - { - case SPECIAL_ATTACK_CURSE: - SetCondition(Condition_Cursed, 1); - pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_WEAK: - SetCondition(Condition_Weak, 1); - pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_SLEEP: - SetCondition(Condition_Sleep, 1); - pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_DRUNK: - SetCondition(Condition_Drunk, 1); - pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_INSANE: - SetCondition(Condition_Insane, 1); - pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_POISON_WEAK: - SetCondition(Condition_Poison_Weak, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_POISON_MEDIUM: - SetCondition(Condition_Poison_Medium, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_POISON_SEVERE: - SetCondition(Condition_Poison_Severe, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_DISEASE_WEAK: - SetCondition(Condition_Disease_Weak, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_DISEASE_MEDIUM: - SetCondition(Condition_Disease_Medium, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_DISEASE_SEVERE: - SetCondition(Condition_Disease_Severe, 1); - pAudioPlayer->PlaySound((SoundID)222, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_PARALYZED: - SetCondition(Condition_Paralyzed, 1); - pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_UNCONSCIOUS: - SetCondition(Condition_Unconcious, 1); - pAudioPlayer->PlaySound((SoundID)224, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_DEAD: - SetCondition(Condition_Dead, 1); - pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_PETRIFIED: - SetCondition(Condition_Pertified, 1); - pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_ERADICATED: - SetCondition(Condition_Eradicated, 1); - pAudioPlayer->PlaySound((SoundID)225, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_BREAK_ANY: - case SPECIAL_ATTACK_BREAK_ARMOR: - case SPECIAL_ATTACK_BREAK_WEAPON: - if ( !(v48->uAttributes & ITEM_HARDENED) ) - { - PlaySound(SPEECH_40, 0); - v48->SetBroken(); - pAudioPlayer->PlaySound((SoundID)47, 0, 0, -1, 0, 0, 0, 0); - } - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_STEAL: - PlaySound(SPEECH_40, 0); - v27 = pActor->ActorHasItems; - if ( pActor->ActorHasItems[0].uItemID ) - { - v27 = &pActor->ActorHasItems[1]; - if ( pActor->ActorHasItems[1].uItemID ) - { - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - } - } - memcpy(v27, &this->pInventoryItemList[this->pInventoryMatrix[v47]-1], 0x24u); - RemoveItemAtInventoryIndex(v47); - pAudioPlayer->PlaySound((SoundID)47, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_AGING: - PlaySound(SPEECH_42, 0); - ++this->sAgeModifier; - pAudioPlayer->PlaySound((SoundID)226, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_MANA_DRAIN: - PlaySound(SPEECH_41, 0); - this->sMana = 0; - pAudioPlayer->PlaySound((SoundID)226, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - case SPECIAL_ATTACK_FEAR: - SetCondition(Condition_Fear, 1); - pAudioPlayer->PlaySound((SoundID)221, 0, 0, -1, 0, 0, 0, 0); - pGame->pStru6Instance->SetPlayerBuffAnim(0x99u, v3); - return 1; - break; - default: - return 0; - } - } -} - -// 48DCF6: using guessed type char var_94[140]; - -//----- (0048E1A3) -------------------------------------------------------- -unsigned int Player::GetSpellSchool(unsigned int uSpellID) -{ - return pSpellStats->pInfos[uSpellID].uSchool; -} - -//----- (0048E1B5) -------------------------------------------------------- -int Player::GetAttackRecoveryTime(bool bRangedAttack) -{ - ItemGen *weapon = nullptr; - uint weapon_recovery = base_recovery_times_per_weapon_type[0]; - if (bRangedAttack) - { - if ( HasItemEquipped(EQUIP_BOW) ) - { - weapon = GetBowItem(); - weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; - } - } - else if ( IsUnarmed() == 1 && GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) - { - weapon_recovery = base_recovery_times_per_weapon_type[1]; - } - else if ( HasItemEquipped(EQUIP_TWO_HANDED) ) - { - weapon = GetMainHandItem(); - if (weapon->GetItemEquipType() == EQUIP_WAND) - { - __debugbreak(); // looks like offset in player's inventory and wand_lut much like case in 0042ECB5 - __debugbreak(); // looks like wands were two-handed weapons once, or supposed to be. should not get here now - weapon_recovery = pSpellDatas[wand_spell_ids[weapon->uItemID - ITEM_WAND_FIRE]].uExpertLevelRecovery; - } - else - weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; - } - if (HasItemEquipped(EQUIP_SINGLE_HANDED) && GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) != EQUIP_SHIELD) - // ADD: shield check because shield recovery is added later and can be accidentally doubled - { - if (base_recovery_times_per_weapon_type[GetOffHandItem()->GetPlayerSkillType()] > weapon_recovery) - { - weapon = GetOffHandItem(); - weapon_recovery = base_recovery_times_per_weapon_type[weapon->GetPlayerSkillType()]; - } - } - - uint armour_recovery = 0; - if ( HasItemEquipped(EQUIP_ARMOUR) ) - { - uchar armour_skill_type = GetArmorItem()->GetPlayerSkillType(); - uint base_armour_recovery = base_recovery_times_per_weapon_type[armour_skill_type]; - float multiplier; - - if (armour_skill_type == PLAYER_SKILL_LEATHER) - { - multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0, 0, 0); - } - else if (armour_skill_type == PLAYER_SKILL_CHAIN) - { - multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0.5f, 0, 0); - } - else if (armour_skill_type == PLAYER_SKILL_PLATE) - { - multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 0.5f, 0.5f, 0); - } - else - { - Error("Unknown armour type"); // what kind of armour is that? - multiplier = GetArmorRecoveryMultiplierFromSkillLevel(armour_skill_type, 1.0f, 1.0f, 1.0f, 1.0f); - } - - armour_recovery = (uint)(base_armour_recovery * multiplier); - } - - uint shield_recovery = 0; - if (HasItemEquipped(EQUIP_SINGLE_HANDED) && GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) == EQUIP_SHIELD) - { - uchar skill_type = GetOffHandItem()->GetPlayerSkillType(); - - uint shield_base_recovery = base_recovery_times_per_weapon_type[skill_type]; - float multiplier = GetArmorRecoveryMultiplierFromSkillLevel(skill_type, 1.0f, 0, 0, 0); - shield_recovery = (uint)(shield_base_recovery * multiplier); - } - - uint player_speed_recovery_reduction = GetParameterBonus(GetActualSpeed()), - sword_axe_bow_recovery_reduction = 0; - bool shooting_laser = false; - if (weapon != nullptr) - { - if (GetActualSkillLevel((PLAYER_SKILL_TYPE)weapon->GetPlayerSkillType()) && - (weapon->GetPlayerSkillType() == PLAYER_SKILL_SWORD || weapon->GetPlayerSkillType() == PLAYER_SKILL_AXE || weapon->GetPlayerSkillType() == PLAYER_SKILL_BOW) ) - { - if (SkillToMastery(pActiveSkills[weapon->GetPlayerSkillType()]) >= 2 ) // Expert Sword, Axe & Bow reduce recovery - sword_axe_bow_recovery_reduction = pActiveSkills[weapon->GetPlayerSkillType()] & 0x3F; - } - if (weapon->GetPlayerSkillType() == PLAYER_SKILL_BLASTER) - shooting_laser = true; - } - - uint armsmaster_recovery_reduction = 0; - if (!bRangedAttack && !shooting_laser) - { - if (uint armsmaster_level = GetActualSkillLevel(PLAYER_SKILL_ARMSMASTER)) - { - armsmaster_recovery_reduction = armsmaster_level & 0x3F; - if (SkillToMastery(armsmaster_level) >= 4) - armsmaster_recovery_reduction *= 2; - } - } - - uint hasteRecoveryReduction = 0; - if (pPlayerBuffs[PLAYER_BUFF_HASTE].uExpireTime > 0 || pParty->pPartyBuffs[PARTY_BUFF_HASTE].uExpireTime > 0 ) - hasteRecoveryReduction = 25; - - uint weapon_enchantment_recovery_reduction = 0; - if ( weapon ) - { - if (weapon->uSpecEnchantmentType == 59 || - weapon->uSpecEnchantmentType == 41 || - weapon->uSpecEnchantmentType == 500) - weapon_enchantment_recovery_reduction = 20; - } - - int recovery = weapon_recovery + - armour_recovery + - shield_recovery - - armsmaster_recovery_reduction - - weapon_enchantment_recovery_reduction - - hasteRecoveryReduction - - sword_axe_bow_recovery_reduction - - player_speed_recovery_reduction; - - if (recovery < 0) - recovery = 0; - return recovery; -} - - -//----- new -------------------------------------------------------- -float Player::GetArmorRecoveryMultiplierFromSkillLevel( unsigned char armour_skill_type, float mult1, float mult2, float mult3, float mult4 ) -{ - uint skill_mastery = SkillToMastery(pActiveSkills[armour_skill_type]); - switch (skill_mastery) - { - case 1: return mult1; break; - case 2: return mult2; break; - case 3: return mult3; break; - case 4: return mult4; break; - } - Error("Unexpected input value: %d", armour_skill_type); - return 0; -} - -//----- (0048E4F8) -------------------------------------------------------- -int Player::GetMaxHealth() -{ - int v3; // esi@1 - int v4; // esi@1 - int v6; // esi@1 - - v3 = GetParameterBonus(GetActualEndurance()); - v4 = pBaseHealthPerLevelByClass[classType] * (GetActualLevel() + v3); - v6 = uFullHealthBonus - + pBaseHealthByClass[classType / 4] - + GetSkillBonus(CHARACTER_ATTRIBUTE_HEALTH) - + GetItemsBonus(CHARACTER_ATTRIBUTE_HEALTH) + v4; - return max(1, v6); -} - -//----- (0048E565) -------------------------------------------------------- -int Player::GetMaxMana() -{ - int v2; // eax@2 - int v3; // esi@4 - int v4; // eax@5 - int v5; // esi@5 - int v6; // eax@5 - int v7; // esi@6 - int v8; // esi@6 - int v9; // esi@6 - - switch (classType) - { - case PLAYER_CLASS_ROGUE: - case PLAYER_CLASS_SPY: - case PLAYER_CLASS_ASSASSIN: - case PLAYER_CLASS_ARCHER: - case PLAYER_CLASS_WARRIOR_MAGE: - case PLAYER_CLASS_MASTER_ARCHER: - case PLAYER_CLASS_SNIPER: - case PLAYER_CLASS_SORCERER: - case PLAYER_CLASS_WIZARD: - case PLAYER_CLASS_ARCHMAGE: - case PLAYER_CLASS_LICH: - v2 = GetActualIntelligence(); - v3 = GetParameterBonus(v2); - break; - case PLAYER_CLASS_INITIATE: - case PLAYER_CLASS_MASTER: - case PLAYER_CLASS_NINJA: - case PLAYER_CLASS_PALADIN: - case PLAYER_CLASS_CRUSADER: - case PLAYER_CLASS_HERO: - case PLAYER_CLASS_VILLIAN: - case PLAYER_CLASS_CLERIC: - case PLAYER_CLASS_PRIEST: - case PLAYER_CLASS_PRIEST_OF_SUN: - case PLAYER_CLASS_PRIEST_OF_MOON: - v2 = GetActualWillpower(); - v3 = GetParameterBonus(v2); - break; - case PLAYER_CLASS_HUNTER: - case PLAYER_CLASS_RANGER_LORD: - case PLAYER_CLASS_BOUNTY_HUNTER: - case PLAYER_CLASS_DRUID: - case PLAYER_CLASS_GREAT_DRUID: - case PLAYER_CLASS_ARCH_DRUID: - case PLAYER_CLASS_WARLOCK: - v4 = GetActualWillpower(); - v5 = GetParameterBonus(v4); - v6 = GetActualIntelligence(); - v3 = GetParameterBonus(v6) + v5; - break; - default: - return 0; - break; - } - v7 = pBaseManaPerLevelByClass[classType] * (GetActualLevel() + v3); - v8 = GetItemsBonus(CHARACTER_ATTRIBUTE_MANA) + v7; - v9 = uFullManaBonus - + pBaseManaByClass[classType / 4] - + GetSkillBonus(CHARACTER_ATTRIBUTE_MANA) - + v8; - return max(0,v9); -} - -//----- (0048E656) -------------------------------------------------------- -int Player::GetBaseAC() -{ - int v2; // eax@1 - int v3; // esi@1 - int v4; // esi@1 - int v5; // esi@1 - - v2 = GetActualSpeed(); - v3 = GetParameterBonus(v2); - v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v3; - v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v4; - return max(0, v5); -} - -//----- (0048E68F) -------------------------------------------------------- -int Player::GetActualAC() -{ - int v2; // eax@1 - int v3; // esi@1 - int v4; // esi@1 - int v5; // esi@1 - int v6; // esi@1 - - v2 = GetActualSpeed(); - v3 = GetParameterBonus(v2); - v4 = GetItemsBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v3; - v5 = GetSkillBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v4; - v6 = this->sACModifier + GetMagicalBonus(CHARACTER_ATTRIBUTE_AC_BONUS) + v5; - return max(0, v6); -} - -//----- (0048E6DC) -------------------------------------------------------- -unsigned int Player::GetBaseAge() -{ - return (unsigned int)(((__int64)(pParty->uTimePlayed * 0.234375) / 60 / 60 / 24) / 7 / 4 / 12 - uBirthYear + game_starting_year); -} - -//----- (0048E72C) -------------------------------------------------------- -unsigned int Player::GetActualAge() -{ - return this->sAgeModifier + GetBaseAge(); -} - -//----- (0048E73F) -------------------------------------------------------- -int Player::GetBaseResistance(enum CHARACTER_ATTRIBUTE_TYPE a2) -{ - int v7; // esi@20 - int racialBonus = 0; - __int16* resStat; - int result; - - switch (a2) - { - case CHARACTER_ATTRIBUTE_RESIST_FIRE: - resStat = &sResFireBase; - if (IsRaceGoblin()) - racialBonus = 5; - break; - case CHARACTER_ATTRIBUTE_RESIST_AIR: - resStat = &sResAirBase; - if (IsRaceGoblin()) - racialBonus = 5; - break; - case CHARACTER_ATTRIBUTE_RESIST_WATER: - resStat = &sResWaterBase; - if (IsRaceDwarf()) - racialBonus = 5; - break; - case CHARACTER_ATTRIBUTE_RESIST_EARTH: - resStat = &sResEarthBase; - if (IsRaceDwarf()) - racialBonus = 5; - break; - case CHARACTER_ATTRIBUTE_RESIST_MIND: - resStat = &sResMindBase; - if (IsRaceElf()) - racialBonus = 10; - break; - case CHARACTER_ATTRIBUTE_RESIST_BODY: - case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: - resStat = &sResBodyBase; - if (IsRaceHuman()) - racialBonus = 5; - break; - default: - Error("Unknown attribute"); - } - v7 = GetItemsBonus(a2) + racialBonus; - result = v7 + *resStat; - if ( classType == PLAYER_CLASS_LICH ) - { - if ( result > 200 ) - result = 200; - } - return result; -} - -//----- (0048E7D0) -------------------------------------------------------- -int Player::GetActualResistance(enum CHARACTER_ATTRIBUTE_TYPE a2) -{ - signed int v10 = 0; // [sp+14h] [bp-4h]@1 - __int16* resStat; - int result; - int baseRes; - - int leatherArmorSkillLevel = GetActualSkillLevel(PLAYER_SKILL_LEATHER); - if ( CheckHiredNPCSpeciality(Enchanter) ) - v10 = 20; - if ( (a2 == CHARACTER_ATTRIBUTE_RESIST_FIRE - || a2 == CHARACTER_ATTRIBUTE_RESIST_AIR - || a2 == CHARACTER_ATTRIBUTE_RESIST_WATER - || a2 == CHARACTER_ATTRIBUTE_RESIST_EARTH) - && SkillToMastery(leatherArmorSkillLevel) == 4 - && HasItemEquipped(EQUIP_ARMOUR) - && GetEquippedItemSkillType(EQUIP_ARMOUR) == PLAYER_SKILL_LEATHER ) - v10 += leatherArmorSkillLevel & 0x3F; - switch (a2) - { - case CHARACTER_ATTRIBUTE_RESIST_FIRE: - resStat = &sResFireBonus; - break; - case CHARACTER_ATTRIBUTE_RESIST_AIR: - resStat = &sResAirBonus; - break; - case CHARACTER_ATTRIBUTE_RESIST_WATER: - resStat = &sResWaterBonus; - break; - case CHARACTER_ATTRIBUTE_RESIST_EARTH: - resStat = &sResEarthBonus; - break; - case CHARACTER_ATTRIBUTE_RESIST_MIND: - resStat = &sResMindBonus; - break; - case CHARACTER_ATTRIBUTE_RESIST_BODY: - case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: - resStat = &sResBodyBonus; - break; - default: Error("Unexpected attribute"); - } - baseRes = GetBaseResistance(a2); - result = v10 + GetMagicalBonus(a2) + baseRes + *(resStat); - if ( classType == PLAYER_CLASS_LICH ) - { - if ( result > 200 ) - result = 200; - } - return result; -} - -//----- (0048E8F5) -------------------------------------------------------- -bool Player::Recover(int dt) -{ - int v3; // qax@1 - - v3 = (int)(dt * GetSpecialItemBonus(17) * 0.01 + dt); - - //Log::Warning(L"Recover(dt = %u/%u - %u", dt, (uint)v3, (uint)uTimeToRecovery); - - if (uTimeToRecovery > v3) - { - uTimeToRecovery -= v3; - return true; - } - else - { - uTimeToRecovery = 0; - viewparams->bRedrawGameUI = true; - if (!uActiveCharacter) - uActiveCharacter = pParty->GetNextActiveCharacter(); - return false; - } -} - -//----- (0048E96A) -------------------------------------------------------- -void Player::SetRecoveryTime(signed int rec) -{ - Assert(rec >= 0); - - if (rec > uTimeToRecovery) - uTimeToRecovery = rec; - - if (uActiveCharacter != 0 && pPlayers[uActiveCharacter] == this && !some_active_character) - uActiveCharacter = pParty->GetNextActiveCharacter(); - - viewparams->bRedrawGameUI = true; -} -// 50C0C4: using guessed type int some_active_character; - -//----- (0048E9B7) -------------------------------------------------------- -void Player::RandomizeName() -{ - if (!uExpressionTimePassed) - strcpy(pName, pNPCStats->pNPCNames[rand() % pNPCStats->uNumNPCNames[uSex]][uSex]); -} - -//----- (0048E9F4) -------------------------------------------------------- -unsigned int Player::GetMajorConditionIdx() -{ - for (uint i = 0; i < 18; ++i) - if (pConditions[pConditionImportancyTable[i]] != 0) - return pConditionImportancyTable[i]; - - return 18; -} - -//----- (0048EA1B) -------------------------------------------------------- -int Player::GetParameterBonus( int player_parameter ) -{ - int i; // eax@1 - i = 0; - while (param_to_bonus_table[i]) - { - if (player_parameter >= param_to_bonus_table[i]) - break; - ++i; - } - return parameter_to_bonus_value[i]; -} - -//----- (0048EA46) -------------------------------------------------------- -int Player::GetSpecialItemBonus( int enchantmentId ) -{ - for (int i = EQUIP_SINGLE_HANDED; i < EQUIP_BOOK; ++i ) - { - if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - if (enchantmentId == 17) - { - if ((GetNthEquippedIndexItem(i)->uSpecEnchantmentType == 17) || (GetNthEquippedIndexItem(i)->uItemID == 533)) //Elven Chainmail+Increases rate of Recovery - return 50; - } - if (enchantmentId == 24) - { - if (GetNthEquippedIndexItem(i)->uSpecEnchantmentType == 24) //Increased Knockback. - return 5; - } - } - } - return 0; -} - -//----- (0048EAAE) -------------------------------------------------------- -int Player::GetItemsBonus( enum CHARACTER_ATTRIBUTE_TYPE attr, bool getOnlyMainHandDmg /*= false*/ ) -{ - int v5; // edi@1 - int v9; // eax@49 - int v14; // ecx@58 - int v15; // eax@58 - int v17; // eax@62 - int v22; // eax@76 - int v25; // ecx@80 - int v26; // edi@80 - int v32; // eax@98 - int v56; // eax@365 - signed int v58; // [sp-4h] [bp-20h]@10 - int v61; // [sp+10h] [bp-Ch]@1 - int v62; // [sp+14h] [bp-8h]@1 - ItemGen *currEquippedItem; // [sp+20h] [bp+4h]@101 - bool no_skills; - - v5 = 0; - v62 = 0; - v61 = 0; - - no_skills=false; - switch (attr) - { - case CHARACTER_ATTRIBUTE_SKILL_ALCHEMY: v58 = PLAYER_SKILL_ALCHEMY; break; - case CHARACTER_ATTRIBUTE_SKILL_STEALING: v58 = PLAYER_SKILL_STEALING; break; - case CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM: v58 = PLAYER_SKILL_TRAP_DISARM; break; - case CHARACTER_ATTRIBUTE_SKILL_ITEM_ID: v58 = PLAYER_SKILL_ITEM_ID; break; - case CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID: v58 = PLAYER_SKILL_MONSTER_ID; break; - case CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER: v58 = PLAYER_SKILL_ARMSMASTER; break; - case CHARACTER_ATTRIBUTE_SKILL_DODGE: v58 = PLAYER_SKILL_DODGE; break; - case CHARACTER_ATTRIBUTE_SKILL_UNARMED: v58 = PLAYER_SKILL_UNARMED; break; - case CHARACTER_ATTRIBUTE_SKILL_FIRE: v58 = PLAYER_SKILL_FIRE; break; - case CHARACTER_ATTRIBUTE_SKILL_AIR: v58 = PLAYER_SKILL_AIR; break; - case CHARACTER_ATTRIBUTE_SKILL_WATER: v58 = PLAYER_SKILL_WATER; break; - case CHARACTER_ATTRIBUTE_SKILL_EARTH: v58 = PLAYER_SKILL_EARTH; break; - case CHARACTER_ATTRIBUTE_SKILL_SPIRIT: v58 = PLAYER_SKILL_SPIRIT; break; - case CHARACTER_ATTRIBUTE_SKILL_MIND: v58 = PLAYER_SKILL_MIND; break; - case CHARACTER_ATTRIBUTE_SKILL_BODY: v58 = PLAYER_SKILL_BODY; break; - case CHARACTER_ATTRIBUTE_SKILL_LIGHT: v58 = PLAYER_SKILL_LIGHT; break; - case CHARACTER_ATTRIBUTE_SKILL_DARK: v58 = PLAYER_SKILL_DARK; break; - case CHARACTER_ATTRIBUTE_SKILL_MEDITATION: v58 = PLAYER_SKILL_MEDITATION; break; - case CHARACTER_ATTRIBUTE_SKILL_BOW: v58 = PLAYER_SKILL_BOW; break; - case CHARACTER_ATTRIBUTE_SKILL_SHIELD: v58 = PLAYER_SKILL_SHIELD; break; - case CHARACTER_ATTRIBUTE_SKILL_LEARNING: v58 = PLAYER_SKILL_LEARNING; break; - default: - no_skills=true; - } - if (!no_skills) - { - if ( !this->pActiveSkills[v58] ) - return 0; - } - - switch(attr) //TODO would be nice to move these into separate functions - { - case CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS: - case CHARACTER_ATTRIBUTE_RANGED_ATTACK: - if ( HasItemEquipped(EQUIP_BOW) ) - v5 = GetBowItem()->GetDamageMod(); - return v5; - break; - - case CHARACTER_ATTRIBUTE_RANGED_DMG_MIN: - if ( !HasItemEquipped(EQUIP_BOW) ) - return 0; - v5 = GetBowItem()->GetDamageMod(); - v56 = GetBowItem()->GetDamageDice(); - return v5 + v56; - break; - - case CHARACTER_ATTRIBUTE_RANGED_DMG_MAX: - if ( !HasItemEquipped(EQUIP_BOW) ) - return 0; - v5 = GetBowItem()->GetDamageDice() * GetBowItem()->GetDamageRoll(); - v56 = GetBowItem()->GetDamageMod(); - return v5 + v56; - - case CHARACTER_ATTRIBUTE_LEVEL: - if ( !Player::HasEnchantedItemEquipped(25) ) - return 0; - return 5; - break; - - case CHARACTER_ATTRIBUTE_MELEE_DMG_MAX: - if ( IsUnarmed() ) - { - return 3; - } - else - { - if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) - { - v22 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); - if ( v22 >= 0 && v22 <= 2) - { - ItemGen* mainHandItem = GetMainHandItem(); - v26 = mainHandItem->GetDamageRoll(); - if ( GetOffHandItem() != nullptr || mainHandItem->GetPlayerSkillType() != 4 ) - { - v25 = mainHandItem->GetDamageDice(); - } - else - { - v25 = mainHandItem->GetDamageDice() + 1; - } - v5 = mainHandItem->GetDamageMod() + v25 * v26; - } - } - if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0 || GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2)) - { - return v5; - } - else - { - ItemGen* offHandItem = GetOffHandItem(); - v15 = offHandItem->GetDamageMod(); - v14 = offHandItem->GetDamageDice() * offHandItem->GetDamageRoll(); - return v5 + v15 + v14; - } - } - break; - - case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: - case CHARACTER_ATTRIBUTE_ATTACK: - if ( IsUnarmed() ) - { - return 0; - } - if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) - { - v17 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); - if ( v17 >= 0 && v17 <= 2) - { - v5 = GetMainHandItem()->GetDamageMod(); - } - } - if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0) || this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2 ) - return v5; - else - { - v56 = GetOffHandItem()->GetDamageMod(); - return v5 + v56; - } - break; - - case CHARACTER_ATTRIBUTE_MELEE_DMG_MIN: - if ( IsUnarmed() ) - { - return 1; - } - if ( this->HasItemEquipped(EQUIP_TWO_HANDED) ) - { - v9 = this->GetEquippedItemEquipType(EQUIP_TWO_HANDED); - if ( v9 >= 0 && v9 <= 2) - { - ItemGen* mainHandItem = GetMainHandItem(); - v5 = mainHandItem->GetDamageDice() + - mainHandItem->GetDamageMod(); - if ( GetOffHandItem() == nullptr && mainHandItem->GetPlayerSkillType() == 4) - { - ++v5; - } - } - } - - if ( getOnlyMainHandDmg || !this->HasItemEquipped(EQUIP_SINGLE_HANDED) || (this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) < 0) || this->GetEquippedItemEquipType(EQUIP_SINGLE_HANDED) > 2 ) - { - return v5; - } - else - { - ItemGen* offHandItem = GetOffHandItem(); - v14 = offHandItem->GetDamageMod(); - v15 = offHandItem->GetDamageDice(); - return v5 + v15 + v14; - } - break; - - case CHARACTER_ATTRIBUTE_STRENGTH: - case CHARACTER_ATTRIBUTE_INTELLIGENCE: - case CHARACTER_ATTRIBUTE_WILLPOWER: - case CHARACTER_ATTRIBUTE_ENDURANCE: - case CHARACTER_ATTRIBUTE_ACCURACY: - case CHARACTER_ATTRIBUTE_SPEED: - case CHARACTER_ATTRIBUTE_LUCK: - case CHARACTER_ATTRIBUTE_HEALTH: - case CHARACTER_ATTRIBUTE_MANA: - case CHARACTER_ATTRIBUTE_AC_BONUS: - - case CHARACTER_ATTRIBUTE_RESIST_FIRE: - case CHARACTER_ATTRIBUTE_RESIST_AIR: - case CHARACTER_ATTRIBUTE_RESIST_WATER: - case CHARACTER_ATTRIBUTE_RESIST_EARTH: - case CHARACTER_ATTRIBUTE_RESIST_MIND: - case CHARACTER_ATTRIBUTE_RESIST_BODY: - case CHARACTER_ATTRIBUTE_RESIST_SPIRIT: - - case CHARACTER_ATTRIBUTE_SKILL_ALCHEMY: - case CHARACTER_ATTRIBUTE_SKILL_STEALING: - case CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM: - case CHARACTER_ATTRIBUTE_SKILL_ITEM_ID: - case CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID: - case CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER: - case CHARACTER_ATTRIBUTE_SKILL_DODGE: - case CHARACTER_ATTRIBUTE_SKILL_UNARMED: - - case CHARACTER_ATTRIBUTE_SKILL_FIRE: - case CHARACTER_ATTRIBUTE_SKILL_AIR: - case CHARACTER_ATTRIBUTE_SKILL_WATER: - case CHARACTER_ATTRIBUTE_SKILL_EARTH: - case CHARACTER_ATTRIBUTE_SKILL_SPIRIT: - case CHARACTER_ATTRIBUTE_SKILL_MIND: - case CHARACTER_ATTRIBUTE_SKILL_BODY: - case CHARACTER_ATTRIBUTE_SKILL_LIGHT: - case CHARACTER_ATTRIBUTE_SKILL_DARK: - case CHARACTER_ATTRIBUTE_SKILL_MEDITATION: - case CHARACTER_ATTRIBUTE_SKILL_BOW: - case CHARACTER_ATTRIBUTE_SKILL_SHIELD: - case CHARACTER_ATTRIBUTE_SKILL_LEARNING: - for (int i = 0; i < 16; i++) - { - if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - currEquippedItem = GetNthEquippedIndexItem(i); - if ( attr == CHARACTER_ATTRIBUTE_AC_BONUS ) - { - v32 = currEquippedItem->GetItemEquipType(); - if ( v32 >= 3 && v32 <= 11 ) - { - v5 += currEquippedItem->GetDamageDice() + currEquippedItem->GetDamageMod(); - } - } - if ( pItemsTable->IsMaterialNonCommon(currEquippedItem) - && !pItemsTable->IsMaterialSpecial(currEquippedItem) ) - { - currEquippedItem->GetItemBonusArtifact(this, attr, &v62); - } - else if ( currEquippedItem->uEnchantmentType != 0 ) - { - if (this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uEnchantmentType - 1 == attr)//if (currEquippedItem->IsRegularEnchanmentForAttribute(attr)) - { - if ( attr > CHARACTER_ATTRIBUTE_RESIST_BODY && v5 < currEquippedItem->m_enchantmentStrength )//for skills bonuses - v5 = currEquippedItem->m_enchantmentStrength; - else // for resists and attributes bonuses - v5 += currEquippedItem->m_enchantmentStrength; - } - } - else - { - currEquippedItem->GetItemBonusSpecialEnchantment(this, attr, &v5, &v61); - } - } - } - return v5 + v62 + v61; - break; - default: - return 0; - } -} - -//----- (0048F73C) -------------------------------------------------------- -int Player::GetMagicalBonus(enum CHARACTER_ATTRIBUTE_TYPE a2) -{ - int v3 = 0; // eax@4 - int v4 = 0; // ecx@5 - - switch ( a2 ) - { - case CHARACTER_ATTRIBUTE_RESIST_FIRE: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_FIRE].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_FIRE].uPower; - break; - case CHARACTER_ATTRIBUTE_RESIST_AIR: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_AIR].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_AIR].uPower; - break; - case CHARACTER_ATTRIBUTE_RESIST_BODY: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_BODY].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_BODY].uPower; - break; - case CHARACTER_ATTRIBUTE_RESIST_WATER: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_WATER].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_WATER].uPower; - break; - case CHARACTER_ATTRIBUTE_RESIST_EARTH: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_EARTH].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_EARTH].uPower; - break; - case CHARACTER_ATTRIBUTE_RESIST_MIND: - v3 = this->pPlayerBuffs[PLAYER_BUFF_RESIST_MIND].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_RESIST_MIND].uPower; - break; - case CHARACTER_ATTRIBUTE_ATTACK: - case CHARACTER_ATTRIBUTE_RANGED_ATTACK: - v3 = this->pPlayerBuffs[PLAYER_BUFF_BLESS].uPower; //only player effect spell in both VI and VII - break; - case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: - v3 = this->pPlayerBuffs[PLAYER_BUFF_HEROISM].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_HEROISM].uPower; - break; - case CHARACTER_ATTRIBUTE_STRENGTH: - v3 = pPlayerBuffs[PLAYER_BUFF_STRENGTH].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_INTELLIGENCE: - v3 = pPlayerBuffs[PLAYER_BUFF_INTELLIGENCE].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_WILLPOWER: - v3 = pPlayerBuffs[PLAYER_BUFF_WILLPOWER].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_ENDURANCE: - v3 = pPlayerBuffs[PLAYER_BUFF_ENDURANCE].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_ACCURACY: - v3 = pPlayerBuffs[PLAYER_BUFF_ACCURACY].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_SPEED: - v3 = pPlayerBuffs[PLAYER_BUFF_SPEED].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_LUCK: - v3 = pPlayerBuffs[PLAYER_BUFF_LUCK].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].uPower; - break; - case CHARACTER_ATTRIBUTE_AC_BONUS: - v3 = this->pPlayerBuffs[PLAYER_BUFF_STONESKIN].uPower; - v4 = pParty->pPartyBuffs[PARTY_BUFF_STONE_SKIN].uPower; - break; - } - return v3 + v4; -} - -//----- (0048F882) -------------------------------------------------------- -int Player::GetActualSkillLevel( PLAYER_SKILL_TYPE uSkillType ) -{ - signed int bonus_value; // esi@1 - unsigned __int16 skill_value; // ax@126 - int result; // al@127 - - bonus_value = 0; - switch (uSkillType) - { - case PLAYER_SKILL_MONSTER_ID: - { - if ( CheckHiredNPCSpeciality(Hunter) ) - bonus_value = 6; - if ( CheckHiredNPCSpeciality(Sage) ) - bonus_value += 6; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID); - } - break; - - case PLAYER_SKILL_ARMSMASTER: - { - if ( CheckHiredNPCSpeciality(Armsmaster) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Weaponsmaster) ) - bonus_value += 3; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER); - } - break; - - case PLAYER_SKILL_STEALING: - { - if (CheckHiredNPCSpeciality(Burglar)) - bonus_value = 8; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_STEALING); - } - break; - - - case PLAYER_SKILL_ALCHEMY: - { - if ( CheckHiredNPCSpeciality(Herbalist) ) - bonus_value = 4; - if ( CheckHiredNPCSpeciality(Apothecary) ) - bonus_value += 8; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ALCHEMY); - } - break; - - case PLAYER_SKILL_LEARNING: - { - if ( CheckHiredNPCSpeciality(Teacher) ) - bonus_value = 10; - if ( CheckHiredNPCSpeciality(Instructor) ) - bonus_value += 15; - if ( CheckHiredNPCSpeciality(Scholar) ) - bonus_value += 5; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_LEARNING); - } - break; - - case PLAYER_SKILL_UNARMED: - { - if (CheckHiredNPCSpeciality(Monk) ) - bonus_value = 2; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_UNARMED); - } - break; - - case PLAYER_SKILL_DODGE: - { - if ( CheckHiredNPCSpeciality(Monk) ) - bonus_value = 2; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_DODGE); - } - break; - - case PLAYER_SKILL_BOW: - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_BOW); - break; - case PLAYER_SKILL_SHIELD: - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_SHIELD); - break; - - case PLAYER_SKILL_EARTH: - if ( CheckHiredNPCSpeciality(Apprentice) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Mystic) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Spellmaster) ) - bonus_value += 4; - if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) - bonus_value += 3; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_EARTH); - break; - case PLAYER_SKILL_FIRE: - if ( CheckHiredNPCSpeciality(Apprentice) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Mystic) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Spellmaster) ) - bonus_value += 4; - if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) - bonus_value += 3; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_FIRE); - break; - case PLAYER_SKILL_AIR: - if ( CheckHiredNPCSpeciality(Apprentice) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Mystic) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Spellmaster) ) - bonus_value += 4; - if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) - bonus_value += 3; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_AIR); - break; - case PLAYER_SKILL_WATER: - if ( CheckHiredNPCSpeciality(Apprentice) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Mystic) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Spellmaster) ) - bonus_value += 4; - if ( classType == PLAYER_CLASS_WARLOCK && PartyHasDragon() ) - bonus_value += 3; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_WATER); - break; - case PLAYER_SKILL_SPIRIT: - if ( CheckHiredNPCSpeciality(Acolyte2) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Initiate) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Prelate) ) - bonus_value += 4; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_SPIRIT); - break; - case PLAYER_SKILL_MIND: - if ( CheckHiredNPCSpeciality(Acolyte2) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Initiate) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Prelate) ) - bonus_value += 4; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MIND); - break; - case PLAYER_SKILL_BODY: - if ( CheckHiredNPCSpeciality(Acolyte2) ) - bonus_value = 2; - if ( CheckHiredNPCSpeciality(Initiate) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Prelate) ) - bonus_value += 4; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_BODY); - break; - case PLAYER_SKILL_LIGHT: - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_LIGHT); - break; - case PLAYER_SKILL_DARK: - { - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_DARK); - } - break; - - case PLAYER_SKILL_MERCHANT: - { - if ( CheckHiredNPCSpeciality(Trader) ) - bonus_value = 4; - if ( CheckHiredNPCSpeciality(Merchant) ) - bonus_value += 6; - if ( CheckHiredNPCSpeciality(Gypsy) ) - bonus_value += 3; - if ( CheckHiredNPCSpeciality(Duper) ) - bonus_value += 8; - } - break; - - case PLAYER_SKILL_PERCEPTION: - { - if ( CheckHiredNPCSpeciality(Scout) ) - bonus_value = 6; - if ( CheckHiredNPCSpeciality(Psychic) ) - bonus_value += 5; - } - break; - - case PLAYER_SKILL_ITEM_ID: - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_ITEM_ID); - break; - case PLAYER_SKILL_MEDITATION: - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_MEDITATION); - break; - case PLAYER_SKILL_TRAP_DISARM: - { - if ( CheckHiredNPCSpeciality(Tinker) ) - bonus_value = 4; - if ( CheckHiredNPCSpeciality(Locksmith) ) - bonus_value += 6; - if ( CheckHiredNPCSpeciality(Burglar) ) - bonus_value += 8; - bonus_value += GetItemsBonus(CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM); - } - break; - } - - skill_value = pActiveSkills[uSkillType]; - if ( bonus_value + (skill_value & 0x3F) < 60 ) - result = bonus_value + skill_value; - else - result = skill_value & 0xFFFC | 0x3C; //al - return result; -} - - -//----- (0048FC00) -------------------------------------------------------- -int Player::GetSkillBonus(enum CHARACTER_ATTRIBUTE_TYPE inSkill) //TODO: move the individual implementations to attribute classes once possible -{ - int armsMasterBonus; - - armsMasterBonus = 0; - int armmaster_skill = GetActualSkillLevel(PLAYER_SKILL_ARMSMASTER); - if ( armmaster_skill > 0 ) - { - int multiplier = 0; - if ( inSkill == CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS ) - { - multiplier = GetMultiplierForSkillLevel(armmaster_skill, 0, 0, 1, 2); - } - else if ( inSkill == CHARACTER_ATTRIBUTE_ATTACK ) - { - multiplier = GetMultiplierForSkillLevel(armmaster_skill, 0, 1, 1, 2); - } - armsMasterBonus = multiplier * (armmaster_skill & 0x3F); - } - - switch(inSkill) - { - case CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS: - if (HasItemEquipped(EQUIP_BOW)) - { - int bowSkillLevel = GetActualSkillLevel(PLAYER_SKILL_DODGE); - int multiplier = GetMultiplierForSkillLevel(bowSkillLevel, 0, 0, 0, 1); - return multiplier * (bowSkillLevel & 0x3F); - } - return 0; - break; - case CHARACTER_ATTRIBUTE_HEALTH: - { - int base_value = pBaseHealthPerLevelByClass[classType]; - int attrib_modif = GetBodybuilding(); - return base_value * attrib_modif; - } - break; - case CHARACTER_ATTRIBUTE_MANA: - { - int base_value = pBaseManaPerLevelByClass[classType]; - int attrib_modif = GetMeditation(); - return base_value * attrib_modif; - } - break; - case CHARACTER_ATTRIBUTE_AC_BONUS: - { - bool wearingArmor = false; - bool wearingLeather = false; - unsigned int ACSum = 0; - - for (int j = 0; j < 16; ++j) - { - ItemGen* currItem = GetNthEquippedIndexItem(j); - if (currItem != nullptr && (!currItem->IsBroken())) - { - PLAYER_SKILL_TYPE itemSkillType = (PLAYER_SKILL_TYPE)currItem->GetPlayerSkillType(); - int currArmorSkillLevel = 0; - int multiplier = 0; - switch (itemSkillType) - { - case PLAYER_SKILL_STAFF: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 0, 1, 1, 1); - break; - case PLAYER_SKILL_SWORD: - case PLAYER_SKILL_SPEAR: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 0, 0, 0, 1); - break; - case PLAYER_SKILL_SHIELD: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - wearingArmor = true; - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 2, 2); - break; - case PLAYER_SKILL_LEATHER: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - wearingLeather = true; - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 2, 2); - break; - case PLAYER_SKILL_CHAIN: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - wearingArmor = true; - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 1, 1); - break; - case PLAYER_SKILL_PLATE: - currArmorSkillLevel = GetActualSkillLevel(itemSkillType); - wearingArmor = true; - multiplier = GetMultiplierForSkillLevel(currArmorSkillLevel, 1, 1, 1, 1); - break; - } - ACSum += multiplier * (currArmorSkillLevel & 0x3F); - } - } - - int dodgeSkillLevel = GetActualSkillLevel(PLAYER_SKILL_DODGE); - int dodgeMastery = SkillToMastery(dodgeSkillLevel); - int multiplier = GetMultiplierForSkillLevel(dodgeSkillLevel, 1, 2, 3, 3); - if ( !wearingArmor && (!wearingLeather || dodgeMastery == 4) ) - { - ACSum += multiplier * (dodgeSkillLevel & 0x3F); - } - return ACSum; - } - break; - case CHARACTER_ATTRIBUTE_ATTACK: - if ( this->IsUnarmed() ) - { - int unarmedSkill = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); - if (!unarmedSkill) - { - return 0; - } - int multiplier = GetMultiplierForSkillLevel(unarmedSkill, 0, 1, 2, 2); - return armsMasterBonus + multiplier * (unarmedSkill & 0x3F); - } - for (int i = 0; i < 16; ++i) - { - if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - ItemGen* currItem = GetNthEquippedIndexItem(i); - if ( currItem->GetItemEquipType() <= EQUIP_TWO_HANDED) - { - PLAYER_SKILL_TYPE currItemSkillType = (PLAYER_SKILL_TYPE)currItem->GetPlayerSkillType(); - int currentItemSkillLevel = this->GetActualSkillLevel(currItemSkillType); - if (currItemSkillType == PLAYER_SKILL_BLASTER) - { - int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 2, 3, 5); - return multiplier * (currentItemSkillLevel & 0x3F); - } - else if (currItemSkillType == PLAYER_SKILL_STAFF && this->GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) - { - int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); - int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 1, 2, 2); - return multiplier * (unarmedSkillLevel & 0x3F) + armsMasterBonus + (currentItemSkillLevel & 0x3F); - } - else - { - return armsMasterBonus + (currentItemSkillLevel & 0x3F); - } - } - } - } - return 0; - break; - - case CHARACTER_ATTRIBUTE_RANGED_ATTACK: - for (int i = 0; i < 16; i++) - { - if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - ItemGen* currItemPtr = GetNthEquippedIndexItem(i); - if ( currItemPtr->GetItemEquipType() == EQUIP_TWO_HANDED || currItemPtr->GetItemEquipType() == EQUIP_SINGLE_HANDED ) - { - PLAYER_SKILL_TYPE currentItemSkillType = (PLAYER_SKILL_TYPE)GetNthEquippedIndexItem(i)->GetPlayerSkillType(); - int currentItemSkillLevel = this->GetActualSkillLevel(currentItemSkillType); - if ( currentItemSkillType == PLAYER_SKILL_BOW ) - { - int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 1, 1, 1); - return multiplier * (currentItemSkillLevel & 0x3F); - } - else if ( currentItemSkillType == PLAYER_SKILL_BLASTER ) - { - int multiplier = GetMultiplierForSkillLevel(currentItemSkillLevel, 1, 2, 3, 5); - return multiplier * (currentItemSkillLevel & 0x3F); - } - } - } - } - return 0; - break; - - case CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS: - if ( this->IsUnarmed() ) - { - int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); - if ( !unarmedSkillLevel ) - { - return 0; - } - int multiplier = GetMultiplierForSkillLevel(unarmedSkillLevel, 0, 1, 2, 2); - return multiplier * (unarmedSkillLevel & 0x3F); - } - for (int i = 0; i < 16; i++) - { - if ( this->HasItemEquipped((ITEM_EQUIP_TYPE)i) ) - { - ItemGen* currItemPtr = GetNthEquippedIndexItem(i); - if ( currItemPtr->GetItemEquipType() == EQUIP_TWO_HANDED || currItemPtr->GetItemEquipType() == EQUIP_SINGLE_HANDED ) - { - PLAYER_SKILL_TYPE currItemSkillType = (PLAYER_SKILL_TYPE)currItemPtr->GetPlayerSkillType(); - int currItemSkillLevel = this->GetActualSkillLevel(currItemSkillType); - int baseSkillBonus; - int multiplier; - switch (currItemSkillType) - { - case PLAYER_SKILL_STAFF: - if ( SkillToMastery(currItemSkillLevel) >= 4 && this->GetActualSkillLevel(PLAYER_SKILL_UNARMED) > 0) - { - int unarmedSkillLevel = this->GetActualSkillLevel(PLAYER_SKILL_UNARMED); - int multiplier = GetMultiplierForSkillLevel(unarmedSkillLevel, 0, 1, 2, 2); - return multiplier * (unarmedSkillLevel & 0x3F); - } - else - { - return armsMasterBonus; - } - break; - - case PLAYER_SKILL_DAGGER: - multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 0, 1); - baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); - return armsMasterBonus + baseSkillBonus; - break; - case PLAYER_SKILL_SWORD: - multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 0, 0); - baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); - return armsMasterBonus + baseSkillBonus; - break; - case PLAYER_SKILL_MACE: - case PLAYER_SKILL_SPEAR: - multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 1, 1, 1); - baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); - return armsMasterBonus + baseSkillBonus; - break; - case PLAYER_SKILL_AXE: - multiplier = GetMultiplierForSkillLevel(currItemSkillLevel, 0, 0, 1, 1); - baseSkillBonus = multiplier * (currItemSkillLevel & 0x3F); - return armsMasterBonus + baseSkillBonus; - break; - } - } - } - } - return 0; - break; - default: - return 0; - } -} - -unsigned int Player::GetMultiplierForSkillLevel(unsigned int skillValue, int mult1, int mult2, int mult3, int mult4) -{ - int masteryLvl = SkillToMastery(skillValue); - switch (masteryLvl) - { - case 1: return mult1; - case 2: return mult2; - case 3: return mult3; - case 4: return mult4; - } - Error("(%u)", masteryLvl); - return 0; -} -//----- (00490109) -------------------------------------------------------- -// faces are: 0 1 2 3 human males -// 4 5 6 7 human females -// 8 9 elf males -// 10 11 elf females -// 12 13 dwarf males -// 14 15 dwarf females -// 16 17 goblin males -// 18 19 goblin females -// 20 lich male -// 21 lich female -// 22 underwater suits (unused) -// 23 zombie male -// 24 zombie female -enum CHARACTER_RACE Player::GetRace() -{ - if ( uCurrentFace <= 7 ) - { - return CHARACTER_RACE_HUMAN; - } - else if ( uCurrentFace <= 11 ) - { - return CHARACTER_RACE_ELF; - } - else if ( uCurrentFace <= 15 ) - { - return CHARACTER_RACE_DWARF; - } - else if ( uCurrentFace <= 19 ) - { - return CHARACTER_RACE_GOBLIN; - } - else - { - return CHARACTER_RACE_HUMAN; - } -} - -//----- (00490141) -------------------------------------------------------- -PLAYER_SEX Player::GetSexByVoice() -{ - switch ( this->uVoiceID ) - { - case 0u: - case 1u: - case 2u: - case 3u: - case 8u: - case 9u: - case 0xCu: - case 0xDu: - case 0x10u: - case 0x11u: - case 0x14u: - case 0x17u: - return SEX_MALE; - - case 4u: - case 5u: - case 6u: - case 7u: - case 0xAu: - case 0xBu: - case 0xEu: - case 0xFu: - case 0x12u: - case 0x13u: - case 0x15u: - case 0x18u: - return SEX_FEMALE; - } - Error("(%u)", this->uVoiceID); - return SEX_MALE; -} - -//----- (00490188) -------------------------------------------------------- -void Player::SetInitialStats() -{ - CHARACTER_RACE v1 = GetRace(); - uMight = StatTable[v1][0].uBaseValue; - uIntelligence = StatTable[v1][1].uBaseValue; - uWillpower = StatTable[v1][2].uBaseValue; - uEndurance = StatTable[v1][3].uBaseValue; - uAccuracy = StatTable[v1][4].uBaseValue; - uSpeed = StatTable[v1][5].uBaseValue; - uLuck = StatTable[v1][6].uBaseValue; -} - -//----- (004901FC) -------------------------------------------------------- -void Player::SetSexByVoice() -{ - switch ( this->uVoiceID) - { - case 0: - case 1: - case 2: - case 3: - case 8: - case 9: - case 0xC: - case 0xD: - case 0x10: - case 0x11: - case 0x14: - case 0x17: - this->uSex = SEX_MALE; - break; - case 4: - case 5: - case 6: - case 7: - case 0xA: - case 0xB: - case 0xE: - case 0xF: - case 0x12: - case 0x13: - case 0x15: - case 0x18: - this->uSex = SEX_FEMALE; - break; - default: - Error("(%u)", this->uVoiceID); - break; - } - -} - -//----- (0049024A) -------------------------------------------------------- -void Player::Reset(PLAYER_CLASS_TYPE cls) -{ - sLevelModifier = 0; - sAgeModifier = 0; - - classType = cls; - uLuckBonus = 0; - uSpeedBonus = 0; - uAccuracyBonus = 0; - uEnduranceBonus = 0; - uWillpowerBonus = 0; - uIntelligenceBonus = 0; - uMightBonus = 0; - uLevel = 1; - uExperience = 251 + rand() % 100; - uBirthYear = 1147 - rand() % 6; - pActiveSkills.fill(0); - memset(_achieved_awards_bits, 0, sizeof(_achieved_awards_bits)); - memset(&spellbook, 0, sizeof(spellbook)); - - for (uint i = 0; i < 37; ++i) - { - if (pSkillAvailabilityPerClass[classType / 4][i] != 2) - continue; - - pActiveSkills[i] = 1; - - switch (i) - { - case PLAYER_SKILL_FIRE: - spellbook.pFireSpellbook.bIsSpellAvailable[0] = true;//its temporary, for test spells - - extern bool all_magic; - if ( all_magic == true ) - { - pActiveSkills[PLAYER_SKILL_AIR] = 1; - pActiveSkills[PLAYER_SKILL_WATER] = 1; - pActiveSkills[PLAYER_SKILL_EARTH] = 1; - spellbook.pFireSpellbook.bIsSpellAvailable[1] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[2] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[3] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[4] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[5] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[6] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[7] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[8] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[9] = true; - spellbook.pFireSpellbook.bIsSpellAvailable[10] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[0] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[1] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[2] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[3] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[4] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[5] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[6] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[7] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[8] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[9] = true; - spellbook.pAirSpellbook.bIsSpellAvailable[10] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[1] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[2] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[3] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[4] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[5] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[6] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[7] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[8] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[9] = true; - spellbook.pWaterSpellbook.bIsSpellAvailable[10] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[1] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[2] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[3] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[4] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[5] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[6] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[7] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[8] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[9] = true; - spellbook.pEarthSpellbook.bIsSpellAvailable[10] = true; - } - break; - case PLAYER_SKILL_AIR: - spellbook.pAirSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_WATER: - spellbook.pWaterSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_EARTH: - spellbook.pEarthSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_SPIRIT: - spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_MIND: - spellbook.pMindSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_BODY: - spellbook.pBodySpellbook.bIsSpellAvailable[0] = true; - - if ( all_magic == true ) - { - pActiveSkills[PLAYER_SKILL_MIND] = 1; - pActiveSkills[PLAYER_SKILL_SPIRIT] = 1; - spellbook.pBodySpellbook.bIsSpellAvailable[1] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[2] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[3] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[4] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[5] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[6] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[7] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[8] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[9] = true; - spellbook.pBodySpellbook.bIsSpellAvailable[10] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[0] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[1] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[2] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[3] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[4] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[5] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[6] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[7] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[8] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[9] = true; - spellbook.pMindSpellbook.bIsSpellAvailable[10] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[0] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[1] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[2] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[3] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[4] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[5] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[6] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[7] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[8] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[9] = true; - spellbook.pSpiritSpellbook.bIsSpellAvailable[10] = true; - } - break; - case PLAYER_SKILL_LIGHT: - spellbook.pLightSpellbook.bIsSpellAvailable[0] = true; - break; - case PLAYER_SKILL_DARK: - spellbook.pDarkSpellbook.bIsSpellAvailable[0] = true; - break; - } - } - - memset(&pEquipment, 0, sizeof(PlayerEquipment)); - pInventoryMatrix.fill(0); - for (uint i = 0; i < 126; ++i) - pInventoryItemList[i].Reset(); - for (uint i = 0; i < 12; ++i) - pEquippedItems[i].Reset(); - - sHealth = GetMaxHealth(); - sMana = GetMaxMana(); -} - -//----- (004903C9) -------------------------------------------------------- -PLAYER_SKILL_TYPE Player::GetSkillIdxByOrder(signed int order) -{ - int counter; // edx@5 - bool canBeInactive; - unsigned char requiredValue; - signed int offset; - - if ( order <= 1 ) - { - canBeInactive = false; - requiredValue = 2; // 2 - primary skill - offset = 0; - } - else if ( order <= 3 ) - { - canBeInactive = false; - requiredValue = 1; // 1 - available - offset = 2; - } - else if ( order <= 12 ) - { - canBeInactive = true; - requiredValue = 1; // 1 - available - offset = 4; - } - else - { - return (PLAYER_SKILL_TYPE)37; - } - counter = 0; - for (int i = 0; i < 37; i++) - { - if ( (this->pActiveSkills[i] || canBeInactive) && pSkillAvailabilityPerClass[classType / 4][i] == requiredValue ) - { - if ( counter == order - offset ) - return (PLAYER_SKILL_TYPE)i; - ++counter; - } - } - - return (PLAYER_SKILL_TYPE)37; -} - - - -//----- (0049048D) -------------------------------------------------------- -//unsigned __int16 PartyCreation_BtnMinusClick(Player *_this, int eAttribute) -void Player::DecreaseAttribute(int eAttribute) -{ - int pBaseValue; // ecx@1 - int pDroppedStep; // ebx@1 - int pStep; // esi@1 - int uMinValue; // [sp+Ch] [bp-4h]@1 - - int raceId = GetRace(); - pBaseValue = StatTable[raceId][eAttribute].uBaseValue; - pDroppedStep = StatTable[raceId][eAttribute].uDroppedStep; - uMinValue = pBaseValue - 2; - pStep = StatTable[raceId][eAttribute].uBaseStep; - unsigned short* AttrToChange = nullptr; - switch ( eAttribute ) - { - case CHARACTER_ATTRIBUTE_STRENGTH: - AttrToChange = &this->uMight; - break; - case CHARACTER_ATTRIBUTE_INTELLIGENCE: - AttrToChange = &this->uIntelligence; - break; - case CHARACTER_ATTRIBUTE_WILLPOWER: - AttrToChange = &this->uWillpower; - break; - case CHARACTER_ATTRIBUTE_ENDURANCE: - AttrToChange = &this->uEndurance; - break; - case CHARACTER_ATTRIBUTE_ACCURACY: - AttrToChange = &this->uAccuracy; - break; - case CHARACTER_ATTRIBUTE_SPEED: - AttrToChange = &this->uSpeed; - break; - case CHARACTER_ATTRIBUTE_LUCK: - AttrToChange = &this->uLuck; - break; - } - if ( *AttrToChange <= pBaseValue ) - pStep = pDroppedStep; - if ( *AttrToChange - pStep >= uMinValue ) - *AttrToChange -= pStep; -} - -//----- (004905F5) -------------------------------------------------------- -//signed int PartyCreation_BtnPlusClick(Player *this, int eAttribute) -void Player::IncreaseAttribute( int eAttribute ) -{ - int raceId; // eax@1 - int maxValue; // ebx@1 - signed int baseStep; // edi@1 - signed int tmp; // eax@17 - signed int result; // eax@18 - int baseValue; // [sp+Ch] [bp-8h]@1 - signed int droppedStep; // [sp+10h] [bp-4h]@1 - unsigned short* statToChange; - - raceId = GetRace(); - maxValue = StatTable[raceId][eAttribute].uMaxValue; - baseStep = StatTable[raceId][eAttribute].uBaseStep; - baseValue = StatTable[raceId][eAttribute].uBaseValue; - droppedStep = StatTable[raceId][eAttribute].uDroppedStep; - PlayerCreation_GetUnspentAttributePointCount(); - switch ( eAttribute ) - { - case 0: - statToChange = &this->uMight; - break; - case 1: - statToChange = &this->uIntelligence; - break; - case 2: - statToChange = &this->uWillpower; - break; - case 3: - statToChange = &this->uEndurance; - break; - case 4: - statToChange = &this->uAccuracy; - break; - case 5: - statToChange = &this->uSpeed; - break; - case 6: - statToChange = &this->uLuck; - break; - default: - Error("(%u)", eAttribute); - break; - } - if ( *statToChange < baseValue ) - { - tmp = baseStep; - baseStep = droppedStep; - droppedStep = tmp; - } - result = PlayerCreation_GetUnspentAttributePointCount(); - if ( result >= droppedStep ) - { - if ( baseStep + *statToChange <= maxValue ) - *statToChange += baseStep; - } -} - -//----- (0049070F) -------------------------------------------------------- -void Player::Zero() -{ - this->sLevelModifier = 0; - this->sACModifier = 0; - this->uLuckBonus = 0; - this->uAccuracyBonus = 0; - this->uSpeedBonus = 0; - this->uEnduranceBonus = 0; - this->uWillpowerBonus = 0; - this->uIntelligenceBonus = 0; - this->uMightBonus = 0; - this->field_100 = 0; - this->field_FC = 0; - this->field_F8 = 0; - this->field_F4 = 0; - this->field_F0 = 0; - this->field_EC = 0; - this->field_E8 = 0; - this->field_E4 = 0; - this->field_E0 = 0; - memset(&this->sResFireBonus, 0, 0x16u); - this->field_1A97 = 0; - this->_ranged_dmg_bonus = 0; - this->field_1A95 = 0; - this->_ranged_atk_bonus = 0; - this->field_1A93 = 0; - this->_melee_dmg_bonus = 0; - this->field_1A91 = 0; - this->_some_attack_bonus = 0; - this->_mana_related = 0; - this->uFullManaBonus = 0; - this->_health_related = 0; - this->uFullHealthBonus = 0; -} - -//----- (004907E7) -------------------------------------------------------- -unsigned int Player::GetStatColor(int uStat) -{ - int attribute_value; // edx@1 - - int base_attribute_value = StatTable[GetRace()][uStat].uBaseValue; - switch (uStat) - { - case 0: attribute_value = uMight; break; - case 1: attribute_value = uIntelligence; break; - case 2: attribute_value = uWillpower; break; - case 3: attribute_value = uEndurance; break; - case 4: attribute_value = uAccuracy; break; - case 5: attribute_value = uSpeed; break; - case 6: attribute_value = uLuck; break; - default: Error("Unexpected attribute"); - }; - - if (attribute_value == base_attribute_value) - return ui_character_stat_default_color; - else if (attribute_value > base_attribute_value) - return ui_character_stat_buffed_color; - else - return ui_character_stat_debuffed_color; -} - -//----- (004908A8) -------------------------------------------------------- -bool Player::DiscardConditionIfLastsLongerThan(unsigned int uCondition, signed __int64 uTime) -{ - if ( pConditions[uCondition] && (uTime < (signed long long)pConditions[uCondition]) ) - { - pConditions[uCondition] = 0i64; - return true; - } - else - return false; -} - -//----- (004680ED) -------------------------------------------------------- -void Player::UseItem_DrinkPotion_etc(signed int player_num, int a3) -{ - Player *playerAffected; // esi@1 - signed int v5; // eax@17 - int v8; // edx@39 - const char *v13; // eax@45 - signed int v15; // edi@68 - int v16; // edx@73 - unsigned __int16 v17; // edi@73 - unsigned int v18; // eax@73 - const char *v22; // eax@84 - int scroll_id; // esi@96 - int v25; // eax@109 - int v26; // eax@113 - int new_mana_val; // edi@114 - signed __int64 v28; // qax@120 - __int64 v30; // edi@137 - __int64 v32; // ST3C_4@137 - __int64 v34; // ST34_4@137 - unsigned __int16 v50; // [sp-Ch] [bp-38h]@120 - const char *v66; // [sp-4h] [bp-30h]@69 - signed int v67; // [sp-4h] [bp-30h]@77 - const char *v68; // [sp-4h] [bp-30h]@89 - char v72; // [sp+20h] [bp-Ch]@68 - signed int v73; // [sp+24h] [bp-8h]@1 - const char* v74; // [sp+24h] [bp-8h]@23 - //Player *thisb; // [sp+28h] [bp-4h]@1 - unsigned int thisa; // [sp+28h] [bp-4h]@22 - - //thisb = this; - playerAffected = &pParty->pPlayers[player_num-1]; - v73 = 1; - if ( pParty->bTurnBasedModeOn == true && (pTurnEngine->turn_stage == TE_WAIT || pTurnEngine->turn_stage == TE_MOVEMENT) ) - return; - if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_REAGENT ) - { - if ( pParty->pPickedItem.uItemID == 160 ) - { - playerAffected->SetCondition(Condition_Poison_Weak, 1); - } - else if ( pParty->pPickedItem.uItemID == 161 ) - { - new_mana_val = playerAffected->sMana; - new_mana_val += 2; - if ( new_mana_val > playerAffected->GetMaxMana() ) - new_mana_val = playerAffected->GetMaxMana(); - playerAffected->PlaySound(SPEECH_36, 0); - } - else if ( pParty->pPickedItem.uItemID == 162 ) - { - playerAffected->Heal(2); - playerAffected->PlaySound(SPEECH_36, 0); - } - else - { - v68 = pParty->pPickedItem.GetDisplayName(); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36], v68);//"%s can not be used that way" - ShowStatusBarString(pTmpBuf.data(), 2); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - pAudioPlayer->PlaySound((SoundID)211, 0, 0, -1, 0, 0, 0, 0); - - if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) - { - pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); - } - if ( v73 ) - { - if ( pParty->bTurnBasedModeOn ) - { - pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; - this->SetRecoveryTime(100); - pTurnEngine->ApplyPlayerAction(); - } - else - { - this->SetRecoveryTime((int)(flt_6BE3A4_debug_recmod1 * 213.3333333333333)); - } - } - pMouse->RemoveHoldingItem(); - return; - } - - if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_POTION ) - { - switch ( pParty->pPickedItem.uItemID ) - { - case 221: //Catalyst - playerAffected->SetCondition(Condition_Poison_Weak, 1); - break; - case 222: //Cure Wounds - v25 = pParty->pPickedItem.uEnchantmentType + 10; - playerAffected->Heal(v25); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 223: //Magic Potion - v26 = pParty->pPickedItem.uEnchantmentType + 10; - new_mana_val = playerAffected->sMana; - new_mana_val += v26; - if ( new_mana_val > playerAffected->GetMaxMana() ) - new_mana_val = playerAffected->GetMaxMana(); - playerAffected->PlaySound(SPEECH_36, 0); - playerAffected->sMana = new_mana_val; - break; - case 224: //Cure Weakness - playerAffected->pConditions[Condition_Weak] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 225: //Cure Disease - playerAffected->pConditions[Condition_Disease_Severe] = 0i64; - playerAffected->pConditions[Condition_Disease_Medium] = 0i64; - playerAffected->pConditions[Condition_Disease_Weak] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 226: //Cure Poison - playerAffected->pConditions[Condition_Poison_Severe] = 0i64; - playerAffected->pConditions[Condition_Poison_Medium] = 0i64; - playerAffected->pConditions[Condition_Poison_Weak] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 227: //Awaken - playerAffected->pConditions[Condition_Sleep] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 228: //Haste - if ( !playerAffected->pConditions[Condition_Weak] ) - { - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_HASTE].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - } - break; - case 229: //Heroism - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_HEROISM].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 230: //Bless - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_BLESS].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 231: //Preservation - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_PRESERVATION].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 232: //Shield - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_SHIELD].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 234: //Stoneskin - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_STONESKIN].Apply(pParty->uTimePlayed + v28, 3, 5, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 235: //Water Breathing - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335), - playerAffected->pPlayerBuffs[PLAYER_BUFF_WATER_WALK].Apply(pParty->uTimePlayed +v28, 3, 5, 0, 0); - break; - case 237: //Remove Fear - playerAffected->pConditions[Condition_Fear] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 238: //Remove Curse - playerAffected->pConditions[Condition_Cursed] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 239: //Cure Insanity - playerAffected->pConditions[Condition_Insane] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 240: //Might Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_STRENGTH].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 241: //Intellect Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_INTELLIGENCE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 242: //Personality Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_WILLPOWER].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 243://Endurance Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_ENDURANCE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 244: //Speed Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_SPEED].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 245: //Accuracy Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_ACCURACY].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 251: //Cure Paralysis - playerAffected->pConditions[Condition_Paralyzed] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 252://Divine Restoration - v30 = playerAffected->pConditions[Condition_Dead]; - v32 = playerAffected->pConditions[Condition_Pertified]; - v34 = playerAffected->pConditions[Condition_Eradicated]; - pConditions.fill(0); - playerAffected->pConditions[Condition_Dead] = v30; - playerAffected->pConditions[Condition_Pertified] = v32; - playerAffected->pConditions[Condition_Eradicated] = v34; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 253: //Divine Cure - v25 = 5 * pParty->pPickedItem.uEnchantmentType; - playerAffected->Heal(v25); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 254: //Divine Power - v26 = 5 * pParty->pPickedItem.uEnchantmentType; - new_mana_val = playerAffected->sMana; - new_mana_val += v26; - if ( new_mana_val > playerAffected->GetMaxMana() ) - new_mana_val = playerAffected->GetMaxMana(); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 255: //Luck Boost - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_LUCK].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 256: //Fire Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_FIRE].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 257: //Air Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_AIR].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 258: //Water Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_WATER].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 259: //Earth Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_EARTH].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 260: //Mind Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_MIND].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 261: //Body Resistance - v50 = 3 * pParty->pPickedItem.uEnchantmentType; - v28 = (signed __int64)((double)(230400 * pParty->pPickedItem.uEnchantmentType) * 0.033333335); - playerAffected->pPlayerBuffs[PLAYER_BUFF_RESIST_BODY].Apply(pParty->uTimePlayed + v28, 0, v50, 0, 0); - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 262: //Stone to Flesh - playerAffected->pConditions[Condition_Pertified] = 0i64; - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 264: //Pure Luck - if ( !playerAffected->pure_luck_used ) - { - playerAffected->uLuck += 50; - playerAffected->pure_luck_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 265: //Pure Speed - if ( !playerAffected->pure_speed_used ) - { - playerAffected->uSpeed += 50; - playerAffected->pure_speed_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 266: //Pure Intellect - if ( !playerAffected->pure_intellect_used ) - { - playerAffected->uIntelligence += 50; - playerAffected->pure_intellect_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 267: //Pure Endurance - if ( !playerAffected->pure_endurance_used ) - { - playerAffected->uEndurance += 50; - playerAffected->pure_endurance_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 268: //Pure Personality - if ( !playerAffected->pure_willpower_used ) - { - playerAffected->uWillpower += 50; - playerAffected->pure_willpower_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 269: //Pure Accuracy - if ( !playerAffected->pure_accuracy_used ) - { - playerAffected->uAccuracy += 50; - playerAffected->pure_accuracy_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 270: //Pure Might - if ( !playerAffected->pure_might_used ) - { - playerAffected->uMight += 50; - playerAffected->pure_might_used = 1; - } - playerAffected->PlaySound(SPEECH_36, 0); - break; - case 271: //Rejuvenation - playerAffected->sAgeModifier = 0; - playerAffected->PlaySound(SPEECH_36, 0); - break; - - default: - v68 = pParty->pPickedItem.GetDisplayName(); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36], v68);//"%s can not be used that way" - ShowStatusBarString(pTmpBuf.data(), 2u); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - pAudioPlayer->PlaySound((SoundID)210, 0, 0, -1, 0, 0, 0, 0); - if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) - { -// if ( !v73 ) v73 is always 1 at this point -// { -// pMouse->RemoveHoldingItem(); -// return; -// } - pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); - } - if ( v73 ) - { - if ( pParty->bTurnBasedModeOn ) - { - pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; - this->SetRecoveryTime(100); - pTurnEngine->ApplyPlayerAction(); - } - else - { - this->SetRecoveryTime((int)(flt_6BE3A4_debug_recmod1 * 213.3333333333333)); - } - } - pMouse->RemoveHoldingItem(); - return; - } - - - if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_SPELL_SCROLL ) - { - if ( pCurrentScreen == SCREEN_CASTING ) - return; - if ( !playerAffected->CanAct() ) - { - - v68 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v68); - ShowStatusBarString(pTmpBuf.data(), 2u); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - if ( bUnderwater == 1 ) - { - ShowStatusBarString(pGlobalTXT_LocalizationStrings[652], 2u);//"You can not do that while you are underwater!" - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - - scroll_id = pParty->pPickedItem.uItemID - 299; - if ( scroll_id == 30 || scroll_id == 4 || scroll_id == 91 || scroll_id == 28 ) //Enchant Item scroll, Vampiric Weapon scroll ,Recharge Item ,Fire Aura - { - pMouse->RemoveHoldingItem(); - pGUIWindow_CurrentMenu->Release(); - pIcons_LOD->RemoveTexturesPackFromTextureList(); - pCurrentScreen = SCREEN_GAME; - viewparams->bRedrawGameUI = 1; - _42777D_CastSpell_UseWand_ShootArrow(scroll_id, player_num - 1, 0x85u, 1, 0); - } - else - { - pMouse->RemoveHoldingItem(); - pMessageQueue_50C9E8->AddGUIMessage(UIMSG_SpellScrollUse, scroll_id, player_num - 1); - if ( pCurrentScreen && pGUIWindow_CurrentMenu - && (pGUIWindow_CurrentMenu->eWindowType != WINDOW_null)) - { - pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); - } - } - return; - } - - if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_BOOK ) - { - v15 = pParty->pPickedItem.uItemID - 400; - v72 = playerAffected->spellbook.bHaveSpell[pParty->pPickedItem.uItemID-400];//(char *)&v3->pConditions[0] + pParty->pPickedItem.uItemID + 2; - if ( v72 ) - { - v66 = pParty->pPickedItem.GetDisplayName(); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[380], v66);//"You already know the %s spell" - ShowStatusBarString(pTmpBuf.data(), 2u); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - if ( !playerAffected->CanAct() ) - { - v66 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v66);//"That player is %s" - ShowStatusBarString(pTmpBuf.data(), 2); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - v16 = v15 % 11 + 1; - v17 = playerAffected->pActiveSkills[v15 / 11 + 12]; - v18 = SkillToMastery(v17) - 1; - switch (v18) - { - case 0: v67 = 4; break; - case 1: v67 = 7; break; - case 2: v67 = 10; break; - case 3: v67 = 11; break; - default: - v67 = player_num; - } - - if ( v16 > v67 || !v17 ) - { - v22 = pParty->pPickedItem.GetDisplayName(); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[381], v22); //"You don't have the skill to learn %s" - ShowStatusBarString(pTmpBuf.data(), 2); - playerAffected->PlaySound((PlayerSpeech)20, 0); - return; - } - playerAffected->spellbook.bHaveSpell[pParty->pPickedItem.uItemID-400] = 1; - playerAffected->PlaySound(SPEECH_21, 0); - v73 = 0; - - - if ( pGUIWindow_CurrentMenu && pGUIWindow_CurrentMenu->eWindowType != WINDOW_null) - { - if ( !v73 ) - { - pMouse->RemoveHoldingItem(); - return; - } - pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); - } -// if ( v73 ) v73 is always 0 at this point -// { -// if ( pParty->bTurnBasedModeOn ) -// { -// pParty->pTurnBasedPlayerRecoveryTimes[player_num-1] = 100; -// thisb->SetRecoveryTime(100); -// pTurnEngine->ApplyPlayerAction(); -// } -// else -// { -// thisb->SetRecoveryTime(flt_6BE3A4_debug_recmod1 * 213.3333333333333); -// } -// } - pMouse->RemoveHoldingItem(); - return; - } - - if ( pParty->pPickedItem.GetItemEquipType() == EQUIP_MESSAGE_SCROLL ) - { - if ( playerAffected->CanAct() ) - { - CreateMsgScrollWindow(pParty->pPickedItem.uItemID); - playerAffected->PlaySound(SPEECH_37, 0); - return; - } - v68 = aCharacterConditionNames[playerAffected->GetMajorConditionIdx()]; - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[382], v68);//That player is %s - ShowStatusBarString(pTmpBuf.data(), 2); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - else - { - if (pParty->pPickedItem.uItemID == 616) //Genie Lamp - { - thisa = pParty->uCurrentMonthWeek + 1; - if ( pParty->uCurrentMonth >= 7 ) - v74 = nullptr; - else - v74 = aAttributeNames[pParty->uCurrentMonth]; - switch ( pParty->uCurrentMonth ) - { - case 0: - playerAffected->uMight += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 1: - playerAffected->uIntelligence += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 2: - playerAffected->uWillpower += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 3: - playerAffected->uEndurance += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 4: - playerAffected->uAccuracy += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 5: - playerAffected->uSpeed += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 6: - playerAffected->uLuck += thisa; - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v74, pGlobalTXT_LocalizationStrings[121]);//"Permanent" - break; - case 7: - pParty->PartyFindsGold(1000 * thisa, 0); - sprintf(pTmpBuf.data(), "+%u %s", 1000 * thisa, pGlobalTXT_LocalizationStrings[97]);//"Gold" - break; - case 8: - Party::GiveFood(5 * thisa); - sprintf(pTmpBuf.data(), "+%u %s",5 * thisa , pGlobalTXT_LocalizationStrings[653]);//"Food" - break; - case 9u: - playerAffected->uSkillPoints += 2 * thisa; - sprintf(pTmpBuf.data(), "+%u %s", 2 * thisa, pGlobalTXT_LocalizationStrings[LOCSTR_SKILL_POINTS]); - break; - case 10: - playerAffected->uExperience += 2500 * thisa; - sprintf(pTmpBuf.data(), "+%u %s", 2500 * thisa, pGlobalTXT_LocalizationStrings[LOCSTR_EXPIRIENCE]); - break; - case 11: - v8 = rand() % 6; - switch (v8) - { - case 0: - playerAffected->sResFireBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[87];//Fire - break; - case 1: - playerAffected->sResAirBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[6];//Air - break; - case 2: - playerAffected->sResWaterBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[240];//Water - break; - case 3: - playerAffected->sResEarthBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[70];//Earth - break; - case 4: - playerAffected->sResMindBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[142];//Mind - break; - case 5: - playerAffected->sResBodyBase += thisa; - v13 = pGlobalTXT_LocalizationStrings[29];//Body - break; - default: ("Unexpected attribute"); - return; - } - sprintf(pTmpBuf.data(), "+%u %s %s", thisa, v13, pGlobalTXT_LocalizationStrings[121]);//Permanent - break; - - } - ShowStatusBarString(pTmpBuf.data(), 2u); - pMouse->RemoveHoldingItem(); - pGame->pStru6Instance->SetPlayerBuffAnim(SPELL_QUEST_COMPLETED, player_num - 1); - playerAffected->PlaySound(SPEECH_93, 0); - pAudioPlayer->PlaySound((SoundID)219, 0, 0, -1, 0, 0, 0, 0); - if ( pParty->uDaysPlayed == 6 || pParty->uDaysPlayed == 20 ) - { - playerAffected->SetCondition(Condition_Eradicated, 0); - pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); - } - else if ( pParty->uDaysPlayed == 12 || pParty->uDaysPlayed == 26 ) - { - playerAffected->SetCondition(Condition_Dead, 0); - pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); - } - else if ( pParty->uDaysPlayed == 4 || pParty->uDaysPlayed == 25 ) - { - playerAffected->SetCondition(Condition_Pertified, 0); - pAudioPlayer->PlaySound((SoundID)215, 0, 0, -1, 0, 0, 0, 0); - } - return; - } - else if ( pParty->pPickedItem.uItemID == 630 ) //Red Apple - { - Party::GiveFood(1u); - pAudioPlayer->PlaySound(SOUND_EatApple, 0, 0, -1, 0, 0, 0, 0); - } - else if ( pParty->pPickedItem.uItemID == 632 ) //Lute - { - pAudioPlayer->PlaySound(SOUND_PlayLute, 0, 0, -1, 0, 0, 0, 0); - return; - } - else if ( pParty->pPickedItem.uItemID == 633 ) //Faerie Pipes - { - pAudioPlayer->PlaySound(SOUND_PlayFaeriePipes, 0, 0, -1, 0, 0, 0, 0); - return; - } - else if ( pParty->pPickedItem.uItemID == 634 ) //Gryphonheart's Trumpet - { - pAudioPlayer->PlaySound(SOUND_PlayGryphonheartsTrumpet, 0, 0, -1, 0, 0, 0, 0); - return; - } - else if ( pParty->pPickedItem.uItemID == 646 ) //Horseshoe - { - pGame->pStru6Instance->SetPlayerBuffAnim(SPELL_QUEST_COMPLETED, player_num - 1); - v5 = PID(OBJECT_Player, player_num + 49); - pAudioPlayer->PlaySound(SOUND_20001, v5, 0, -1, 0, 0, 0, 0); - playerAffected->AddVariable(VAR_NumSkillPoints, 2); - } - else if ( pParty->pPickedItem.uItemID == 650 ) //Temple in a Bottle - { - TeleportToNWCDungeon(); - return; - } - else - { - v68 = pParty->pPickedItem.GetDisplayName(); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[36],v68);//"%s can not be used that way" - ShowStatusBarString(pTmpBuf.data(), 2u); - pAudioPlayer->PlaySound((SoundID)27, 0, 0, -1, 0, 0, 0, 0); - return; - } - - pMouse->RemoveHoldingItem(); - return; - } -} - -bool CmpSkillValue(int valToCompare, int skillValue) -{ - int v4; - if ( valToCompare <= 63 ) - v4 = skillValue & 0x3F; - else - v4 = skillValue & skillValue; - return v4 >= valToCompare; -} - -//----- (00449BB4) -------------------------------------------------------- -bool Player::CompareVariable( enum VariableType VarNum, signed int pValue ) // in some cases this calls only calls v4 >= pValue, which i've changed to return false, since these values are supposed to be positive and v4 was -1 by default -{ - Assert(pValue >= 0, "Compare variable shouldn't have negative arguments"); - - signed int v4; // edi@1 - unsigned __int8 test_bit_value; // eax@25 - unsigned __int8 byteWithRequestedBit; // cl@25 - DDM_DLV_Header *v19; // eax@122 - DDM_DLV_Header *v21; // eax@126 - int actStat; // ebx@161 - int baseStat; // eax@161 - - - if ( (signed int)VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_74 ) - return (unsigned __int8)stru_5E4C90_MapPersistVars.field_0[VarNum - VAR_MapPersistentVariable_0] > 0; // originally (unsigned __int8)byte_5E4C15[VarNum]; - if ( (signed int)VarNum >= VAR_MapPersistentVariable_75 && VarNum <= VAR_MapPersistentVariable_99 ) - return (unsigned __int8)stru_5E4C90_MapPersistVars._decor_events[VarNum - VAR_MapPersistentVariable_75] > 0; //not really sure whether the number gets up to 99, but can't ignore the possibility - - switch ( VarNum ) - { - case VAR_Sex: - return ( pValue == this->uSex ); - case VAR_Class: - return ( pValue == this->classType ); - case VAR_Race: - return pValue == GetRace(); - case VAR_CurrentHP: - return this->sHealth >= pValue; - case VAR_MaxHP: - return (this->sHealth >= GetMaxHealth()); - case VAR_CurrentSP: - return this->sMana >= pValue; - case VAR_MaxSP: - return (this->sMana >= GetMaxMana()); - case VAR_ActualAC: - return GetActualAC() >= pValue; - case VAR_ACModifier: - return this->sACModifier >= pValue; - case VAR_BaseLevel: - return this->uLevel >= pValue; - case VAR_LevelModifier: - return this->sLevelModifier >= pValue; - case VAR_Age: - return GetActualAge() >= (unsigned int)pValue; - case VAR_Award: - return _449B57_test_bit(this->_achieved_awards_bits, pValue); - case VAR_Experience: - return this->uExperience >= pValue; //TODO change pValue to long long - case VAR_QBits_QuestsDone: - return _449B57_test_bit(pParty->_quest_bits, pValue); - case VAR_PlayerItemInHands: - //for (int i = 0; i < 138; i++) - for (int i = 0; i < 126; i++) - { - if (pInventoryItemList[i].uItemID == pValue) - { - return true; - } - } - return pParty->pPickedItem.uItemID == pValue; - case VAR_Hour: - if ( (long long)(pParty->uTimePlayed * 0.234375) / 60 / 60 % 24 == pValue ) - return true; - return false; - case VAR_DayOfYear: - if (((long long)(pParty->uTimePlayed * 0.234375) / 60 / 60) / 24 % 336 + 1 == pValue) - return true; - return false; - case VAR_DayOfWeek: - if (((long long)(pParty->uTimePlayed * 0.234375) / 60 / 60) / 24 % 7) - return true; - return false; - case VAR_FixedGold: - return pParty->uNumGold >= (unsigned int)pValue; - case VAR_FixedFood: - return pParty->uNumFoodRations >= (unsigned int)pValue; - case VAR_MightBonus: - return this->uMightBonus >= pValue; - case VAR_IntellectBonus: - return this->uIntelligenceBonus >= pValue; - case VAR_PersonalityBonus: - return this->uWillpowerBonus >= pValue; - case VAR_EnduranceBonus: - return this->uEnduranceBonus >= pValue; - case VAR_SpeedBonus: - return this->uSpeedBonus >= pValue; - case VAR_AccuracyBonus: - return this->uAccuracyBonus >= pValue; - case VAR_LuckBonus: - return this->uLuckBonus >= pValue; - case VAR_BaseMight: - return this->uMight >= pValue; - case VAR_BaseIntellect: - return this->uIntelligence >= pValue; - case VAR_BasePersonality: - return this->uWillpower >= pValue; - case VAR_BaseEndurance: - return this->uEndurance >= pValue; - case VAR_BaseSpeed: - return this->uSpeed >= pValue; - case VAR_BaseAccuracy: - return this->uAccuracy >= pValue; - case VAR_BaseLuck: - return this->uLuck >= pValue; - case VAR_ActualMight: - return GetActualMight() >= pValue; - case VAR_ActualIntellect: - return GetActualIntelligence() >= pValue; - case VAR_ActualPersonality: - return GetActualWillpower() >= pValue; - case VAR_ActualEndurance: - return GetActualEndurance() >= pValue; - case VAR_ActualSpeed: - return GetActualSpeed() >= pValue; - case VAR_ActualAccuracy: - return GetActualAccuracy() >= pValue; - case VAR_ActualLuck: - return GetActualLuck() >= pValue; - case VAR_FireResistance: - return this->sResFireBase >= pValue; - case VAR_AirResistance: - return this->sResAirBase >= pValue; - case VAR_WaterResistance: - return this->sResWaterBase >= pValue; - case VAR_EarthResistance: - return this->sResEarthBase >= pValue; - case VAR_SpiritResistance: - return this->sResSpiritBase >= pValue; - case VAR_MindResistance: - return this->sResMindBase >= pValue; - case VAR_BodyResistance: - return this->sResBodyBase >= pValue; - case VAR_LightResistance: - return this->sResLightBase >= pValue; - case VAR_DarkResistance: - return this->sResDarkBase >= pValue; - case VAR_PhysicalResistance: - Error("Physical resistance isn't used in events"); - return false; - case VAR_MagicResistance: - return this->sResMagicBase >= pValue; - case VAR_FireResistanceBonus: - return this->sResFireBonus >= pValue; - case VAR_AirResistanceBonus: - return this->sResAirBonus >= pValue; - case VAR_WaterResistanceBonus: - return this->sResWaterBonus >= pValue; - case VAR_EarthResistanceBonus: - return this->sResEarthBonus >= pValue; - case VAR_SpiritResistanceBonus: - return this->sResSpiritBonus >= pValue; - case VAR_MindResistanceBonus: - return this->sResMindBonus >= pValue; - case VAR_BodyResistanceBonus: - return this->sResBodyBonus >= pValue; - case VAR_LightResistanceBonus: - return this->sResLightBonus >= pValue; - case VAR_DarkResistanceBonus: - return this->sResDarkBonus >= pValue; - case VAR_MagicResistanceBonus: - return this->sResMagicBonus >= pValue; - case VAR_StaffSkill: - return CmpSkillValue(pValue, this->skillStaff); - case VAR_SwordSkill: - return CmpSkillValue(pValue, this->skillSword); - case VAR_DaggerSkill: - return CmpSkillValue(pValue, this->skillDagger); - case VAR_AxeSkill: - return CmpSkillValue(pValue, this->skillAxe); - case VAR_SpearSkill: - return CmpSkillValue(pValue, this->skillSpear); - case VAR_BowSkill: - return CmpSkillValue(pValue, this->skillBow); - case VAR_MaceSkill: - return CmpSkillValue(pValue, this->skillMace); - case VAR_BlasterSkill: - return CmpSkillValue(pValue, this->skillBlaster); - case VAR_ShieldSkill: - return CmpSkillValue(pValue, this->skillShield); - case VAR_LeatherSkill: - return CmpSkillValue(pValue, this->skillLeather); - case VAR_SkillChain: - return CmpSkillValue(pValue, this->skillChain); - case VAR_PlateSkill: - return CmpSkillValue(pValue, this->skillPlate); - case VAR_FireSkill: - return CmpSkillValue(pValue, this->skillFire); - case VAR_AirSkill: - return CmpSkillValue(pValue, this->skillAir); - case VAR_WaterSkill: - return CmpSkillValue(pValue, this->skillWater); - case VAR_EarthSkill: - return CmpSkillValue(pValue, this->skillEarth); - case VAR_SpiritSkill: - return CmpSkillValue(pValue, this->skillSpirit); - case VAR_MindSkill: - return CmpSkillValue(pValue, this->skillMind); - case VAR_BodySkill: - return CmpSkillValue(pValue, this->skillBody); - case VAR_LightSkill: - return CmpSkillValue(pValue, this->skillLight); - case VAR_DarkSkill: - return CmpSkillValue(pValue, this->skillDark); - case VAR_IdentifyItemSkill: - return CmpSkillValue(pValue, this->skillItemId); - case VAR_MerchantSkill: - return CmpSkillValue(pValue, this->skillMerchant); - case VAR_RepairSkill: - return CmpSkillValue(pValue, this->skillRepair); - case VAR_BodybuildingSkill: - return CmpSkillValue(pValue, this->skillBodybuilding); - case VAR_MeditationSkill: - return CmpSkillValue(pValue, this->skillMeditation); - case VAR_PerceptionSkill: - return CmpSkillValue(pValue, this->skillPerception); - case VAR_DiplomacySkill: - return CmpSkillValue(pValue, this->skillDiplomacy); - case VAR_ThieverySkill: - Error("Thievery isn't used in events"); - return false; - case VAR_DisarmTrapSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillDisarmTrap); - case VAR_DodgeSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillDodge); - case VAR_UnarmedSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillUnarmed); - case VAR_IdentifyMonsterSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillMonsterId); - case VAR_ArmsmasterSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillArmsmaster); - case VAR_StealingSkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillStealing); - case VAR_AlchemySkill: //wasn't in the original - return CmpSkillValue(pValue, this->skillAlchemy); - case VAR_LearningSkill: - return CmpSkillValue(pValue, this->skillLearning); - case VAR_Cursed: - return pConditions[Condition_Cursed] > 0; - case VAR_Weak: - return pConditions[Condition_Weak] > 0; - case VAR_Asleep: - return pConditions[Condition_Sleep] > 0; - case VAR_Afraid: - return pConditions[Condition_Fear] > 0; - case VAR_Drunk: - return pConditions[Condition_Drunk] > 0; - case VAR_Insane: - return pConditions[Condition_Insane] > 0; - case VAR_PoisonedGreen: - return pConditions[Condition_Poison_Weak] > 0; - case VAR_DiseasedGreen: - return pConditions[Condition_Disease_Weak] > 0; - case VAR_PoisonedYellow: - return pConditions[Condition_Poison_Medium] > 0; - case VAR_DiseasedYellow: - return pConditions[Condition_Disease_Medium] > 0; - case VAR_PoisonedRed: - return pConditions[Condition_Poison_Severe] > 0; - case VAR_DiseasedRed: - return pConditions[Condition_Disease_Severe] > 0; - case VAR_Paralyzed: - return pConditions[Condition_Paralyzed] > 0; - case VAR_Unconsious: - return pConditions[Condition_Unconcious] > 0; - case VAR_Dead: - return pConditions[Condition_Dead] > 0; - case VAR_Stoned: - return pConditions[Condition_Pertified] > 0; - case VAR_Eradicated: - return pConditions[Condition_Eradicated] > 0; - case VAR_MajorCondition: - v4 = GetMajorConditionIdx(); - if ( v4 != 18 ) - { - return v4 >= pValue; - } - return true; - case VAR_AutoNotes : //TODO: find out why the double subtraction. or whether this is even used - test_bit_value = 0x80u >> (pValue - 2) % 8; - byteWithRequestedBit = pParty->_autonote_bits[(pValue - 2) /8]; - return (test_bit_value & byteWithRequestedBit) != 0; - case VAR_IsMightMoreThanBase: - actStat = GetActualMight(); - baseStat = GetBaseStrength(); - return (actStat >= baseStat); - case VAR_IsIntellectMoreThanBase: - actStat = GetActualIntelligence(); - baseStat = GetBaseIntelligence(); - return (actStat >= baseStat); - case VAR_IsPersonalityMoreThanBase: - actStat = GetActualWillpower(); - baseStat = GetBaseWillpower(); - return (actStat >= baseStat); - case VAR_IsEnduranceMoreThanBase: - actStat = GetActualEndurance(); - baseStat = GetBaseEndurance(); - return (actStat >= baseStat); - case VAR_IsSpeedMoreThanBase: - actStat = GetActualSpeed(); - baseStat = GetBaseSpeed(); - return (actStat >= baseStat); - case VAR_IsAccuracyMoreThanBase: - actStat = GetActualAccuracy(); - baseStat = GetBaseAccuracy(); - return (actStat >= baseStat); - case VAR_IsLuckMoreThanBase: - actStat = GetActualLuck(); - baseStat = GetBaseLuck(); - return (actStat >= baseStat); - case VAR_PlayerBits: - test_bit_value = 0x80u >> ((signed __int16)pValue - 1) % 8; - byteWithRequestedBit = this->playerEventBits[((signed __int16)pValue - 1)/8]; - return ( test_bit_value & byteWithRequestedBit ) != 0; - case VAR_NPCs2: - return pNPCStats->pNewNPCData[pValue].Hired(); - case VAR_IsFlying: - if ( pParty->bFlying - && (pParty->pPartyBuffs[PARTY_BUFF_FLY].uExpireTime> 0) ) - return true; - return false; - case VAR_HiredNPCHasSpeciality: - return CheckHiredNPCSpeciality(pValue); - case VAR_CircusPrises: //isn't used in MM6 since 0x1D6u is a book of regeneration - v4 = 0; - for (int playerNum = 0; playerNum < 4; playerNum++) - { - for (int invPos = 0; invPos < 138; invPos++) - { - int itemId = pParty->pPlayers[playerNum].pInventoryItemList[invPos].uItemID; - switch ( itemId ) - { - case 0x1D6u: - ++v4; - break; - case 0x1D7u: - v4 += 3; - break; - case 0x1DDu: - v4 += 5; - break; - } - } - } - return v4 >= pValue; - case VAR_NumSkillPoints: - return this->uSkillPoints >= (unsigned int)pValue; - case VAR_MonthIs: - return (pParty->uCurrentMonth == (unsigned int)pValue); - case VAR_Counter1: - case VAR_Counter2: - case VAR_Counter3: - case VAR_Counter4: - case VAR_Counter5: - case VAR_Counter6: - case VAR_Counter7: - case VAR_Counter8: - case VAR_Counter9: - case VAR_Counter10: - if (pParty->PartyTimes.CounterEventValues[VarNum - VAR_Counter1]) //originally (signed __int64)(__PAIR__(*(int *)&stru_AA1058[3].pSounds[8 * VarNum + 44304], *(int *)&stru_AA1058[3].pSounds[8 * VarNum + 44300]) - { - return (pParty->PartyTimes.CounterEventValues[VarNum - VAR_Counter1] + 460800 * pValue * 0.033333335) <= pParty->uTimePlayed ; - } - case VAR_ReputationInCurrentLocation: - v19 = &pOutdoor->ddm; - if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) - v19 = &pIndoor->dlv; - return (v19->uReputation >= pValue); - case VAR_Unknown1: - v21 = &pOutdoor->ddm; - if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) - v21 = &pIndoor->dlv; - return (v21->field_C_alert == pValue); //yes, equality, not >= - case VAR_GoldInBank: - return pParty->uNumGoldInBank >= (unsigned int)pValue; - case VAR_NumDeaths: - return pParty->uNumDeaths >= (unsigned int)pValue; - case VAR_NumBounties: - return pParty->uNumBountiesCollected >= (unsigned int)pValue; - case VAR_PrisonTerms: - return pParty->uNumPrisonTerms >= pValue; - case VAR_ArenaWinsPage: - return (unsigned __int8)pParty->uNumArenaPageWins >= pValue; - case VAR_ArenaWinsSquire: - return (unsigned __int8)pParty->uNumArenaSquireWins >= pValue; - case VAR_ArenaWinsKnight: - return (unsigned __int8)pParty->uNumArenaKnightWins >= pValue; - case VAR_ArenaWinsLord: - return pParty->uNumArenaLordWins >= pValue; - case VAR_Invisible: - return ( pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime > 0 ); - case VAR_ItemEquipped: - for (int i = 0; i < 16; i++) - { - if ( HasItemEquipped((ITEM_EQUIP_TYPE)i) && GetNthEquippedIndexItem(i)->uItemID == pValue ) - { - return true; - } - } - return false; - } - - return false; -} - - -//----- (0044A5CB) -------------------------------------------------------- -void Player::SetVariable(enum VariableType var_type, signed int var_value) -{ - unsigned int v6; // esi@13 - unsigned int v7; // esi@14 - signed int v11; // eax@30 - DDM_DLV_Header *v24; // ecx@148 - ItemGen item; // [sp+Ch] [bp-28h]@52 - - - if ( var_type >= VAR_History_0 && var_type <= VAR_History_28) - { - if (!pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0]) - { - pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0] = pParty->uTimePlayed; - if (pStorylineText->StoreLine[var_type - VAR_History_0].pText) - { - bFlashHistoryBook = 1; - PlayAwardSound(); - } - } - return; - } - - if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_99 ) - { - if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_74 ) - stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] = (char)var_value; // originally (unsigned __int8)byte_5E4C15[VarNum]; - if ( var_type >= VAR_MapPersistentVariable_75 && var_type <= VAR_MapPersistentVariable_99 ) - stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] = (unsigned char)var_value; //not really sure whether the number gets up to 99, but can't ignore the possibility - return; - } - - if ( var_type >= VAR_UnknownTimeEvent0 && var_type <= VAR_UnknownTimeEvent19 ) - { - pParty->PartyTimes._s_times[var_type - VAR_UnknownTimeEvent0] = pParty->uTimePlayed; //*(int *)&stru_AA1058[3].pSounds[8 * var_type + 44532] = LODWORD(pParty->uTimePlayed);, *(int *)&stru_AA1058[3].pSounds[8 * var_type + 44536] = HIDWORD(pParty->uTimePlayed - PlayAwardSound(); - return; - } - - switch ( var_type ) - { - case VAR_Sex: - this->uSex = (PLAYER_SEX)var_value; - PlayAwardSound_Anim(); - return; - case VAR_Class: - this->classType = (PLAYER_CLASS_TYPE)var_value; - if ( (PLAYER_CLASS_TYPE)var_value == PLAYER_CLASS_LICH ) - { - for (int i = 0; i < 138; i++) - { - if (this->pOwnItems[i].uItemID == ITEM_LICH_JAR_EMPTY) - { - this->pOwnItems[i].uItemID = ITEM_LICH_JAR_FULL; - this->pOwnItems[i].uHolderPlayer = GetPlayerIndex() + 1; - } - } - if ( this->sResFireBase < 20 ) - this->sResFireBase = 20; - if ( this->sResAirBase < 20 ) - this->sResAirBase = 20; - if ( this->sResWaterBase < 20 ) - this->sResWaterBase = 20; - if ( this->sResEarthBase < 20 ) - this->sResEarthBase = 20; - this->sResMindBase = 200; - this->sResBodyBase = 200; - v11 = this->GetSexByVoice(); - this->uPrevVoiceID = this->uVoiceID; - this->uPrevFace = this->uCurrentFace; - if ( v11 ) - { - this->uCurrentFace = 21; - this->uVoiceID = 21; - } - else - { - this->uCurrentFace = 20; - this->uVoiceID = 20; - } - ReloadPlayerPortraits(GetPlayerIndex(), this->uCurrentFace); - } - PlayAwardSound_Anim(); - return; - case VAR_CurrentHP: - this->sHealth = var_value; - PlayAwardSound_Anim(); - return; - case VAR_MaxHP: - this->sHealth = GetMaxHealth(); - return; - case VAR_CurrentSP: - this->sMana = var_value; - PlayAwardSound_Anim(); - return; - case VAR_MaxSP: - this->sMana = GetMaxMana(); - return; - case VAR_ACModifier: - this->sACModifier = (unsigned __int8)var_value; - PlayAwardSound_Anim(); - return; - case VAR_BaseLevel: - this->uLevel = (unsigned __int8)var_value; - PlayAwardSound_Anim(); - return; - case VAR_LevelModifier: - this->sLevelModifier = (unsigned __int8)var_value; - PlayAwardSound_Anim(); - return; - case VAR_Age: - this->sAgeModifier = var_value; - return; - case VAR_Award: - if ( !_449B57_test_bit(this->_achieved_awards_bits, var_value) && pAwards[var_value].pText ) - { - PlayAwardSound_Anim(); - this->PlaySound(SPEECH_96, 0); - } - _449B7E_toggle_bit(this->_achieved_awards_bits, var_value, 1u); - return; - case VAR_Experience: - this->uExperience = var_value; - PlayAwardSound_Anim(); - return; - case VAR_QBits_QuestsDone: - if ( !_449B57_test_bit(pParty->_quest_bits, var_value) && pQuestTable[var_value-1] ) - { - bFlashQuestBook = 1; - pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, GetPlayerIndex()); - PlayAwardSound(); - this->PlaySound(SPEECH_93, 0); - } - _449B7E_toggle_bit(pParty->_quest_bits, var_value, 1u); - return; - case VAR_PlayerItemInHands: - item.Reset(); - item.uItemID = var_value; - item.uAttributes = 1; - pParty->SetHoldingItem(&item); - if ( var_value >= ITEM_ARTIFACT_PUCK && var_value <= ITEM_RELIC_MEKORIGS_HAMMER ) - pParty->pIsArtifactFound[var_value-500] = 1; - return; - case VAR_FixedGold: - Party::SetGold(var_value); - return; - case VAR_RandomGold: - v6 = rand() % var_value + 1; - Party::SetGold(v6); - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[500], v6);// You have %lu gold - ShowStatusBarString(pTmpBuf.data(), 2u); - GameUI_DrawFoodAndGold(); - return; - case VAR_FixedFood: - Party::SetFood(var_value); - PlayAwardSound_Anim(); - return; - case VAR_RandomFood: - v7 = rand() % var_value + 1; - Party::SetFood(v7); - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[501], v7);// You have %lu food - ShowStatusBarString(pTmpBuf.data(), 2u); - GameUI_DrawFoodAndGold(); - PlayAwardSound_Anim(); - return; - case VAR_BaseMight: - this->uMight = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BaseIntellect: - this->uIntelligence = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BasePersonality: - this->uWillpower = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BaseEndurance: - this->uEndurance = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BaseSpeed: - this->uSpeed = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BaseAccuracy: - this->uAccuracy = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BaseLuck: - this->uLuck = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_MightBonus: - case VAR_ActualMight: - this->uMightBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_IntellectBonus: - case VAR_ActualIntellect: - this->uIntelligenceBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_PersonalityBonus: - case VAR_ActualPersonality: - this->uWillpowerBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_EnduranceBonus: - case VAR_ActualEndurance: - this->uEnduranceBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_SpeedBonus: - case VAR_ActualSpeed: - this->uSpeedBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_AccuracyBonus: - case VAR_ActualAccuracy: - this->uAccuracyBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_LuckBonus: - case VAR_ActualLuck: - this->uLuckBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_FireResistance: - this->sResFireBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_AirResistance: - this->sResAirBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_WaterResistance: - this->sResWaterBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_EarthResistance: - this->sResEarthBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_SpiritResistance: - this->sResSpiritBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_MindResistance: - this->sResMindBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_BodyResistance: - this->sResBodyBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_LightResistance: - this->sResLightBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_DarkResistance: - this->sResDarkBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_MagicResistance: - this->sResMagicBase = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_92); - return; - case VAR_FireResistanceBonus: - this->sResFireBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_AirResistanceBonus: - this->sResAirBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_WaterResistanceBonus: - this->sResWaterBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_EarthResistanceBonus: - this->sResEarthBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_SpiritResistanceBonus: - this->sResSpiritBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_MindResistanceBonus: - this->sResMindBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_BodyResistanceBonus: - this->sResBodyBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_LightResistanceBonus: - this->sResLightBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_DarkResistanceBonus: - this->sResDarkBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_PhysicalResistanceBonus: - Error("Physical res. bonus not used"); - return; - case VAR_MagicResistanceBonus: - this->sResMagicBonus = (unsigned __int8)var_value; - PlayAwardSound_Anim_Face(SPEECH_91); - return; - case VAR_Cursed: - this->SetCondition(Condition_Cursed, 1); - PlayAwardSound_Anim(); - return; - case VAR_Weak: - this->SetCondition(Condition_Weak, 1); - PlayAwardSound_Anim(); - return; - case VAR_Asleep: - this->SetCondition(Condition_Sleep, 1); - PlayAwardSound_Anim(); - return; - case VAR_Afraid: - this->SetCondition(Condition_Fear, 1); - PlayAwardSound_Anim(); - return; - case VAR_Drunk: - this->SetCondition(Condition_Drunk, 1); - PlayAwardSound_Anim(); - return; - case VAR_Insane: - this->SetCondition(Condition_Insane, 1); - PlayAwardSound_Anim(); - return; - case VAR_PoisonedGreen: - this->SetCondition(Condition_Poison_Weak, 1); - PlayAwardSound_Anim(); - return; - case VAR_DiseasedGreen: - this->SetCondition(Condition_Disease_Weak, 1); - PlayAwardSound_Anim(); - return; - case VAR_PoisonedYellow: - this->SetCondition(Condition_Poison_Medium, 1); - PlayAwardSound_Anim(); - return; - case VAR_DiseasedYellow: - this->SetCondition(Condition_Disease_Medium, 1); - PlayAwardSound_Anim(); - return; - case VAR_PoisonedRed: - this->SetCondition(Condition_Poison_Severe, 1); - PlayAwardSound_Anim(); - return; - case VAR_DiseasedRed: - this->SetCondition(Condition_Disease_Severe, 1); - PlayAwardSound_Anim(); - return; - case VAR_Paralyzed: - this->SetCondition(Condition_Paralyzed, 1); - PlayAwardSound_Anim(); - return; - case VAR_Unconsious: - this->SetCondition(Condition_Unconcious, 1); - PlayAwardSound_Anim(); - return; - case VAR_Dead: - this->SetCondition(Condition_Dead, 1); - PlayAwardSound_Anim(); - return; - case VAR_Stoned: - this->SetCondition(Condition_Pertified, 1); - PlayAwardSound_Anim(); - return; - case VAR_Eradicated: - this->SetCondition(Condition_Eradicated, 1); - PlayAwardSound_Anim(); - return; - case VAR_MajorCondition: - pConditions.fill(0); - PlayAwardSound_Anim(); - return; - case VAR_AutoNotes: - if ( !_449B57_test_bit(pParty->_autonote_bits, var_value) && pAutonoteTxt[var_value-1].pText ) - { - pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, GetPlayerIndex()); - this->PlaySound(SPEECH_96, 0); - bFlashAutonotesBook = 1; - _506568_autonote_type = pAutonoteTxt[var_value-1].eType;// dword_72371C[2 * a3]; - } - _449B7E_toggle_bit(pParty->_autonote_bits, var_value, 1u); - PlayAwardSound(); - return; - case VAR_PlayerBits: - _449B7E_toggle_bit((unsigned char *)playerEventBits, var_value, 1u); - return; - case VAR_NPCs2: - pParty->hirelingScrollPosition = 0; - LOBYTE(pNPCStats->pNewNPCData[var_value].uFlags) |= 0x80u; - pParty->CountHirelings(); - viewparams->bRedrawGameUI = true; - return; - case VAR_NumSkillPoints: - this->uSkillPoints = var_value; - return; - case VAR_Counter1: - case VAR_Counter2: - case VAR_Counter3: - case VAR_Counter4: - case VAR_Counter5: - case VAR_Counter6: - case VAR_Counter7: - case VAR_Counter8: - case VAR_Counter9: - case VAR_Counter10: - pParty->PartyTimes.CounterEventValues[var_type - VAR_Counter1] = pParty->uTimePlayed; // *(int *)&stru_AA1058[3].pSounds[8 * var_type + 44300] = LODWORD(pParty->uTimePlayed);*(int *)&stru_AA1058[3].pSounds[8 * var_type + 44304] = HIDWORD(pParty->uTimePlayed); - return; - case VAR_ReputationInCurrentLocation: - v24 = &pOutdoor->ddm; - if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) - v24 = &pIndoor->dlv; - v24->uReputation = var_value; - if ( var_value > 10000 ) - v24->uReputation = 10000; - return; - case VAR_GoldInBank: - pParty->uNumGoldInBank = var_value; - return; - case VAR_NumDeaths: - pParty->uNumDeaths = var_value; - return; - case VAR_NumBounties: - pParty->uNumBountiesCollected = var_value; - return; - case VAR_PrisonTerms: - pParty->uNumPrisonTerms = var_value; - return; - case VAR_ArenaWinsPage: - pParty->uNumArenaPageWins = var_value; - return; - case VAR_ArenaWinsSquire: - pParty->uNumArenaSquireWins = var_value; - return; - case VAR_ArenaWinsKnight: - pParty->uNumArenaKnightWins = var_value; - return; - case VAR_ArenaWinsLord: - pParty->uNumArenaLordWins = var_value; - return; - case VAR_StaffSkill: - SetSkillByEvent(&Player::skillStaff, var_value); - return; - case VAR_SwordSkill: - SetSkillByEvent(&Player::skillSword, var_value); - return; - case VAR_DaggerSkill: - SetSkillByEvent(&Player::skillDagger, var_value); - return; - case VAR_AxeSkill: - SetSkillByEvent(&Player::skillAxe, var_value); - return; - case VAR_SpearSkill: - SetSkillByEvent(&Player::skillSpear, var_value); - return; - case VAR_BowSkill: - SetSkillByEvent(&Player::skillBow, var_value); - return; - case VAR_MaceSkill: - SetSkillByEvent(&Player::skillMace, var_value); - return; - case VAR_BlasterSkill: - SetSkillByEvent(&Player::skillBlaster, var_value); - return; - case VAR_ShieldSkill: - SetSkillByEvent(&Player::skillShield, var_value); - return; - case VAR_LeatherSkill: - SetSkillByEvent(&Player::skillLeather, var_value); - return; - case VAR_SkillChain: - SetSkillByEvent(&Player::skillChain, var_value); - return; - case VAR_PlateSkill: - SetSkillByEvent(&Player::skillPlate, var_value); - return; - case VAR_FireSkill: - SetSkillByEvent(&Player::skillFire, var_value); - return; - case VAR_AirSkill: - SetSkillByEvent(&Player::skillAir, var_value); - return; - case VAR_WaterSkill: - SetSkillByEvent(&Player::skillWater, var_value); - return; - case VAR_EarthSkill: - SetSkillByEvent(&Player::skillEarth, var_value); - return; - case VAR_SpiritSkill: - SetSkillByEvent(&Player::skillSpirit, var_value); - return; - case VAR_MindSkill: - SetSkillByEvent(&Player::skillMind, var_value); - return; - case VAR_BodySkill: - SetSkillByEvent(&Player::skillBody, var_value); - return; - case VAR_LightSkill: - SetSkillByEvent(&Player::skillLight, var_value); - return; - case VAR_DarkSkill: - SetSkillByEvent(&Player::skillDark, var_value); - return; - case VAR_IdentifyItemSkill: - SetSkillByEvent(&Player::skillItemId, var_value); - return; - case VAR_MerchantSkill: - SetSkillByEvent(&Player::skillMerchant, var_value); - return; - case VAR_RepairSkill: - SetSkillByEvent(&Player::skillRepair, var_value); - return; - case VAR_BodybuildingSkill: - SetSkillByEvent(&Player::skillBodybuilding, var_value); - return; - case VAR_MeditationSkill: - SetSkillByEvent(&Player::skillMeditation, var_value); - return; - case VAR_PerceptionSkill: - SetSkillByEvent(&Player::skillPerception, var_value); - return; - case VAR_DiplomacySkill: - SetSkillByEvent(&Player::skillDiplomacy, var_value); - return; - case VAR_ThieverySkill: - Error ("Thieving unsupported"); - return; - case VAR_DisarmTrapSkill: - SetSkillByEvent(&Player::skillDisarmTrap, var_value); - return; - case VAR_DodgeSkill: - SetSkillByEvent(&Player::skillDodge, var_value); - return; - case VAR_UnarmedSkill: - SetSkillByEvent(&Player::skillUnarmed, var_value); - return; - case VAR_IdentifyMonsterSkill: - SetSkillByEvent(&Player::skillMonsterId, var_value); - return; - case VAR_ArmsmasterSkill: - SetSkillByEvent(&Player::skillArmsmaster, var_value); - return; - case VAR_StealingSkill: - SetSkillByEvent(&Player::skillStealing, var_value); - return; - case VAR_AlchemySkill: - SetSkillByEvent(&Player::skillAlchemy, var_value); - return; - case VAR_LearningSkill: - SetSkillByEvent(&Player::skillLearning, var_value); - return; - } -} - - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound() -{ - int playerIndex = GetPlayerIndex(); - signed int v25 = 8 * playerIndex + 400; - LOBYTE(v25) = PID(OBJECT_Player,playerIndex - 112); - pAudioPlayer->PlaySound(SOUND_20001, v25, 0, -1, 0, 0, 0, 0); -} - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim() -{ - int playerIndex = GetPlayerIndex(); - pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, playerIndex); - PlayAwardSound(); -} - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim_Face( PlayerSpeech speech ) -{ - this->PlaySound(speech, 0); - PlayAwardSound_Anim(); -} - -//----- (new function) -------------------------------------------------------- -void Player::SetSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 skillValue ) -{ - unsigned __int16 currSkillValue = this->*skillToSet; - if ( skillValue > 63 ) //the original had the condition reversed which was probably wrong - { - this->*skillToSet = skillValue | currSkillValue & 63; - } - else - { - this->*skillToSet = skillValue | currSkillValue & 0xC0; - } - int playerIndex = GetPlayerIndex(); - pGame->pStru6Instance->SetPlayerBuffAnim(0x96u, playerIndex); - PlayAwardSound(); -} - -//----- (0044AFFB) -------------------------------------------------------- -void Player::AddVariable(enum VariableType var_type, signed int val) -{ - int v6; // eax@15 - unsigned int v7; // esi@18 - DDM_DLV_Header *v27; // eax@153 - ItemGen item; // [sp+Ch] [bp-2Ch]@45 - - if ( var_type >= VAR_Counter1 && var_type <= VAR_Counter10) - { - pParty->PartyTimes.CounterEventValues[var_type - VAR_Counter1] = pParty->uTimePlayed; - return; - } - - if ( var_type >= VAR_UnknownTimeEvent0 && var_type <= VAR_UnknownTimeEvent19 ) - { - pParty->PartyTimes._s_times[var_type - VAR_UnknownTimeEvent0] = pParty->uTimePlayed; - PlayAwardSound(); - return; - } - - if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_99 ) - { - - if ( var_type >= VAR_MapPersistentVariable_0 && var_type <= VAR_MapPersistentVariable_74 ) - { - if (255 - val > stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0]) - stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] += val; - else - stru_5E4C90_MapPersistVars.field_0[var_type - VAR_MapPersistentVariable_0] = 255; - } - if ( (signed int)var_type >= VAR_MapPersistentVariable_75 && var_type <= VAR_MapPersistentVariable_99 ) - { - if (255 - val > stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75]) - stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] += val; - else - stru_5E4C90_MapPersistVars._decor_events[var_type - VAR_MapPersistentVariable_75] = 255; - } - return; - } - - if ( var_type >= VAR_History_0 && var_type <= VAR_History_28) - { - if (!pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0]) - { - pParty->PartyTimes.HistoryEventTimes[var_type - VAR_History_0] = pParty->uTimePlayed; - if (pStorylineText->StoreLine[var_type - VAR_History_0].pText = 0) - { - bFlashHistoryBook = 1; - PlayAwardSound(); - } - } - return; - } - - switch ( var_type ) - { - case VAR_RandomGold: - if ( val == 0 ) - val = 1; - v6 = rand(); - pParty->PartyFindsGold(v6 % val + 1, 1); - GameUI_DrawFoodAndGold(); - return; - case VAR_RandomFood: - if ( val == 0 ) - val = 1; - v7 = rand() % val + 1; - Party::GiveFood(v7); - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[502], v7);// You find %lu food - ShowStatusBarString(pTmpBuf.data(), 2u); - GameUI_DrawFoodAndGold(); - PlayAwardSound(); - return; - case VAR_Sex: - this->uSex = (PLAYER_SEX)val; - PlayAwardSound_Anim97(); - return; - case VAR_Class: - this->classType = (PLAYER_CLASS_TYPE)val; - PlayAwardSound_Anim97(); - return; - case VAR_CurrentHP: - this->sHealth = min(this->sHealth + val, this->GetMaxHealth() ); - PlayAwardSound_Anim97(); - return; - case VAR_MaxHP: - this->_health_related = 0; - this->uFullHealthBonus = 0; - this->sHealth = this->GetMaxHealth(); - return; - case VAR_CurrentSP: - this->sMana = min(this->sMana + val, this->GetMaxMana() ); - PlayAwardSound_Anim97(); - return; - case VAR_MaxSP: - this->_mana_related = 0; - this->uFullManaBonus = 0; - this->sMana = GetMaxMana(); - return; - case VAR_ACModifier: - this->sACModifier = min(this->sACModifier + val, 255); - PlayAwardSound_Anim97(); - return; - case VAR_BaseLevel: - this->uLevel = min(this->uLevel + val, 255); - PlayAwardSound_Anim97(); - return; - case VAR_LevelModifier: - this->sLevelModifier = min(this->sLevelModifier + val, 255); - PlayAwardSound_Anim97(); - return; - case VAR_Age: - this->sAgeModifier += val; - return; - case VAR_Award: - if (_449B57_test_bit(this->_achieved_awards_bits, val) && pAwards[val].pText ) - { - PlayAwardSound_Anim97_Face(SPEECH_96); - } - _449B7E_toggle_bit(this->_achieved_awards_bits, val, 1); - return; - case VAR_Experience: - this->uExperience = min(this->uExperience + val, 4000000000i64); - PlayAwardSound_Anim97(); - return; - case VAR_QBits_QuestsDone: - if ( !_449B57_test_bit(pParty->_quest_bits, val) && pQuestTable[val] ) - { - bFlashQuestBook = 1; - PlayAwardSound_Anim97_Face(SPEECH_93); - } - _449B7E_toggle_bit(pParty->_quest_bits, val, 1); - return; - case VAR_PlayerItemInHands: - item.Reset(); - item.uAttributes = 1; - item.uItemID = val; - if ( val >= ITEM_ARTIFACT_PUCK && val <= ITEM_RELIC_MEKORIGS_HAMMER ) - pParty->pIsArtifactFound[val-500] = 1; - else if ( val >= ITEM_WAND_FIRE && val <= ITEM_WAND_INCENERATION ) - { - item.uNumCharges = rand() % 6 + item.GetDamageMod() + 1; - item.uMaxCharges = LOBYTE(item.uNumCharges); - } - pParty->SetHoldingItem(&item); - return; - case VAR_FixedGold: - pParty->PartyFindsGold(val, 1); - return; - case VAR_BaseMight: - this->uMight = min(this->uMight + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BaseIntellect: - this->uIntelligence = min(this->uIntelligence + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BasePersonality: - this->uWillpower = min(this->uWillpower + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BaseEndurance: - this->uEndurance = min(this->uEndurance + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BaseSpeed: - this->uSpeed = min(this->uSpeed + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BaseAccuracy: - this->uAccuracy = min(this->uAccuracy + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BaseLuck: - this->uLuck = min(this->uLuck + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_FixedFood: - Party::GiveFood(val); - sprintfex(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[502], val); - ShowStatusBarString(pTmpBuf.data(), 2u); - if ( pParty->uNumFoodRations > 0xFFFF ) - Party::SetFood(0xFFFFu); - PlayAwardSound(); - return; - case VAR_MightBonus: - case VAR_ActualMight: - this->uMightBonus = min(this->uMightBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_IntellectBonus: - case VAR_ActualIntellect: - this->uIntelligenceBonus = min(this->uIntelligenceBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_PersonalityBonus: - case VAR_ActualPersonality: - this->uWillpowerBonus = min(this->uWillpowerBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_EnduranceBonus: - case VAR_ActualEndurance: - this->uEnduranceBonus = min(this->uEnduranceBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_SpeedBonus: - case VAR_ActualSpeed: - this->uSpeedBonus = min(this->uSpeedBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_AccuracyBonus: - case VAR_ActualAccuracy: - this->uAccuracyBonus = min(this->uAccuracyBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_LuckBonus: - case VAR_ActualLuck: - this->uLuckBonus = min(this->uLuckBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_FireResistance: - this->sResFireBase = min(this->sResFireBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_AirResistance: - this->sResAirBase = min(this->sResAirBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_WaterResistance: - this->sResWaterBase = min(this->sResWaterBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_EarthResistance: - this->sResEarthBase = min(this->sResEarthBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_SpiritResistance: - this->sResSpiritBase = min(this->sResSpiritBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_MindResistance: - this->sResMindBase = min(this->sResMindBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_BodyResistance: - this->sResBodyBase = min(this->sResBodyBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_LightResistance: - this->sResLightBase = min(this->sResLightBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_DarkResistance: - this->sResDarkBase = min(this->sResDarkBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_MagicResistance: - this->sResMagicBase = min(this->sResMagicBase + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_92); - return; - case VAR_FireResistanceBonus: - this->sResFireBonus = min(this->sResFireBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_AirResistanceBonus: - this->sResAirBonus = min(this->sResAirBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_WaterResistanceBonus: - this->sResWaterBonus = min(this->sResWaterBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_EarthResistanceBonus: - this->sResEarthBonus = min(this->sResEarthBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_SpiritResistanceBonus: - this->sResSpiritBonus = min(this->sResSpiritBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_MindResistanceBonus: - this->sResMindBonus = min(this->sResMindBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_BodyResistanceBonus: - this->sResBodyBonus = min(this->sResBodyBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_LightResistanceBonus: - this->sResLightBonus = min(this->sResLightBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_DarkResistanceBonus: - this->sResDarkBonus = min(this->sResDarkBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_MagicResistanceBonus: - this->sResMagicBonus = min(this->sResMagicBonus + val, 255); - PlayAwardSound_Anim97_Face(SPEECH_91); - return; - case VAR_Cursed: - this->SetCondition(Condition_Cursed, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Weak: - this->SetCondition(Condition_Weak, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Asleep: - this->SetCondition(Condition_Sleep, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Afraid: - this->SetCondition(Condition_Fear, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Drunk: - this->SetCondition(Condition_Drunk, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Insane: - this->SetCondition(Condition_Insane, 1); - PlayAwardSound_Anim97(); - return; - case VAR_PoisonedGreen: - this->SetCondition(Condition_Poison_Weak, 1); - PlayAwardSound_Anim97(); - return; - case VAR_DiseasedGreen: - this->SetCondition(Condition_Disease_Weak, 1); - PlayAwardSound_Anim97(); - return; - case VAR_PoisonedYellow: - this->SetCondition(Condition_Poison_Medium, 1); - PlayAwardSound_Anim97(); - return; - case VAR_DiseasedYellow: - this->SetCondition(Condition_Disease_Medium, 1); - PlayAwardSound_Anim97(); - return; - case VAR_PoisonedRed: - this->SetCondition(Condition_Poison_Severe, 1); - PlayAwardSound_Anim97(); - return; - case VAR_DiseasedRed: - this->SetCondition(Condition_Disease_Severe, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Paralyzed: - this->SetCondition(Condition_Paralyzed, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Unconsious: - this->SetCondition(Condition_Unconcious, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Dead: - this->SetCondition(Condition_Dead, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Stoned: - this->SetCondition(Condition_Pertified, 1); - PlayAwardSound_Anim97(); - return; - case VAR_Eradicated: - this->SetCondition(Condition_Eradicated, 1); - PlayAwardSound_Anim97(); - return; - case VAR_MajorCondition : - pConditions.fill(0); - PlayAwardSound_Anim97(); - return; - case VAR_AutoNotes: - if ( !_449B57_test_bit(pParty->_autonote_bits, val) && pAutonoteTxt[val].pText ) - { - this->PlaySound(SPEECH_96, 0); - bFlashAutonotesBook = 1; - _506568_autonote_type = pAutonoteTxt[val].eType; - pGame->pStru6Instance->SetPlayerBuffAnim(0x97u, GetPlayerIndex()); - } - _449B7E_toggle_bit(pParty->_autonote_bits, val, 1); - PlayAwardSound(); - return; - case VAR_PlayerBits: - _449B7E_toggle_bit((unsigned char *)this->playerEventBits, val, 1u); - return; - case VAR_NPCs2: - pParty->hirelingScrollPosition = 0; - LOBYTE(pNPCStats->pNewNPCData[val].uFlags) |= 0x80u; - pParty->CountHirelings(); - viewparams->bRedrawGameUI = true; - return; - case VAR_NumSkillPoints: - this->uSkillPoints += val; - return; - case VAR_ReputationInCurrentLocation: - v27 = &pOutdoor->ddm; - if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) - v27 = &pIndoor->dlv; - v27->uReputation += val; - if ( v27->uReputation > 10000 ) - v27->uReputation = 10000; - return; - case VAR_GoldInBank: - pParty->uNumGoldInBank += val; - return; - case VAR_NumDeaths: - pParty->uNumDeaths += val; - return; - case VAR_NumBounties: - pParty->uNumBountiesCollected += val; - return; - case VAR_PrisonTerms: - pParty->uNumPrisonTerms += val; - return; - case VAR_ArenaWinsPage: - pParty->uNumArenaPageWins += val; - return; - case VAR_ArenaWinsSquire: - pParty->uNumArenaSquireWins += val; - return; - case VAR_ArenaWinsKnight: - pParty->uNumArenaKnightWins += val; - return; - case VAR_ArenaWinsLord: - pParty->uNumArenaLordWins += val; - return; - case VAR_StaffSkill: - AddSkillByEvent(&Player::skillStaff, val); - return; - case VAR_SwordSkill: - AddSkillByEvent(&Player::skillSword, val); - return; - case VAR_DaggerSkill: - AddSkillByEvent(&Player::skillDagger, val); - return; - case VAR_AxeSkill: - AddSkillByEvent(&Player::skillAxe, val); - return; - case VAR_SpearSkill: - AddSkillByEvent(&Player::skillSpear, val); - return; - case VAR_BowSkill: - AddSkillByEvent(&Player::skillBow, val); - return; - case VAR_MaceSkill: - AddSkillByEvent(&Player::skillMace, val); - return; - case VAR_BlasterSkill: - AddSkillByEvent(&Player::skillBlaster, val); - return; - case VAR_ShieldSkill: - AddSkillByEvent(&Player::skillShield, val); - return; - case VAR_LeatherSkill: - AddSkillByEvent(&Player::skillLeather, val); - return; - case VAR_SkillChain: - AddSkillByEvent(&Player::skillChain, val); - return; - case VAR_PlateSkill: - AddSkillByEvent(&Player::skillPlate, val); - return; - case VAR_FireSkill: - AddSkillByEvent(&Player::skillFire, val); - return; - case VAR_AirSkill: - AddSkillByEvent(&Player::skillAir, val); - return; - case VAR_WaterSkill: - AddSkillByEvent(&Player::skillWater, val); - return; - case VAR_EarthSkill: - AddSkillByEvent(&Player::skillEarth, val); - return; - case VAR_SpiritSkill: - AddSkillByEvent(&Player::skillSpirit, val); - return; - case VAR_MindSkill: - AddSkillByEvent(&Player::skillMind, val); - return; - case VAR_BodySkill: - AddSkillByEvent(&Player::skillBody, val); - return; - case VAR_LightSkill: - AddSkillByEvent(&Player::skillLight, val); - return; - case VAR_DarkSkill: - AddSkillByEvent(&Player::skillDark, val); - return; - case VAR_IdentifyItemSkill: - AddSkillByEvent(&Player::skillItemId, val); - return; - case VAR_MerchantSkill: - AddSkillByEvent(&Player::skillMerchant, val); - return; - case VAR_RepairSkill: - AddSkillByEvent(&Player::skillRepair, val); - return; - case VAR_BodybuildingSkill: - AddSkillByEvent(&Player::skillBodybuilding, val); - return; - case VAR_MeditationSkill: - AddSkillByEvent(&Player::skillMeditation, val); - return; - case VAR_PerceptionSkill: - AddSkillByEvent(&Player::skillPerception, val); - return; - case VAR_DiplomacySkill: - AddSkillByEvent(&Player::skillDiplomacy, val); - return; - case VAR_ThieverySkill: - Error ("Thieving unsupported"); - return; - case VAR_DisarmTrapSkill: - AddSkillByEvent(&Player::skillDisarmTrap, val); - return; - case VAR_DodgeSkill: - AddSkillByEvent(&Player::skillDodge, val); - return; - case VAR_UnarmedSkill: - AddSkillByEvent(&Player::skillUnarmed, val); - return; - case VAR_IdentifyMonsterSkill: - AddSkillByEvent(&Player::skillMonsterId, val); - return; - case VAR_ArmsmasterSkill: - AddSkillByEvent(&Player::skillArmsmaster, val); - return; - case VAR_StealingSkill: - AddSkillByEvent(&Player::skillStealing, val); - return; - case VAR_AlchemySkill: - AddSkillByEvent(&Player::skillAlchemy, val); - return; - case VAR_LearningSkill: - AddSkillByEvent(&Player::skillLearning, val); - return; - default: - return; - } -} - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim97() -{ - int playerIndex = GetPlayerIndex(); - pGame->pStru6Instance->SetPlayerBuffAnim(0x97u, playerIndex); - PlayAwardSound(); -} - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim97_Face( PlayerSpeech speech ) -{ - this->PlaySound(speech, 0); - PlayAwardSound_Anim97(); -} - -//----- (new function) -------------------------------------------------------- -void Player::AddSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 addSkillValue ) -{ - if ( addSkillValue > 63 ) - { - this->*skillToSet = (unsigned __int8)addSkillValue | this->*skillToSet & 63; - } - else - { - this->*skillToSet = min(this->*skillToSet + addSkillValue, 60) | this->*skillToSet & 0xC0; - } - PlayAwardSound_Anim97(); - return; -} - -//----- (0044B9C4) -------------------------------------------------------- -void Player::SubtractVariable( enum VariableType VarNum, signed int pValue ) -{ - DDM_DLV_Header *locationHeader; // eax@90 - int randGold; - int randFood; - int npcIndex; - - if ( VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_99 ) - { - if ( VarNum >= VAR_MapPersistentVariable_0 && VarNum <= VAR_MapPersistentVariable_74 ) - { - stru_5E4C90_MapPersistVars.field_0[VarNum - VAR_MapPersistentVariable_0] -= pValue; - } - if ( (signed int)VarNum >= VAR_MapPersistentVariable_75 && VarNum <= VAR_MapPersistentVariable_99 ) - { - stru_5E4C90_MapPersistVars._decor_events[VarNum - VAR_MapPersistentVariable_75] -= pValue; - } - return; - } - - switch (VarNum) - { - case VAR_CurrentHP: - ReceiveDamage((signed int)pValue, DMGT_PHISYCAL); - PlayAwardSound_Anim98(); - return; - case VAR_CurrentSP: - this->sMana = max(this->sMana - pValue, 0); - PlayAwardSound_Anim98(); - return; - case VAR_ACModifier: - this->sACModifier -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_BaseLevel: - this->uLevel -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_LevelModifier: - this->sLevelModifier -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_Age: - this->sAgeModifier -= (signed __int16)pValue; - return; - case VAR_Award: - _449B7E_toggle_bit(this->_achieved_awards_bits, (signed __int16)pValue, 0); - return; - case VAR_Experience: - this->uExperience -= pValue; - PlayAwardSound_Anim98(); - return; - case VAR_QBits_QuestsDone: - _449B7E_toggle_bit(pParty->_quest_bits, (__int16)pValue, 0); - this->PlaySound(SPEECH_96, 0); - return; - case VAR_PlayerItemInHands: - for ( uint i = 0; i < 16; ++i ) - { - int id_ = this->pEquipment.pIndices[i]; - if ( id_ > 0 ) - { - if ( this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uItemID == pValue ) - { - this->pEquipment.pIndices[i] = 0; - } - } - } - for (int i = 0; i < 126; i++) - { - int id_ = this->pInventoryMatrix[i]; - if ( id_ > 0 ) - { - if ( this->pInventoryItemList[id_ - 1].uItemID == pValue ) - { - RemoveItemAtInventoryIndex(i); - return; - } - } - } - if ( pParty->pPickedItem.uItemID == pValue ) - { - pMouse->RemoveHoldingItem(); - return; - } - return; - case VAR_FixedGold: - if ( (unsigned int)pValue > pParty->uNumGold ) - { - dword_5B65C4_cancelEventProcessing = 1; - return; - } - Party::TakeGold((unsigned int)pValue); - return; - case VAR_RandomGold: - randGold = rand() % (signed int)pValue + 1; - if ( (unsigned int)randGold > pParty->uNumGold ) - randGold = pParty->uNumGold; - Party::TakeGold(randGold); - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[503], randGold); - ShowStatusBarString(pTmpBuf.data(), 2); - GameUI_DrawFoodAndGold(); - return; - case VAR_FixedFood: - Party::TakeFood((unsigned int)pValue); - PlayAwardSound_Anim98(); - return; - case VAR_RandomFood: - randFood = rand() % (signed int)pValue + 1; - if ( (unsigned int)randFood > pParty->uNumFoodRations ) - randFood = pParty->uNumFoodRations; - Party::TakeFood(randFood); - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[504], randFood); - ShowStatusBarString(pTmpBuf.data(), 2u); - GameUI_DrawFoodAndGold(); - PlayAwardSound_Anim98(); - return; - case VAR_MightBonus: - case VAR_ActualMight: - this->uMightBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_IntellectBonus: - case VAR_ActualIntellect: - this->uIntelligenceBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_PersonalityBonus: - case VAR_ActualPersonality: - this->uWillpowerBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_EnduranceBonus: - case VAR_ActualEndurance: - this->uEnduranceBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_SpeedBonus: - case VAR_ActualSpeed: - this->uSpeedBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_AccuracyBonus: - case VAR_ActualAccuracy: - this->uAccuracyBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_LuckBonus: - case VAR_ActualLuck: - this->uLuckBonus -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_BaseMight: - this->uMight -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BaseIntellect: - this->uIntelligence -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BasePersonality: - this->uWillpower -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BaseEndurance: - this->uEndurance -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BaseSpeed: - this->uSpeed -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BaseAccuracy: - this->uAccuracy -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BaseLuck: - this->uLuck -= (unsigned __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_FireResistance: - this->sResFireBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_AirResistance: - this->sResAirBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_WaterResistance: - this->sResWaterBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_EarthResistance: - this->sResEarthBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_SpiritResistance: - this->sResSpiritBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_MindResistance: - this->sResMindBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_BodyResistance: - this->sResBodyBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_LightResistance: - this->sResLightBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_DarkResistance: - this->sResDarkBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_MagicResistance: - this->sResMagicBase -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_FireResistanceBonus: - this->sResFireBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_AirResistanceBonus: - this->sResAirBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_92); - return; - case VAR_WaterResistanceBonus: - this->sResWaterBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_EarthResistanceBonus: - this->sResEarthBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_SpiritResistanceBonus: - this->sResSpiritBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_MindResistanceBonus: - this->sResMindBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_BodyResistanceBonus: - this->sResBodyBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_LightResistanceBonus: - this->sResLightBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_DarkResistanceBonus: - this->sResDarkBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_MagicResistanceBonus: - this->sResMagicBonus -= (signed __int16)pValue; - this->PlayAwardSound_Anim98_Face(SPEECH_91); - return; - case VAR_StaffSkill: - this->skillStaff -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_SwordSkill: - this->skillSword -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_DaggerSkill: - this->skillDagger -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_AxeSkill: - this->skillAxe -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_SpearSkill: - this->skillSpear -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_BowSkill: - this->skillBow -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_MaceSkill: - this->skillMace -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_BlasterSkill: - this->skillBlaster -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_ShieldSkill: - this->skillShield -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_LeatherSkill: - this->skillLearning -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_SkillChain: - this->skillChain -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_PlateSkill: - this->skillPlate -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_FireSkill: - this->skillFire -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_AirSkill: - this->skillAir -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_WaterSkill: - this->skillWater -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_EarthSkill: - this->skillEarth -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_SpiritSkill: - this->skillSpirit -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_MindSkill: - this->skillMind -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_BodySkill: - this->skillBody -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_LightSkill: - this->skillLight -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_DarkSkill: - this->skillDark -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_IdentifyItemSkill: - this->skillItemId -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_MerchantSkill: - this->skillMerchant -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_RepairSkill: - this->skillRepair -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_BodybuildingSkill: - this->skillBodybuilding -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_MeditationSkill: - this->skillMeditation -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_PerceptionSkill: - this->skillPerception -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_DiplomacySkill: - this->skillDiplomacy -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_ThieverySkill: - Error ("Thieving unsupported"); - return; - case VAR_DisarmTrapSkill: - this->skillDisarmTrap -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_DodgeSkill: - this->skillDodge -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_UnarmedSkill: - this->skillUnarmed -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_IdentifyMonsterSkill: - this->skillMonsterId -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_ArmsmasterSkill: - this->skillArmsmaster -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_StealingSkill: - this->skillStealing -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_AlchemySkill: - this->skillAlchemy -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_LearningSkill: - this->skillLearning -= (unsigned __int8)pValue; - PlayAwardSound_Anim98(); - return; - case VAR_Cursed: - this->pConditions[Condition_Cursed] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Weak: - this->pConditions[Condition_Weak] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Asleep: - this->pConditions[Condition_Sleep] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Afraid: - this->pConditions[Condition_Fear] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Drunk: - this->pConditions[Condition_Drunk] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Insane: - this->pConditions[Condition_Insane] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_PoisonedGreen: - this->pConditions[Condition_Poison_Weak] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_DiseasedGreen: - this->pConditions[Condition_Disease_Weak] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_PoisonedYellow: - this->pConditions[Condition_Poison_Medium] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_DiseasedYellow: - this->pConditions[Condition_Disease_Medium] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_PoisonedRed: - this->pConditions[Condition_Poison_Severe] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_DiseasedRed: - this->pConditions[Condition_Disease_Severe] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Paralyzed: - this->pConditions[Condition_Paralyzed] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Unconsious: - this->pConditions[Condition_Unconcious] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Dead: - this->pConditions[Condition_Dead] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Stoned: - this->pConditions[Condition_Pertified] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_Eradicated: - this->pConditions[Condition_Eradicated] = 0; - PlayAwardSound_Anim98(); - return; - case VAR_AutoNotes: - _449B7E_toggle_bit(pParty->_autonote_bits, pValue - 1, 0); - return; - case VAR_NPCs2: - npcIndex = 0; - GetNewNPCData(sDialogue_SpeakingActorNPC_ID, &npcIndex); - if ( npcIndex == pValue ) - { - npcIdToDismissAfterDialogue = pValue; - } - else - { - npcIdToDismissAfterDialogue = 0; - pParty->hirelingScrollPosition = 0; - LOBYTE(pNPCStats->pNewNPCData[(int)pValue].uFlags) &= 0x7Fu; - pParty->CountHirelings(); - viewparams->bRedrawGameUI = true; - } - return; - case VAR_HiredNPCHasSpeciality: - for (unsigned int i = 0; i < pNPCStats->uNumNewNPCs; i++) - { - if (pNPCStats->pNewNPCData[i].uProfession == pValue) - { - LOBYTE(pNPCStats->pNewNPCData[(int)pValue].uFlags) &= 0x7Fu; - } - } - if ( pParty->pHirelings[0].uProfession == pValue ) - memset(&pParty->pHirelings[0], 0, sizeof(NPCData)); - if ( pParty->pHirelings[1].uProfession == pValue ) - memset(&pParty->pHirelings[1], 0, sizeof(NPCData)); - pParty->hirelingScrollPosition = 0; - pParty->CountHirelings(); - return; - case VAR_NumSkillPoints: - if ((unsigned int)pValue <= this->uSkillPoints) - { - this->uSkillPoints -= pValue; - } - else - { - this->uSkillPoints = 0; - } - return; - case VAR_ReputationInCurrentLocation: - locationHeader = &pOutdoor->ddm; - if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) - locationHeader = &pIndoor->dlv; - locationHeader->uReputation -= pValue; - if (locationHeader->uReputation < -10000) - locationHeader->uReputation = -10000; - return; - case VAR_GoldInBank: - if ( (unsigned int)pValue <= pParty->uNumGoldInBank ) - { - pParty->uNumGoldInBank -= (unsigned int)pValue; - } - else - { - dword_5B65C4_cancelEventProcessing = 1; - } - return; - case VAR_NumDeaths: - pParty->uNumDeaths -= (unsigned int)pValue; - return; - case VAR_NumBounties: - pParty->uNumBountiesCollected -= (unsigned int)pValue; - return; - case VAR_PrisonTerms: - pParty->uNumPrisonTerms -= (int)pValue; - return; - case VAR_ArenaWinsPage: - pParty->uNumArenaPageWins -= (char)pValue; - return; - case VAR_ArenaWinsSquire: - pParty->uNumArenaSquireWins -= (char)pValue; - return; - case VAR_ArenaWinsKnight: - pParty->uNumArenaKnightWins -= (char)pValue; - return; - case VAR_ArenaWinsLord: - pParty->uNumArenaLordWins -= (char)pValue; - return; - } -} -// 5B65C4: using guessed type int dword_5B65C4; -// 5B65CC: using guessed type int dword_5B65CC; - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim98() -{ - int playerIndex = GetPlayerIndex(); - pGame->pStru6Instance->SetPlayerBuffAnim(0x98u, playerIndex); - PlayAwardSound(); -} - -//----- (new function) -------------------------------------------------------- -void Player::PlayAwardSound_Anim98_Face( PlayerSpeech speech ) -{ - this->PlaySound(speech, 0); - PlayAwardSound_Anim98(); -} - -//----- (00467E7F) -------------------------------------------------------- -void Player::EquipBody(ITEM_EQUIP_TYPE uEquipType) -{ - int itemAnchor; // ebx@1 - int itemInvLocation; // edx@1 - int freeSlot; // eax@3 - ItemGen tempPickedItem; // [sp+Ch] [bp-30h]@1 - - tempPickedItem.Reset(); - itemAnchor = pEquipTypeToBodyAnchor[uEquipType]; - itemInvLocation = pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor]; - if ( itemInvLocation )//ïåðåîäåòüñÿ â äðóãóþ âåùü - { - memcpy(&tempPickedItem, &pParty->pPickedItem, sizeof(tempPickedItem)); - pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1].uBodyAnchor = 0; - pParty->pPickedItem.Reset(); - pParty->SetHoldingItem(&pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1]); - tempPickedItem.uBodyAnchor = itemAnchor + 1; - memcpy(&pPlayers[uActiveCharacter]->pInventoryItemList[itemInvLocation - 1], &tempPickedItem, sizeof(ItemGen)); - pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor] = itemInvLocation; - } - else//îäåòü âåùü - { - freeSlot = pPlayers[uActiveCharacter]->FindFreeInventoryListSlot(); - if (freeSlot >= 0) - { - pParty->pPickedItem.uBodyAnchor = itemAnchor + 1; - memcpy(&pPlayers[uActiveCharacter]->pInventoryItemList[freeSlot], &pParty->pPickedItem, sizeof(ItemGen)); - pPlayers[uActiveCharacter]->pEquipment.pIndices[itemAnchor] = freeSlot + 1; - pMouse->RemoveHoldingItem(); - } - } -} - -//----- (0049387A) -------------------------------------------------------- -int CycleCharacter(bool backwards) -{ - const int PARTYSIZE = 4; - int valToAdd = backwards ? (PARTYSIZE - 2) : 0; - int mult = backwards ? -1 : 1; - - for (int i = 0; i < (PARTYSIZE - 1); i++) - { - int currCharId = ((uActiveCharacter + mult * i + valToAdd) % PARTYSIZE) + 1; - if ( pPlayers[currCharId]->uTimeToRecovery == 0 ) - { - return currCharId; - } - } - return uActiveCharacter; -} - -//----- (0043EE77) -------------------------------------------------------- -bool Player::HasUnderwaterSuitEquipped() //the original function took the player number as a parameter. if it was 0, the whole party was checked. calls with the parameter 0 have been changed to calls to this for every player -{ - if (GetArmorItem() == nullptr || GetArmorItem()->uItemID != 604) - { - return false; - } - return true; -} - -//----- (0043EE15) -------------------------------------------------------- -bool Player::HasItem( unsigned int uItemID, bool checkHeldItem ) -{ - if ( !checkHeldItem || pParty->pPickedItem.uItemID != uItemID ) - { - for ( uint i = 0; i < 126; ++i ) - { - if ( this->pInventoryMatrix[i] > 0 ) - { - if ( (unsigned int)this->pInventoryItemList[this->pInventoryMatrix[i] - 1].uItemID == uItemID ) - return true; - } - } - for ( uint i = 0; i < 16; ++i ) - { - if ( this->pEquipment.pIndices[i] ) - { - if ( (unsigned int)this->pInventoryItemList[this->pEquipment.pIndices[i] - 1].uItemID == uItemID ) - return true; - } - } - return false; - } - else - { - return true; - } -} -//----- (0043EDB9) -------------------------------------------------------- -bool ShouldLoadTexturesForRaceAndGender(unsigned int _this) -{ - CHARACTER_RACE race; // edi@2 - PLAYER_SEX sex; // eax@2 - - for (int i = 1; i <= 4; i++) - { - race = pPlayers[i]->GetRace(); - sex = pPlayers[i]->GetSexByVoice(); - switch(_this) - { - case 0: - if (( race == CHARACTER_RACE_HUMAN || race == CHARACTER_RACE_ELF || race == CHARACTER_RACE_GOBLIN ) && sex == SEX_MALE ) - return true; - break; - case 1: - if (( race == CHARACTER_RACE_HUMAN || race == CHARACTER_RACE_ELF || race == CHARACTER_RACE_GOBLIN ) && sex == SEX_FEMALE ) - return true; - break; - case 2: - if ( race == CHARACTER_RACE_DWARF && sex == SEX_MALE ) - return true; - break; - case 3: - if ( race == CHARACTER_RACE_DWARF && sex == SEX_FEMALE ) - return true; - break; - } - } - return false; -} - -//----- (0043ED6F) -------------------------------------------------------- -bool IsDwarfPresentInParty(bool a1) -{ - for (uint i = 0; i < 4; ++i) - { - CHARACTER_RACE race = pParty->pPlayers[i].GetRace(); - - if (race == CHARACTER_RACE_DWARF && a1) - return true; - else if (race != CHARACTER_RACE_DWARF && !a1) - return true; - } - return false; -} - -//----- (00439FCB) -------------------------------------------------------- -void __fastcall DamagePlayerFromMonster(unsigned int uObjID, int dmgSource, Vec3_int_ *pPos, signed int a4) -{ - Player *playerPtr; // ebx@3 - Actor *actorPtr; // esi@3 - int spellId; // eax@38 - signed int recvdMagicDmg; // eax@139 - int v72[4]; // [sp+30h] [bp-24h]@164 - int healthBeforeRecvdDamage; // [sp+48h] [bp-Ch]@3 - unsigned int uActorID; // [sp+4Ch] [bp-8h]@1 - - uActorID = PID_ID(uObjID); - if ( PID_TYPE(uObjID) != 2) - { - playerPtr = &pParty->pPlayers[a4]; - actorPtr = &pActors[uActorID]; - healthBeforeRecvdDamage = playerPtr->sHealth; - if ( PID_TYPE(uObjID) != 3 || !actorPtr->ActorHitOrMiss(playerPtr) ) - return; - ItemGen* equippedArmor = playerPtr->GetArmorItem(); - SoundID soundToPlay; - if ( !equippedArmor - || equippedArmor->IsBroken() - || - (equippedArmor->GetPlayerSkillType() != PLAYER_SKILL_CHAIN - && equippedArmor->GetPlayerSkillType() != PLAYER_SKILL_PLATE - ) - ) - { - int randVal = rand() % 4; - switch (randVal) - { - case 0 : soundToPlay = (SoundID)108; break; - case 1 : soundToPlay = (SoundID)109; break; - case 2 : soundToPlay = (SoundID)110; break; - case 3 : soundToPlay = (SoundID)44; break; - default: Error("Unexpected sound value"); - } - } - else - { - int randVal = rand() % 4; - switch (randVal) - { - case 0 : soundToPlay = (SoundID)105; break; - case 1 : soundToPlay = (SoundID)106; break; - case 2 : soundToPlay = (SoundID)107; break; - case 3 : soundToPlay = (SoundID)45; break; - default: Error("Unexpected sound value"); - } - } - pAudioPlayer->PlaySound(soundToPlay, PID(OBJECT_Player,a4 + 80), 0, -1, 0, 0, 0, 0); - int dmgToReceive = actorPtr->_43B3E0_CalcDamage(dmgSource); - if ( actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime > 0 ) - { - __int16 spellPower = actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uPower; - if ( spellPower ) - dmgToReceive /= (signed int)spellPower; - } - int damageType; - switch (dmgSource) - { - case 0: damageType = actorPtr->pMonsterInfo.uAttack1Type; - break; - case 1: damageType = actorPtr->pMonsterInfo.uAttack2Type; - break; - case 2: spellId = actorPtr->pMonsterInfo.uSpell1ID; - damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); - break; - case 3: spellId = actorPtr->pMonsterInfo.uSpell2ID; - damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); - break; - case 4: damageType = actorPtr->pMonsterInfo.field_3C_some_special_attack; - break; - default: - case 5: damageType = 4; //yes, the original just assigned the value 4 - break; - } - if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) ) - { - dmgToReceive = playerPtr->ReceiveDamage(dmgToReceive, (DAMAGE_TYPE)damageType); - if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_PAIN_REFLECTION].uExpireTime > 0 ) - { - int actorState = actorPtr->uAIState; - if ( actorState != Dying && actorState != Dead) - { - int reflectedDamage = actorPtr->CalcMagicalDamageToActor((DAMAGE_TYPE)damageType, dmgToReceive); - actorPtr->sCurrentHP -= reflectedDamage; - if ( reflectedDamage >= 0 ) - { - if ( actorPtr->sCurrentHP >= 1 ) - { - Actor::AI_Stun(uActorID, PID(OBJECT_Player,a4), 0); //todo extract this branch to a function once Actor::functions are changed to nonstatic actor functions - Actor::AggroSurroundingPeasants(uActorID, 1); - } - else - { - if ( pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].bQuestMonster & 1 && pGame->uFlags2 & GAME_FLAGS_2_DRAW_BLOODSPLATS) - { - int splatRadius = byte_4D864C && BYTE2(pGame->uFlags) & 8 ? 10 * actorPtr->uActorRadius : actorPtr->uActorRadius; - pDecalBuilder->AddBloodsplat(actorPtr->vPosition.x, actorPtr->vPosition.y, actorPtr->vPosition.z, 1.0, 0.0, 0.0, (float)splatRadius, 0, 0); - } - Actor::Die(uActorID); - Actor::ApplyFineForKillingPeasant(uActorID); - Actor::AggroSurroundingPeasants(uActorID, 1); - if ( actorPtr->pMonsterInfo.uExp ) - pParty->GivePartyExp(pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].uExp); - int speechToPlay = SPEECH_51; - if ( rand() % 100 < 20 ) - speechToPlay = actorPtr->pMonsterInfo.uHP >= 100 ? 2 : 1; - playerPtr->PlaySound((PlayerSpeech)speechToPlay, 0); - } - } - } - } - if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) - && actorPtr->pMonsterInfo.uSpecialAttackType - && rand() % 100 < actorPtr->pMonsterInfo.uLevel * actorPtr->pMonsterInfo.uSpecialAttackLevel ) - { - playerPtr->ReceiveSpecialAttackEffect(actorPtr->pMonsterInfo.uSpecialAttackType, actorPtr); - } - } - if ( !pParty->bTurnBasedModeOn ) - { - int actEndurance = playerPtr->GetActualEndurance(); - int recoveryTime = (int)((20 - playerPtr->GetParameterBonus(actEndurance)) * flt_6BE3A4_debug_recmod1 * 2.133333333333333); - playerPtr->SetRecoveryTime(recoveryTime); - } - int yellThreshold = playerPtr->GetMaxHealth() / 4; - if ( yellThreshold < playerPtr->sHealth && yellThreshold >= healthBeforeRecvdDamage && playerPtr->sHealth > 0 ) - { - playerPtr->PlaySound(SPEECH_48, 0); - } - viewparams->bRedrawGameUI = 1; - return; - } - else - { - SpriteObject* v37 = &pSpriteObjects[uActorID]; - int uActorType = PID_TYPE(v37->spell_caster_pid); - int uActorID = PID_ID(v37->spell_caster_pid); - if ( uActorType == 2 ) - { - Player *playerPtr; // eax@81 - if ( a4 != -1 ) - { - playerPtr = &pParty->pPlayers[a4]; - } - else - { - int activePlayerCounter = 0; - for (int i = 1; i <= 4; i++) - { - if (pPlayers[i]->CanAct()) - { - v72[activePlayerCounter] = i; - activePlayerCounter++; - } - } - if ( activePlayerCounter ) - { - playerPtr = &pParty->pPlayers[v72[rand() % activePlayerCounter] - 1];//&stru_AA1058[3].pSounds[6972 * *(&v72 + rand() % v74) + 40552]; - } - } - int v68; - int v69; - if ( uActorType != OBJECT_Player || v37->spell_id != SPELL_BOW_ARROW) - { - int playerMaxHp = playerPtr->GetMaxHealth(); - v68 = _43AFE3_calc_spell_damage(v37->spell_id, v37->spell_level, v37->spell_skill, playerMaxHp); - v69 = LOBYTE(pSpellStats->pInfos[v37->spell_id].uSchool); - } - else - { - v68 = pParty->pPlayers[uActorID].CalculateRangedDamageTo(0); - v69 = 0; - } - playerPtr->ReceiveDamage(v68, (DAMAGE_TYPE)v69); - if ( uActorType == OBJECT_Player && !_A750D8_player_speech_timer ) - { - _A750D8_player_speech_timer = 256i64; - PlayerSpeechID = SPEECH_44; - uSpeakingCharacter = uActorID + 1; - } - return; - } - else if ( uActorType == 3 ) - { - Actor *actorPtr = &pActors[uActorID]; - if ( a4 == -1 ) - a4 = stru_50C198.which_player_to_attack(actorPtr); - Player *playerPtr = &pParty->pPlayers[a4]; - int dmgToReceive = actorPtr->_43B3E0_CalcDamage(dmgSource); - unsigned __int16 spriteType = v37->uType; - if ( v37->uType == 545 ) - { - __int16 skillLevel = playerPtr->GetActualSkillLevel(PLAYER_SKILL_UNARMED); - if ( SkillToMastery(skillLevel) >= 4 && rand() % 100 < (skillLevel & 0x3F) ) - { - sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[637], playerPtr->pName); - ShowStatusBarString(pTmpBuf.data(), 2u); - playerPtr->PlaySound(SPEECH_6, 0); - return; - } - } - else if ( spriteType == 555 - || spriteType == 510 - || spriteType == 500 - || spriteType == 515 - || spriteType == 505 - || spriteType == 530 - || spriteType == 525 - || spriteType == 520 - || spriteType == 535 - || spriteType == 540 ) - { - if ( !actorPtr->ActorHitOrMiss(playerPtr) ) - return; - if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_SHIELD].uExpireTime > 0 ) - dmgToReceive >>= 1; - if ( playerPtr->HasEnchantedItemEquipped(36) ) - dmgToReceive >>= 1; - if ( playerPtr->HasEnchantedItemEquipped(69) ) - dmgToReceive >>= 1; - if ( playerPtr->HasItemEquipped(EQUIP_ARMOUR) - && playerPtr->GetArmorItem()->uItemID == ITEM_ARTIFACT_GOVERNORS_ARMOR ) - dmgToReceive >>= 1; - if ( playerPtr->HasItemEquipped(EQUIP_TWO_HANDED)) - { - ItemGen* mainHandItem = playerPtr->GetMainHandItem(); - if ( mainHandItem->uItemID == ITEM_RELIC_KELEBRIM || mainHandItem->uItemID == ITEM_ARTIFACT_ELFBANE || (mainHandItem->GetItemEquipType() == EQUIP_SHIELD && SkillToMastery(playerPtr->pActiveSkills[PLAYER_SKILL_SHIELD]) == 4)) - dmgToReceive >>= 1; - } - if ( playerPtr->HasItemEquipped(EQUIP_SINGLE_HANDED)) - { - ItemGen* offHandItem = playerPtr->GetOffHandItem(); - if ( offHandItem->uItemID == ITEM_RELIC_KELEBRIM || offHandItem->uItemID == ITEM_ARTIFACT_ELFBANE || (offHandItem->GetItemEquipType() == EQUIP_SHIELD && SkillToMastery(playerPtr->pActiveSkills[PLAYER_SKILL_SHIELD]) == 4)) - dmgToReceive >>= 1; - } - } - if ( actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uExpireTime > 0 ) - { - int spellPower = actorPtr->pActorBuffs[ACTOR_BUFF_SHRINK].uPower; - if ( spellPower ) - dmgToReceive /= (signed int)spellPower; - } - int damageType; - switch(dmgSource) - { - case 0: - damageType = actorPtr->pMonsterInfo.uAttack1Type; - break; - case 1: - damageType = actorPtr->pMonsterInfo.uAttack2Type; - break; - case 2: - spellId = actorPtr->pMonsterInfo.uSpell1ID; - damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); - break; - case 3: - spellId = actorPtr->pMonsterInfo.uSpell2ID; - damageType = LOBYTE(pSpellStats->pInfos[spellId].uSchool); - break; - case 4: - damageType = actorPtr->pMonsterInfo.field_3C_some_special_attack; - break; - case 5: - damageType = 4; - break; - } - if ( !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) ) - { - int reflectedDmg = playerPtr->ReceiveDamage(dmgToReceive, (DAMAGE_TYPE)damageType); - if ( playerPtr->pPlayerBuffs[PLAYER_BUFF_PAIN_REFLECTION].uExpireTime > 0 ) - { - unsigned __int16 actorState = actorPtr->uAIState; - if ( actorState != Dying && actorState != Dead) - { - recvdMagicDmg = actorPtr->CalcMagicalDamageToActor((DAMAGE_TYPE)damageType, reflectedDmg); - actorPtr->sCurrentHP -= recvdMagicDmg; - if ( recvdMagicDmg >= 0 ) - { - if ( actorPtr->sCurrentHP >= 1 ) - { - Actor::AI_Stun(uActorID, PID(OBJECT_Player,a4), 0); - Actor::AggroSurroundingPeasants(uActorID, 1); - } - else - { - if ( pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].bQuestMonster & 1 && pGame->uFlags2 & GAME_FLAGS_2_DRAW_BLOODSPLATS ) - { - int splatRadius = byte_4D864C && BYTE2(pGame->uFlags) & 8 ? 10 * actorPtr->uActorRadius : actorPtr->uActorRadius; - pDecalBuilder->AddBloodsplat(actorPtr->vPosition.x, actorPtr->vPosition.y, actorPtr->vPosition.z, 1.0, 0.0, 0.0, (float)splatRadius, 0, 0); - } - Actor::Die(uActorID); - Actor::ApplyFineForKillingPeasant(uActorID); - Actor::AggroSurroundingPeasants(uActorID, 1); - if ( actorPtr->pMonsterInfo.uExp ) - pParty->GivePartyExp(pMonsterStats->pInfos[actorPtr->pMonsterInfo.uID].uExp); - int speechToPlay = SPEECH_51; - if ( rand() % 100 < 20 ) - speechToPlay = actorPtr->pMonsterInfo.uHP >= 100 ? 2 : 1; - playerPtr->PlaySound((PlayerSpeech)speechToPlay, 0); - } - } - } - } - } - if ( !dmgSource - && !(dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DAMAGE) - && actorPtr->pMonsterInfo.uSpecialAttackType - && rand() % 100 < actorPtr->pMonsterInfo.uLevel * actorPtr->pMonsterInfo.uSpecialAttackLevel ) - { - playerPtr->ReceiveSpecialAttackEffect(actorPtr->pMonsterInfo.uSpecialAttackType, actorPtr); - } - if ( !pParty->bTurnBasedModeOn ) - { - int actEnd = playerPtr->GetActualEndurance(); - int recTime = (int)((20 - playerPtr->GetParameterBonus(actEnd)) - * flt_6BE3A4_debug_recmod1 - * 2.133333333333333); - playerPtr->SetRecoveryTime(recTime); - } - return; - } - else - { - return; - } - } -} -//----- (00421EA6) -------------------------------------------------------- -void Player::OnInventoryLeftClick() -{ - signed int inventoryXCoord; // ecx@2 - int inventoryYCoord; // eax@2 - int invMatrixIndex; // eax@2 - unsigned int enchantedItemPos; // eax@7 - unsigned int pickedItemId; // esi@12 - unsigned int invItemIndex; // eax@12 - unsigned int itemPos; // eax@18 - ItemGen tmpItem; // [sp+Ch] [bp-3Ch]@1 - unsigned int pY; // [sp+3Ch] [bp-Ch]@2 - unsigned int pX; // [sp+40h] [bp-8h]@2 - CastSpellInfo *pSpellInfo; - - if ( pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] == 103 ) - { - pMouse->GetClickPos(&pX, &pY); - inventoryYCoord = (pY - 17) / 32; - inventoryXCoord = (pX - 14) / 32; - invMatrixIndex = inventoryXCoord + (INVETORYSLOTSWIDTH * inventoryYCoord); - if ( inventoryYCoord >= 0 && inventoryYCoord < INVETORYSLOTSHEIGHT && inventoryXCoord >= 0 && inventoryXCoord < INVETORYSLOTSWIDTH) - { - if ( _50C9A0_IsEnchantingInProgress ) - { - enchantedItemPos = this->GetItemIDAtInventoryIndex(&invMatrixIndex); - if ( enchantedItemPos ) - { - /* *((char *)pGUIWindow_Settings->ptr_1C + 8) &= 0x7Fu; - *((short *)pGUIWindow_Settings->ptr_1C + 2) = uActiveCharacter - 1; - *((int *)pGUIWindow_Settings->ptr_1C + 3) = enchantedItemPos - 1; - *((short *)pGUIWindow_Settings->ptr_1C + 3) = invMatrixIndex;*/ - pSpellInfo = (CastSpellInfo *)pGUIWindow_Settings->ptr_1C; - pSpellInfo->uFlags &= 0x7F; - pSpellInfo->uPlayerID_2 = uActiveCharacter - 1; - pSpellInfo->spell_target_pid = enchantedItemPos - 1; - pSpellInfo->field_6 = invMatrixIndex; - ptr_50C9A4_ItemToEnchant = &this->pInventoryItemList[enchantedItemPos-1]; - _50C9A0_IsEnchantingInProgress = 0; - if ( pMessageQueue_50CBD0->uNumMessages ) - pMessageQueue_50CBD0->uNumMessages = pMessageQueue_50CBD0->pMessages[0].field_8 != 0; - pMouse->SetCursorBitmap("MICON1"); - _50C9D0_AfterEnchClickEventId = 113; - _50C9D4_AfterEnchClickEventSecondParam = 0; - _50C9D8_AfterEnchClickEventTimeout = 256; - } - return; - } - if ( ptr_50C9A4_ItemToEnchant ) - return; - pickedItemId = pParty->pPickedItem.uItemID; - invItemIndex = this->GetItemIDAtInventoryIndex(&invMatrixIndex); - if (!pickedItemId) - { - if ( !invItemIndex ) - return; - else - { - memcpy(&pParty->pPickedItem, &this->pInventoryItemList[invItemIndex-1], sizeof(pParty->pPickedItem)); - this->RemoveItemAtInventoryIndex(invMatrixIndex); - pickedItemId = pParty->pPickedItem.uItemID; - pMouse->SetCursorBitmap(pItemsTable->pItems[pickedItemId].pIconName); - return; - } - } - else - { - if ( invItemIndex ) - { - ItemGen* invItemPtr = &this->pInventoryItemList[invItemIndex-1]; - memcpy(&tmpItem, invItemPtr, sizeof(tmpItem)); - this->RemoveItemAtInventoryIndex(invMatrixIndex); - int emptyIndex = this->AddItem2(invMatrixIndex, &pParty->pPickedItem); - if ( !emptyIndex ) - { - emptyIndex = this->AddItem2(-1, &pParty->pPickedItem); - if ( !emptyIndex ) - { - this->PutItemArInventoryIndex(tmpItem.uItemID, invItemIndex - 1, invMatrixIndex); - memcpy(invItemPtr, &tmpItem, sizeof(ItemGen)); - return; - } - } - memcpy(&pParty->pPickedItem, &tmpItem, sizeof(ItemGen)); - pMouse->SetCursorBitmap(pParty->pPickedItem.GetIconName()); - return; - } - else - { - itemPos = this->AddItem(invMatrixIndex, pickedItemId); - if ( itemPos ) - { - memcpy(&this->pInventoryItemList[itemPos-1], &pParty->pPickedItem, sizeof(ItemGen)); - pMouse->RemoveHoldingItem(); - return; - } - itemPos = this->AddItem(-1, pickedItemId); - if ( itemPos ) - { - memcpy(&this->pInventoryItemList[itemPos-1], &pParty->pPickedItem, sizeof(ItemGen)); - pMouse->RemoveHoldingItem(); - return; - } - } - } - } - } -} - - -bool Player::IsWeak() -{ - return pConditions[Condition_Weak] != 0; -} - -bool Player::IsDead() -{ - return pConditions[Condition_Dead] != 0; -} - -bool Player::IsEradicated() -{ - return pConditions[Condition_Eradicated] != 0; -} - -bool Player::IsZombie() -{ - return pConditions[Condition_Zombie] != 0; -} - -bool Player::IsCursed() -{ - return pConditions[Condition_Cursed] != 0; -} - -bool Player::IsPertified() -{ - return pConditions[Condition_Pertified] != 0; -} - -bool Player::IsUnconcious() -{ - return pConditions[Condition_Unconcious] != 0; -} - -bool Player::IsAsleep() -{ - return pConditions[Condition_Sleep] != 0; -} - -bool Player::IsParalyzed() -{ - return pConditions[Condition_Paralyzed] != 0; -} - -bool Player::IsDrunk() -{ - return pConditions[Condition_Drunk] != 0; -} - -void Player::SetCursed( unsigned long long state ) -{ - pConditions[Condition_Cursed] = state; -} - -void Player::SetWeak( unsigned long long state ) -{ - pConditions[Condition_Weak] = state; -} - -void Player::SetAsleep( unsigned long long state ) -{ - pConditions[Condition_Sleep] = state; -} - -void Player::SetAfraid( unsigned long long state ) -{ - pConditions[Condition_Fear] = state; -} - -void Player::SetDrunk( unsigned long long state ) -{ - pConditions[Condition_Drunk] = state; -} - -void Player::SetInsane( unsigned long long state ) -{ - pConditions[Condition_Insane] = state; -} - -void Player::SetPoisonWeak( unsigned long long state ) -{ - pConditions[Condition_Poison_Weak] = state; -} - -void Player::SetDiseaseWeak( unsigned long long state ) -{ - pConditions[Condition_Disease_Weak] = state; -} - -void Player::SetPoisonMedium( unsigned long long state ) -{ - pConditions[Condition_Poison_Medium] = state; -} - -void Player::SetDiseaseMedium( unsigned long long state ) -{ - pConditions[Condition_Disease_Medium] = state; -} - -void Player::SetPoisonSevere( unsigned long long state ) -{ - pConditions[Condition_Poison_Severe] = state; -} - -void Player::SetDiseaseSevere( unsigned long long state ) -{ - pConditions[Condition_Disease_Severe] = state; -} - -void Player::SetParalyzed( unsigned long long state ) -{ - pConditions[Condition_Paralyzed] = state; -} - -void Player::SetUnconcious( unsigned long long state ) -{ - pConditions[Condition_Unconcious] = state; -} - -void Player::SetDead( unsigned long long state ) -{ - pConditions[Condition_Dead] = state; -} - -void Player::SetPertified( unsigned long long state ) -{ - pConditions[Condition_Pertified] = state; -} - -void Player::SetEradicated( unsigned long long state ) -{ - pConditions[Condition_Eradicated] = state; -} - -void Player::SetZombie( unsigned long long state ) -{ - pConditions[Condition_Zombie] = state; -} - -void Player::SetCondWeakWithBlockCheck( int blockable ) -{ - SetCondition(Condition_Weak, blockable); -} - -void Player::SetCondInsaneWithBlockCheck( int blockable ) -{ - SetCondition(Condition_Insane, blockable); -} - -void Player::SetCondDeadWithBlockCheck( int blockable ) -{ - SetCondition(Condition_Dead, blockable); -} - -void Player::SetCondUnconsciousWithBlockCheck( int blockable ) -{ - SetCondition(Condition_Dead, blockable); -} - -ItemGen* Player::GetOffHandItem() -{ - return GetItem(&PlayerEquipment::uShield); -} - -ItemGen* Player::GetMainHandItem() -{ - return GetItem(&PlayerEquipment::uMainHand); -} - -ItemGen* Player::GetBowItem() -{ - return GetItem(&PlayerEquipment::uBow); -} - -ItemGen* Player::GetArmorItem() -{ - return GetItem(&PlayerEquipment::uArmor); -} - -ItemGen* Player::GetHelmItem() -{ - return GetItem(&PlayerEquipment::uHelm); -} - -ItemGen* Player::GetBeltItem() -{ - return GetItem(&PlayerEquipment::uBelt); -} - -ItemGen* Player::GetCloakItem() -{ - return GetItem(&PlayerEquipment::uCloak); -} - -ItemGen* Player::GetGloveItem() -{ - return GetItem(&PlayerEquipment::uGlove); -} - -ItemGen* Player::GetBootItem() -{ - return GetItem(&PlayerEquipment::uBoot); -} - -ItemGen* Player::GetAmuletItem() -{ - return GetItem(&PlayerEquipment::uAmulet); -} - -ItemGen* Player::GetNthRingItem(int ringNum) -{ - return GetNthEquippedIndexItem(ringNum + 10); -} - -ItemGen* Player::GetNthEquippedIndexItem(int index) -{ - if (this->pEquipment.pIndices[index] == 0) - { - return nullptr; - } - return &this->pInventoryItemList[this->pEquipment.pIndices[index] - 1]; -} - -ItemGen* Player::GetItem(unsigned int PlayerEquipment::* itemPos) -{ - if (this->pEquipment.*itemPos == 0) - { - return nullptr; - } - return &this->pInventoryItemList[this->pEquipment.*itemPos - 1]; -} - -int Player::GetPlayerIndex() -{ - int uPlayerIdx = 0; - if ( this == pPlayers[1] ) - uPlayerIdx = 0; - else if( this == pPlayers[2] ) - uPlayerIdx = 1; - else if ( this == pPlayers[3] ) - uPlayerIdx = 2; - else if ( this == pPlayers[4] ) - uPlayerIdx = 3; - else - Error("Unexpected player pointer"); - return uPlayerIdx; -} - -//----- (004272F5) -------------------------------------------------------- -bool Player::PlayerHitOrMiss(Actor *pActor, int a3, int a4) -{ - signed int naturalArmor; // esi@1 - signed int armorBuff; // edi@1 - int effectiveActorArmor; // esi@8 - int attBonus; // eax@9 - int v9; // edx@11 -// unsigned __int8 v12; // sf@13 -// unsigned __int8 v13; // of@13 - int attPositiveMod; // edx@14 - int attNegativeMod; // eax@14 -// signed int result; // eax@17 - - naturalArmor = pActor->pMonsterInfo.uAC; - armorBuff = 0; - if ( pActor->pActorBuffs[ACTOR_BUFF_SOMETHING_THAT_HALVES_AC].uExpireTime > 0 ) - naturalArmor /= 2; - if ( pActor->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].uExpireTime > 0 ) - armorBuff = pActor->pActorBuffs[ACTOR_BUFF_SHIELD].uPower; - if ( pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uExpireTime > 0 && pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower > armorBuff ) - armorBuff = pActor->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower; - effectiveActorArmor = armorBuff + naturalArmor; - if ( a3 ) - attBonus = this->GetRangedAttack(); - else - attBonus = this->GetActualAttack(false); - v9 = rand() % (effectiveActorArmor + 2 * attBonus + 30); - attPositiveMod = a4 + v9; - if ( a3 == 2 ) - { - attNegativeMod = ((effectiveActorArmor + 15) / 2) + effectiveActorArmor + 15; - } - else if ( a3 == 3 ) - { - attNegativeMod = 2 * effectiveActorArmor + 30; - } - else - { - attNegativeMod = effectiveActorArmor + 15; - } - return (attPositiveMod > attNegativeMod); -} - - -//----- (0042ECB5) -------------------------------------------------------- -void Player::_42ECB5_PlayerAttacksActor() -{ -// char *v5; // eax@8 -// unsigned int v9; // ecx@21 -// char *v11; // eax@26 -// unsigned int v12; // eax@47 -// SoundID v24; // [sp-4h] [bp-40h]@58 - - //result = pParty->pPlayers[uActiveCharacter-1].CanAct(); - Player* player = &pParty->pPlayers[uActiveCharacter - 1]; - if (!player->CanAct()) - return; - - CastSpellInfoHelpers::_427D48(); - //v3 = 0; - if (pParty->Invisible()) - pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset(); - - //v31 = player->pEquipment.uBow; - int bow_idx = player->pEquipment.uBow; - if (bow_idx && player->pInventoryItemList[bow_idx - 1].IsBroken()) - bow_idx = 0; - - //v32 = 0; - int wand_item_id = 0; - //v33 = 0; - //v4 = v1->pEquipment.uMainHand; - int laser_weapon_item_id = 0; - - int main_hand_idx = player->pEquipment.uMainHand; - if (main_hand_idx) - { - ItemGen* item = &player->pInventoryItemList[main_hand_idx - 1]; - //v5 = (char *)v1 + 36 * v4; - if (!item->IsBroken()) - { - //v28b = &v1->pInventoryItems[v4].uItemID; - //v6 = v1->pInventoryItems[v4].uItemID;//*((int *)v5 + 124); - if (item->GetItemEquipType() == EQUIP_WAND) - { - if (item->uNumCharges <= 0) - player->pEquipment.uMainHand = 0; // wand discharged - unequip - else - wand_item_id = item->uItemID;//*((int *)v5 + 124); - } - else if (item->uItemID == ITEM_BLASTER || item->uItemID == ITEM_LASER_RIFLE) - laser_weapon_item_id = item->uItemID;//*((int *)v5 + 124); - } - } - - //v30 = 0; - //v29 = 0; - //v28 = 0; - //v7 = pMouse->uPointingObjectID; - - int target_pid = pMouse->uPointingObjectID; - int target_type = PID_TYPE(target_pid), - target_id = PID_ID(target_pid); - if (target_type != OBJECT_Actor || !pActors[target_id].CanAct()) - { - target_pid = stru_50C198.FindClosestActor(5120, 0, 0); - target_type = PID_TYPE(target_pid); - target_id = PID_ID(target_pid); - } - - Actor* actor = &pActors[target_id]; - int actor_distance = 0; - if (target_type == OBJECT_Actor) - { - int distance_x = actor->vPosition.x - pParty->vPosition.x, - distance_y = actor->vPosition.y - pParty->vPosition.y, - distance_z = actor->vPosition.z - pParty->vPosition.z; - actor_distance = integer_sqrt(distance_x * distance_x + distance_y * distance_y + distance_z * distance_z) - actor->uActorRadius; - if (actor_distance < 0) - actor_distance = 0; - } - - bool shooting_bow = false, - shotting_laser = false, - shooting_wand = false, - melee_attack = false; - if (laser_weapon_item_id) - { - shotting_laser = true; - _42777D_CastSpell_UseWand_ShootArrow(SPELL_LASER_PROJECTILE, uActiveCharacter - 1, 0, 0, uActiveCharacter + 8); - } - else if (wand_item_id) - { - shooting_wand = true; - - int main_hand_idx = player->pEquipment.uMainHand; - _42777D_CastSpell_UseWand_ShootArrow(wand_spell_ids[player->pInventoryItemList[main_hand_idx - 1].uItemID - ITEM_WAND_FIRE], uActiveCharacter - 1, 8, 0, uActiveCharacter + 8); - - if (!--player->pInventoryItemList[main_hand_idx - 1].uNumCharges) - player->pEquipment.uMainHand = 0; - } - else if (target_type == OBJECT_Actor && actor_distance <= 407.2) - { - melee_attack = true; - - Vec3_int_ a3; - a3.x = actor->vPosition.x - pParty->vPosition.x; - a3.y = actor->vPosition.y - pParty->vPosition.y; - a3.z = actor->vPosition.z - pParty->vPosition.z; - Vec3_int_::Normalize(&a3.x, &a3.y, &a3.z); - - Actor::DamageMonsterFromParty(PID(OBJECT_Player, uActiveCharacter - 1), target_id, &a3); - if (player->WearsItem(ITEM_ARTIFACT_SPLITTER, EQUIP_TWO_HANDED) || player->WearsItem(ITEM_ARTIFACT_SPLITTER, EQUIP_SINGLE_HANDED)) - _42FA66_do_explosive_impact(actor->vPosition.x, actor->vPosition.y, actor->vPosition.z + actor->uActorHeight / 2, 0, 512, uActiveCharacter); - } - else if (bow_idx) - { - shooting_bow = true; - _42777D_CastSpell_UseWand_ShootArrow(SPELL_BOW_ARROW, uActiveCharacter - 1, 0, 0, 0); - } - else - { - melee_attack = true; - ; // actor out of range or no actor; no ranged weapon so melee attacking air - } - - if (!pParty->bTurnBasedModeOn && melee_attack) // wands, bows & lasers will add recovery while shooting spell effect - { - int recovery = player->GetAttackRecoveryTime(false); - if (recovery < 30 ) - recovery = 30; - player->SetRecoveryTime(flt_6BE3A4_debug_recmod1 * (double)recovery * 2.133333333333333); - } - - int v34 = 0; - if (shooting_wand) - return; - else if (shooting_bow) - { - v34 = 5; - player->PlaySound(SPEECH_50, 0); - } - if (shotting_laser) - v34 = 7; - else - { - int main_hand_idx = player->pEquipment.uMainHand; - if (player->HasItemEquipped(EQUIP_TWO_HANDED)) - v34 = player->pInventoryItemList[main_hand_idx - 1].GetPlayerSkillType(); - pTurnEngine->ApplyPlayerAction(); - } - - switch (v34) - { - case 0: pAudioPlayer->PlaySound(SOUND_81, 0, 0, -1, 0, 0, 0, 0); break; - case 1: pAudioPlayer->PlaySound(SOUND_84, 0, 0, -1, 0, 0, 0, 0); break; - case 2: pAudioPlayer->PlaySound(SOUND_85, 0, 0, -1, 0, 0, 0, 0); break; - case 3: pAudioPlayer->PlaySound(SOUND_78, 0, 0, -1, 0, 0, 0, 0); break; - case 4: pAudioPlayer->PlaySound(SOUND_80, 0, 0, -1, 0, 0, 0, 0); break; - case 5: pAudioPlayer->PlaySound(SOUND_71, 0, 0, -1, 0, 0, 0, 0); break; - case 6: pAudioPlayer->PlaySound(SOUND_83, 0, 0, -1, 0, 0, 0, 0); break; - case 7: pAudioPlayer->PlaySound(SOUND_67, 0, 0, -1, 0, 0, 0, 0); break; - } -} - - -//----- (0042FA66) -------------------------------------------------------- -void Player::_42FA66_do_explosive_impact(int a1, int a2, int a3, int a4, __int16 a5, signed int a6) -{ - unsigned __int16 v9; // ax@5 - - SpriteObject a1a; // [sp+Ch] [bp-74h]@1 - //SpriteObject::SpriteObject(&a1a); - a1a.uType = 600; - a1a.stru_24.Reset(); - - a1a.spell_id = SPELL_FIRE_FIREBALL; - a1a.spell_level = 8; - a1a.spell_skill = 3; - v9 = 0; - for ( uint i = 0; i < pObjectList->uNumObjects; ++i ) - { - if ( a1a.uType == pObjectList->pObjects[i].uObjectID ) - v9 = i; - } - a1a.uObjectDescID = v9; - a1a.vPosition.x = a1; - a1a.vPosition.y = a2; - a1a.vPosition.z = a3; - a1a.uAttributes = 0; - a1a.uSectorID = pIndoor->GetSector(a1, a2, a3); - a1a.uSpriteFrameID = 0; - a1a.spell_target_pid = 0; - a1a.field_60_distance_related_prolly_lod = 0; - a1a.uFacing = 0; - a1a.uSoundID = 0; - if ( a6 >= 1 || a6 <= 4 ) - a1a.spell_caster_pid = PID(OBJECT_Player, a6 - 1); - else - a1a.spell_caster_pid = 0; - - int id = a1a.Create(0, 0, 0, 0); - if (id != -1) - AttackerInfo.Add(PID(OBJECT_Item, id), a5, SLOWORD(a1a.vPosition.x), SLOWORD(a1a.vPosition.y), - SLOWORD(a1a.vPosition.z), 0, 0); -} - -//----- (00458244) -------------------------------------------------------- -unsigned int SkillToMastery( unsigned int skill_value ) -{ - switch (skill_value & 0x1C0) - { - case 0x100: return 4; // Grandmaster - case 0x80: return 3; // Master - case 0x40: return 2; // Expert - case 0x00: return 1; // Normal - } - assert(false); - return 0; -} \ No newline at end of file
--- a/Player.h Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,856 +0,0 @@ -#pragma once -#include "Items.h" -#include "Spells.h" -#include "Conditions.h" - - - -enum PLAYER_BUFFS -{ - PLAYER_BUFF_RESIST_AIR = 0, - PLAYER_BUFF_BLESS = 1, - PLAYER_BUFF_RESIST_BODY = 2, - PLAYER_BUFF_RESIST_EARTH = 3, - PLAYER_BUFF_FATE = 4, - PLAYER_BUFF_RESIST_FIRE = 5, - PLAYER_BUFF_HAMMERHANDS = 6, - PLAYER_BUFF_HASTE = 7, - PLAYER_BUFF_HEROISM = 8, - PLAYER_BUFF_RESIST_MIND = 9, - PLAYER_BUFF_PAIN_REFLECTION = 10, - PLAYER_BUFF_PRESERVATION = 11, - PLAYER_BUFF_REGENERATION = 12, - PLAYER_BUFF_SHIELD = 13, - PLAYER_BUFF_STONESKIN = 14, - PLAYER_BUFF_ACCURACY = 15, - PLAYER_BUFF_ENDURANCE = 16, - PLAYER_BUFF_INTELLIGENCE = 17, - PLAYER_BUFF_LUCK = 18, - PLAYER_BUFF_STRENGTH = 19, - PLAYER_BUFF_WILLPOWER = 20, - PLAYER_BUFF_SPEED = 21, - PLAYER_BUFF_RESIST_WATER = 22, - PLAYER_BUFF_WATER_WALK = 23 -}; - - -#define PLAYER_GUILD_BITS__SPIRIT_MEMBERSHIP 58 -#define PLAYER_GUILD_BITS__ARCOMAGE_WIN 103 -#define PLAYER_GUILD_BITS__ARCOMAGE_LOSE 104 - - -/* 301 */ -enum PlayerSpeech -{ - SPEECH_1 = 1, - SPEECH_2 = 2, - SPEECH_3 = 3, - SPEECH_4 = 4, - SPEECH_5 = 5, - SPEECH_6 = 6, - SPEECH_7 = 7, - SPEECH_8 = 8, - SPEECH_9 = 9, - SPEECH_10 = 10, - SPEECH_11 = 11, - SPEECH_12 = 12, - SPEECH_14 = 14, - SPEECH_NoRoom = 15, // when placing to inventory - SPEECH_DO_POTION_FINE = 16, - SPEECH_17 = 17, - SPEECH_18 = 18, - SPEECH_19 = 19, - SPEECH_20 = 20, - SPEECH_21 = 21, - SPEECH_GoodDay = 22, // greets on dialogue start - SPEECH_GoodEvening = 23, - SPEECH_24 = 24, - SPEECH_25 = 25, - SPEECH_26 = 26, - SPEECH_27 = 27, - SPEECH_28 = 28, - SPEECH_29 = 29, - SPEECH_30 = 30, - SPEECH_31 = 31, - SPEECH_32 = 32, - SPEECH_33 = 33, - SPEECH_34 = 34, - SPEECH_35 = 35, - SPEECH_36 = 36, - SPEECH_37 = 37, - SPEECH_NotEnoughGold = 38, - SPEECH_39 = 39, - SPEECH_40 = 40, - SPEECH_41 = 41, - SPEECH_42 = 42, - SPEECH_43 = 43, - SPEECH_44 = 44, - SPEECH_45 = 45, - SPEECH_46 = 46, - SPEECH_47 = 47, - SPEECH_48 = 48, - SPEECH_49 = 49, - SPEECH_50 = 50, - SPEECH_51 = 51, - SPEECH_52 = 52, - SPEECH_53 = 53, - SPEECH_54 = 54, - SPEECH_55 = 55, - SPEECH_56 = 56, - SPEECH_57 = 57, - SPEECH_58 = 58, - SPEECH_59 = 59, - SPEECH_60 = 60, - SPEECH_61 = 61, - SPEECH_62 = 62, - SPEECH_63 = 63, - SPEECH_64 = 64, - SPEECH_Yell = 65, - SPEECH_Falling_scream = 66, - SPEECH_67 = 67, - SPEECH_68 = 68, - SPEECH_69 = 69, - SPEECH_70 = 70, - SPEECH_CarriageReady = 71, // travelling by carriage - SPEECH_SetSail = 72, // travelling by sea - SPEECH_73 = 73, - SPEECH_74 = 74, - SPEECH_75 = 75, - SPEECH_76 = 76, - SPEECH_77 = 77, - SPEECH_78 = 78, - SPEECH_79 = 79, - SPEECH_80 = 80, - SPEECH_81 = 81, - SPEECH_82 = 82, - SPEECH_83 = 83, - SPEECH_84 = 84, - SPEECH_85 = 85, - SPEECH_86 = 86, - SPEECH_87 = 87, - SPEECH_88 = 88, - SPEECH_89 = 89, - SPEECH_90 = 90, - SPEECH_91 = 91, - SPEECH_92 = 92, - SPEECH_93 = 93, - SPEECH_94 = 94, - SPEECH_95 = 95, - SPEECH_96 = 96, - SPEECH_97 = 97, - SPEECH_98 = 98, - SPEECH_99 = 99, - SPEECH_100 = 100, - SPEECH_101 = 101, - SPEECH_PickMe = 102, - SPEECH_103 = 103, - SPEECH_IDENTIFY_MONSTER_WEAKER = 104, - SPEECH_IDENTIFY_MONSTER_STRONGER = 105, - SPEECH_IDENTIFY_MONSTER_106 = 106, - SPEECH_107 = 107, - SPEECH_108 = 108, - SPEECH_109 = 109, - SPEECH_110 = 110, -}; - - - -/* 339 */ -enum CHARACTER_RACE -{ - CHARACTER_RACE_HUMAN = 0, - CHARACTER_RACE_ELF = 1, - CHARACTER_RACE_GOBLIN = 2, - CHARACTER_RACE_DWARF = 3, -}; - -/* 332 */ -enum CHARACTER_ATTRIBUTE_TYPE -{ - CHARACTER_ATTRIBUTE_STRENGTH = 0, - CHARACTER_ATTRIBUTE_INTELLIGENCE = 1, - CHARACTER_ATTRIBUTE_WILLPOWER = 2, - CHARACTER_ATTRIBUTE_ENDURANCE = 3, - CHARACTER_ATTRIBUTE_ACCURACY = 4, - CHARACTER_ATTRIBUTE_SPEED = 5, - CHARACTER_ATTRIBUTE_LUCK = 6, - CHARACTER_ATTRIBUTE_HEALTH = 7, - CHARACTER_ATTRIBUTE_MANA = 8, - CHARACTER_ATTRIBUTE_AC_BONUS = 9, - - CHARACTER_ATTRIBUTE_RESIST_FIRE = 10, - CHARACTER_ATTRIBUTE_RESIST_AIR = 11, - CHARACTER_ATTRIBUTE_RESIST_WATER = 12, - CHARACTER_ATTRIBUTE_RESIST_EARTH = 13, - CHARACTER_ATTRIBUTE_RESIST_MIND = 14, - CHARACTER_ATTRIBUTE_RESIST_BODY = 15, - - CHARACTER_ATTRIBUTE_SKILL_ALCHEMY = 16, - CHARACTER_ATTRIBUTE_SKILL_STEALING = 17, - CHARACTER_ATTRIBUTE_SKILL_TRAP_DISARM = 18, - CHARACTER_ATTRIBUTE_SKILL_ITEM_ID = 19, - CHARACTER_ATTRIBUTE_SKILL_MONSTER_ID = 20, - CHARACTER_ATTRIBUTE_SKILL_ARMSMASTER = 21, - CHARACTER_ATTRIBUTE_SKILL_DODGE = 22, - CHARACTER_ATTRIBUTE_SKILL_UNARMED = 23, - - CHARACTER_ATTRIBUTE_LEVEL = 24, - CHARACTER_ATTRIBUTE_ATTACK = 25, - CHARACTER_ATTRIBUTE_MELEE_DMG_BONUS = 26, - CHARACTER_ATTRIBUTE_MELEE_DMG_MIN = 27, - CHARACTER_ATTRIBUTE_MELEE_DMG_MAX = 28, - CHARACTER_ATTRIBUTE_RANGED_ATTACK = 29, - CHARACTER_ATTRIBUTE_RANGED_DMG_BONUS = 30, - CHARACTER_ATTRIBUTE_RANGED_DMG_MIN = 31, - CHARACTER_ATTRIBUTE_RANGED_DMG_MAX = 32, - CHARACTER_ATTRIBUTE_RESIST_SPIRIT = 33, - - CHARACTER_ATTRIBUTE_SKILL_FIRE = 34, - CHARACTER_ATTRIBUTE_SKILL_AIR = 35, - CHARACTER_ATTRIBUTE_SKILL_WATER = 36, - CHARACTER_ATTRIBUTE_SKILL_EARTH = 37, - CHARACTER_ATTRIBUTE_SKILL_SPIRIT = 38, - CHARACTER_ATTRIBUTE_SKILL_MIND = 39, - CHARACTER_ATTRIBUTE_SKILL_BODY = 40, - CHARACTER_ATTRIBUTE_SKILL_LIGHT = 41, - CHARACTER_ATTRIBUTE_SKILL_DARK = 42, - CHARACTER_ATTRIBUTE_SKILL_MEDITATION = 43, - CHARACTER_ATTRIBUTE_SKILL_BOW = 44, - CHARACTER_ATTRIBUTE_SKILL_SHIELD = 45, - CHARACTER_ATTRIBUTE_SKILL_LEARNING = 46 -}; - -#pragma warning( push ) -#pragma warning( disable: 4341 ) -/* 328 */ -enum PLAYER_SKILL_TYPE: signed __int8 -{ - PLAYER_SKILL_STAFF = 0, - PLAYER_SKILL_SWORD = 1, - PLAYER_SKILL_DAGGER = 2, - PLAYER_SKILL_AXE = 3, - PLAYER_SKILL_SPEAR = 4, - PLAYER_SKILL_BOW = 5, - PLAYER_SKILL_MACE = 6, - PLAYER_SKILL_BLASTER = 7, - PLAYER_SKILL_SHIELD = 8, - PLAYER_SKILL_LEATHER = 9, - PLAYER_SKILL_CHAIN = 10, - PLAYER_SKILL_PLATE = 11, - PLAYER_SKILL_FIRE = 12, - PLAYER_SKILL_AIR = 13, - PLAYER_SKILL_WATER = 14, - PLAYER_SKILL_EARTH = 15, - PLAYER_SKILL_SPIRIT = 16, - PLAYER_SKILL_MIND = 17, - PLAYER_SKILL_BODY = 18, - PLAYER_SKILL_LIGHT = 19, - PLAYER_SKILL_DARK = 20, - PLAYER_SKILL_ITEM_ID = 21, - PLAYER_SKILL_MERCHANT = 22, - PLAYER_SKILL_REPAIR = 23, - PLAYER_SKILL_BODYBUILDING = 24, - PLAYER_SKILL_MEDITATION = 25, - PLAYER_SKILL_PERCEPTION = 26, - PLAYER_SKILL_DIPLOMACY = 27, - PLAYER_SKILL_TIEVERY = 28, - PLAYER_SKILL_TRAP_DISARM = 29, - PLAYER_SKILL_DODGE = 30, - PLAYER_SKILL_UNARMED = 31, - PLAYER_SKILL_MONSTER_ID = 32, - PLAYER_SKILL_ARMSMASTER = 33, - PLAYER_SKILL_STEALING = 34, - PLAYER_SKILL_ALCHEMY = 35, - PLAYER_SKILL_LEARNING = 36, - PLAYER_SKILL_CLUB = 37, - PLAYER_SKILL_MISC = 38, - PLAYER_SKILL_INVALID = -1 -}; -#pragma warning( pop ) - -/* 329 */ -enum PLAYER_CLASS_TYPE: unsigned __int8 -{ - PLAYER_CLASS_KNIGHT = 0, - PLAYER_CLASS_CHEVALIER = 1, - PLAYER_CLASS_CHAMPION = 2, - PLAYER_CLASS_BLACK_KNIGHT = 3, - PLAYER_CLASS_THEIF = 4, - PLAYER_CLASS_ROGUE = 5, - PLAYER_CLASS_SPY = 6, - PLAYER_CLASS_ASSASSIN = 7, - PLAYER_CLASS_MONK = 8, - PLAYER_CLASS_INITIATE = 9, - PLAYER_CLASS_MASTER = 10, - PLAYER_CLASS_NINJA = 11, - PLAYER_CLASS_PALADIN = 12, - PLAYER_CLASS_CRUSADER = 13, - PLAYER_CLASS_HERO = 14, - PLAYER_CLASS_VILLIAN = 15, - PLAYER_CLASS_ARCHER = 16, - PLAYER_CLASS_WARRIOR_MAGE = 17, - PLAYER_CLASS_MASTER_ARCHER = 18, - PLAYER_CLASS_SNIPER = 19, - PLAYER_CLASS_RANGER = 20, - PLAYER_CLASS_HUNTER = 21, - PLAYER_CLASS_RANGER_LORD = 22, - PLAYER_CLASS_BOUNTY_HUNTER = 23, - PLAYER_CLASS_CLERIC = 24, - PLAYER_CLASS_PRIEST = 25, - PLAYER_CLASS_PRIEST_OF_SUN = 26, - PLAYER_CLASS_PRIEST_OF_MOON = 27, - PLAYER_CLASS_DRUID = 28, - PLAYER_CLASS_GREAT_DRUID = 29, - PLAYER_CLASS_ARCH_DRUID = 30, - PLAYER_CLASS_WARLOCK = 31, - PLAYER_CLASS_SORCERER = 32, - PLAYER_CLASS_WIZARD = 33, - PLAYER_CLASS_ARCHMAGE = 34, - PLAYER_CLASS_LICH = 35 -}; - - - - -#pragma pack(push, 1) -struct LloydBeacon -{ - unsigned __int64 uBeaconTime; - int PartyPos_X; - int PartyPos_Y; - int PartyPos_Z; - __int16 PartyRot_X; - __int16 PartyRot_Y; - int SaveFileID; -}; -#pragma pack(pop) - - - -#pragma pack(push, 1) -struct PlayerSpellbookChapter -{ - std::array<char, 11> bIsSpellAvailable; -}; -#pragma pack(pop) - -#pragma pack(push, 1) -struct PlayerSpells -{ - union - { - struct - { - PlayerSpellbookChapter pFireSpellbook; - PlayerSpellbookChapter pAirSpellbook; - PlayerSpellbookChapter pWaterSpellbook; - PlayerSpellbookChapter pEarthSpellbook; - PlayerSpellbookChapter pSpiritSpellbook; - PlayerSpellbookChapter pMindSpellbook; - PlayerSpellbookChapter pBodySpellbook; - PlayerSpellbookChapter pLightSpellbook; - PlayerSpellbookChapter pDarkSpellbook; - char _pad_0; - }; - struct - { - std::array<PlayerSpellbookChapter, 9> pChapters; - char _pad_1; - }; - struct - { - std::array<char, 99> bHaveSpell; - char _pad_1; - }; - }; -}; -#pragma pack(pop) - - - -#pragma pack(push, 1) -union PlayerEquipment -{ - union - { - struct - { - unsigned int uShield; - unsigned int uMainHand; - unsigned int uBow; - unsigned int uArmor; - unsigned int uHelm; - unsigned int uBelt; - unsigned int uCloak; - unsigned int uGlove; - unsigned int uBoot; - unsigned int uAmulet; - std::array<unsigned int, 6> uRings; - //unsigned int field_2C; - //unsigned int field_30; - //unsigned int field_34; - //unsigned int field_38; - //unsigned int field_3C; - }; - std::array<unsigned int, 16> pIndices; - }; -}; -#pragma pack(pop) - - - - - -enum CHARACTER_EXPRESSION_ID: unsigned __int16 -{ - CHARACTER_EXPRESSION_INVALID = 0, - CHARACTER_EXPRESSION_1 = 1, - CHARACTER_EXPRESSION_CURSED = 2, - CHARACTER_EXPRESSION_WEAK = 3, - CHARACTER_EXPRESSION_SLEEP = 4, - CHARACTER_EXPRESSION_FEAR = 5, - CHARACTER_EXPRESSION_DRUNK = 6, - CHARACTER_EXPRESSION_INSANE = 7, - CHARACTER_EXPRESSION_POISONED = 8, - CHARACTER_EXPRESSION_DISEASED = 9, - CHARACTER_EXPRESSION_PARALYZED = 10, - CHARACTER_EXPRESSION_UNCONCIOUS = 11, - CHARACTER_EXPRESSION_PERTIFIED = 12, - CHARACTER_EXPRESSION_13 = 13, - CHARACTER_EXPRESSION_14 = 14, - CHARACTER_EXPRESSION_15 = 15, - CHARACTER_EXPRESSION_16 = 16, - CHARACTER_EXPRESSION_17 = 17, - CHARACTER_EXPRESSION_18 = 18, - CHARACTER_EXPRESSION_19 = 19, - CHARACTER_EXPRESSION_20 = 20, - CHARACTER_EXPRESSION_21 = 21, - CHARACTER_EXPRESSION_22 = 22, - CHARACTER_EXPRESSION_23 = 23, - CHARACTER_EXPRESSION_24 = 24, - CHARACTER_EXPRESSION_25 = 25, - CHARACTER_EXPRESSION_26 = 26, - CHARACTER_EXPRESSION_27 = 27, - CHARACTER_EXPRESSION_28 = 28, - CHARACTER_EXPRESSION_29 = 29, - CHARACTER_EXPRESSION_30 = 30, - CHARACTER_EXPRESSION_31 = 31, - CHARACTER_EXPRESSION_32 = 32, - CHARACTER_EXPRESSION_33 = 33, - CHARACTER_EXPRESSION_DMGRECVD_MINOR = 34, - CHARACTER_EXPRESSION_DMGRECVD_MODERATE = 35, - CHARACTER_EXPRESSION_DMGRECVD_MAJOR = 36, - CHARACTER_EXPRESSION_37 = 37, - CHARACTER_EXPRESSION_38 = 38, - CHARACTER_EXPRESSION_39 = 39, - - // ? - - CHARACTER_EXPRESSION_SCARED = 46, // like falling - - CHARACTER_EXPRESSION_54 = 54, - CHARACTER_EXPRESSION_55 = 55, - CHARACTER_EXPRESSION_56 = 56, - CHARACTER_EXPRESSION_57 = 57, - CHARACTER_EXPRESSION_FALLING = 58, - - // ? - - CHARACTER_EXPRESSION_DEAD = 98, - CHARACTER_EXPRESSION_ERADICATED = 99, -}; - - -enum PLAYER_SEX: unsigned __int8 -{ - SEX_MALE = 0, - SEX_FEMALE = 1 -}; - -#pragma pack(push, 1) -struct Player -{ - static const unsigned int INVETORYSLOTSWIDTH = 14; - static const unsigned int INVETORYSLOTSHEIGHT = 9; - - - Player(); - - void SetVariable(enum VariableType var, signed int a3); - void AddVariable(enum VariableType var, signed int val); - void SubtractVariable(enum VariableType VarNum, signed int pValue); - bool CompareVariable(enum VariableType VarNum, signed int pValue); - void UseItem_DrinkPotion_etc(signed int a2, int a3); - bool AddItem(struct ItemGen *pItem); - int GetActualAttribute(CHARACTER_ATTRIBUTE_TYPE attrId, unsigned short Player::* attrValue, unsigned short Player::* attrBonus); - int GetBaseStrength(); - int GetBaseIntelligence(); - int GetBaseWillpower(); - int GetBaseEndurance(); - int GetBaseAccuracy(); - int GetBaseSpeed(); - int GetBaseLuck(); - int GetBaseLevel(); - int GetActualLevel(); - int GetActualMight(); - int GetActualIntelligence(); - int GetActualWillpower(); - int GetActualEndurance(); - int GetActualAccuracy(); - int GetActualSpeed(); - int GetActualLuck(); - int GetActualAttack(bool a2); - int GetMeleeDamageMinimal(); - int GetMeleeDamageMaximal(); - int CalculateMeleeDamageTo(bool ignoreSkillBonus, bool ignoreOffhand, unsigned int uTargetActorID); - int GetRangedAttack(); - int GetRangedDamageMin(); - int GetRangedDamageMax(); - int CalculateRangedDamageTo(int a2); - char *GetMeleeDamageString(); - char *GetRangedDamageString(); - bool CanTrainToNextLevel(); - unsigned int GetExperienceDisplayColor(); - int CalculateIncommingDamage(DAMAGE_TYPE dmg_type, int amount); - ITEM_EQUIP_TYPE GetEquippedItemEquipType(ITEM_EQUIP_TYPE uEquipSlot); - PLAYER_SKILL_TYPE GetEquippedItemSkillType(ITEM_EQUIP_TYPE uEquipSlot); - bool IsUnarmed(); - bool HasItemEquipped(ITEM_EQUIP_TYPE uEquipIndex); - bool HasEnchantedItemEquipped(int uEnchantment); - bool WearsItem(int item_id, ITEM_EQUIP_TYPE equip_type); - int StealFromShop( ItemGen *itemToSteal, int a3, int reputation, int a5, int *fineIfFailed); - int StealFromActor(unsigned int uActorID, int _steal_perm, int reputation); - void Heal(int amount); - int ReceiveDamage(signed int amount, DAMAGE_TYPE dmg_type); - int ReceiveSpecialAttackEffect(int attType, struct Actor *pActor); - unsigned int GetSpellSchool(unsigned int uSpellID); - int GetAttackRecoveryTime(bool bRangedAttack); - int GetMaxHealth(); - int GetMaxMana(); - int GetBaseAC(); - int GetActualAC(); - unsigned int GetBaseAge(); - unsigned int GetActualAge(); - int GetBaseResistance(enum CHARACTER_ATTRIBUTE_TYPE a2); - int GetActualResistance(enum CHARACTER_ATTRIBUTE_TYPE a2); - void SetRecoveryTime(signed int sRecoveryTime); - void RandomizeName(); - unsigned int GetMajorConditionIdx(); - int GetParameterBonus(int player_parameter); - int GetSpecialItemBonus(int enchantmentId); - int GetItemsBonus(enum CHARACTER_ATTRIBUTE_TYPE attr, bool a3 = false); - int GetMagicalBonus(enum CHARACTER_ATTRIBUTE_TYPE a2); - int GetActualSkillLevel(PLAYER_SKILL_TYPE uSkillType); - int GetSkillBonus(enum CHARACTER_ATTRIBUTE_TYPE a2); - enum CHARACTER_RACE GetRace(); - PLAYER_SEX GetSexByVoice(); - void SetInitialStats(); - void SetSexByVoice(); - void Reset(PLAYER_CLASS_TYPE classType); - PLAYER_SKILL_TYPE GetSkillIdxByOrder(signed int order); - void DecreaseAttribute(int eAttribute); - void IncreaseAttribute(int eAttribute); - void Player::Zero(); - unsigned int GetStatColor(int uStat); - bool DiscardConditionIfLastsLongerThan(unsigned int uCondition, signed __int64 uTime); - int SelectPhrasesTransaction(ItemGen *pItem, int building_type, int BuildID_2Events, int a5); - int GetBodybuilding(); - int GetMeditation(); - bool CanIdentify(ItemGen *pItem); - bool CanRepair(ItemGen *pItem); - int GetMerchant(); - int GetPerception(); - int GetDisarmTrap(); - char GetLearningPercent(); - bool CanFitItem(unsigned int uSlot, unsigned int uItemID); - int FindFreeInventoryListSlot(); - int CreateItemInInventory(unsigned int uSlot, unsigned int uItemID); - int HasSkill(unsigned int uSkillType); - void WearItem(unsigned int uItemID); - int AddItem(int uSlot, unsigned int uItemID); - int AddItem2(int uSlot, ItemGen *Src); - int CreateItemInInventory2(unsigned int index, ItemGen *Src); - void PutItemArInventoryIndex(int uItemID, int itemListPos, int uSlot); - void RemoveItemAtInventoryIndex(unsigned int uSlot); - bool CanAct(); - bool CanSteal(); - bool CanEquip_RaceAndAlignmentCheck(unsigned int uItemID); - void SetCondition(unsigned int uConditionIdx, int a3); - bool ProfessionOrGuildFlagsCorrect(unsigned int uClass, int a3); - void PlaySound(PlayerSpeech speech, int a3); - void PlayEmotion(CHARACTER_EXPRESSION_ID expression, int a3); - void ItemsEnchant(int enchant_count); - unsigned int GetItemIDAtInventoryIndex(int *a2); - bool IsPlayerHealableByTemple(); - int GetBaseIdentifyPrice(float a2); - int GetBaseRepairPrice(int a2, float a3); - int GetBaseBuyingPrice(int a2, float a3); - int GetBaseSellingPrice(int a2, float a3); - int GetPriceRepair(int a2, float a3); - int GetPriceIdentification(float a2); - int GetBuyingPrice(unsigned int uRealValue, float price_multiplier); - int GetPriceSell(int uRealValue, float price_multiplier); - int GetTempleHealCostModifier(float a2); - int GetConditionDayOfWeek(unsigned int uCondition); - bool NothingOrJustBlastersEquipped(); - void SalesProcess(unsigned int inventory_idnx, int item_index, int _2devent_idx);//0x4BE2DD - bool Recover(signed int a2); - bool CanCastSpell(unsigned int uRequiredMana); - void PlayAwardSound(); - void EquipBody(ITEM_EQUIP_TYPE uEquipType); - bool HasUnderwaterSuitEquipped(); - bool HasItem(unsigned int uItemID, bool checkHeldItem); - void OnInventoryLeftClick(); - - bool PlayerHitOrMiss(Actor *pActor, int a3, int a4); - - unsigned int GetMultiplierForSkillLevel(unsigned int skillValue, int mult1, int mult2, int mult3, int mult4); - int CalculateMeleeDmgToEnemyWithWeapon( ItemGen * weapon, unsigned int uTargetActorID , bool addOneDice); - bool WearsItemAnyWhere(int item_id); - float GetArmorRecoveryMultiplierFromSkillLevel( unsigned char armour_skill_type, float param2, float param3, float param4, float param5 ); - void SetSkillByEvent(unsigned __int16 Player::* skillToSet, unsigned __int16 skillValue); - void AddSkillByEvent( unsigned __int16 Player::* skillToSet, unsigned __int16 addSkillValue); - void PlayAwardSound_Anim(); - void PlayAwardSound_Anim_Face(PlayerSpeech speech); - void PlayAwardSound_Anim97(); - void PlayAwardSound_Anim97_Face(PlayerSpeech speech); - void PlayAwardSound_Anim98(); - void PlayAwardSound_Anim98_Face(PlayerSpeech speech); - - bool IsWeak(); - bool IsDead(); - bool IsEradicated(); - bool IsZombie(); - bool IsCursed(); - bool IsPertified(); - bool IsUnconcious(); - bool IsAsleep(); - bool IsParalyzed(); - bool IsDrunk(); - - void SetCursed(unsigned long long state); - void SetWeak(unsigned long long state); - void SetAsleep(unsigned long long state); - void SetAfraid(unsigned long long state); - void SetDrunk(unsigned long long state); - void SetInsane(unsigned long long state); - void SetPoisonWeak(unsigned long long state); - void SetDiseaseWeak(unsigned long long state); - void SetPoisonMedium(unsigned long long state); - void SetDiseaseMedium(unsigned long long state); - void SetPoisonSevere(unsigned long long state); - void SetDiseaseSevere(unsigned long long state); - void SetParalyzed(unsigned long long state); - void SetUnconcious(unsigned long long state); - void SetDead(unsigned long long state); - void SetPertified(unsigned long long state); - void SetEradicated(unsigned long long state); - void SetZombie(unsigned long long state); - - void SetCondWeakWithBlockCheck (int blockable); - void SetCondInsaneWithBlockCheck (int blockable); - void SetCondDeadWithBlockCheck (int blockable); - void SetCondUnconsciousWithBlockCheck( int blockable ); - - inline bool IsRaceHuman() {return GetRace() == CHARACTER_RACE_HUMAN;} - inline bool IsRaceDwarf() {return GetRace() == CHARACTER_RACE_DWARF;} - inline bool IsRaceElf() {return GetRace() == CHARACTER_RACE_ELF;} - inline bool IsRaceGoblin() {return GetRace() == CHARACTER_RACE_GOBLIN;} - - inline bool IsMale() { return GetSexByVoice() == SEX_MALE;} - inline bool IsFemale() { return !IsMale();} - - ItemGen* GetMainHandItem(); - ItemGen* GetOffHandItem(); - ItemGen* GetBowItem(); - ItemGen* GetArmorItem(); - ItemGen* GetHelmItem(); - ItemGen* GetBeltItem(); - ItemGen* GetCloakItem(); - ItemGen* GetGloveItem(); - ItemGen* GetBootItem(); - ItemGen* GetAmuletItem(); - ItemGen* GetNthRingItem(int ringNum); - ItemGen* GetNthEquippedIndexItem(int index); - ItemGen* GetItem(unsigned int PlayerEquipment::* itemPos); - int GetPlayerIndex(); - - static void _42ECB5_PlayerAttacksActor(); - static void _42FA66_do_explosive_impact(int a1, int a2, int a3, int a4, __int16 a5, signed int a6); - - std::array<__int64, 20> pConditions; - unsigned __int64 uExperience; - char pName[16]; - PLAYER_SEX uSex; - PLAYER_CLASS_TYPE classType; - unsigned __int8 uCurrentFace; - char field_BB; - unsigned __int16 uMight; - unsigned __int16 uMightBonus; - unsigned __int16 uIntelligence; - unsigned __int16 uIntelligenceBonus; - unsigned __int16 uWillpower; - unsigned __int16 uWillpowerBonus; - unsigned __int16 uEndurance; - unsigned __int16 uEnduranceBonus; - unsigned __int16 uSpeed; - unsigned __int16 uSpeedBonus; - unsigned __int16 uAccuracy; - unsigned __int16 uAccuracyBonus; - unsigned __int16 uLuck; - unsigned __int16 uLuckBonus; - __int16 sACModifier; - unsigned __int16 uLevel; - __int16 sLevelModifier; - __int16 sAgeModifier; - int field_E0; - int field_E4; - int field_E8; - int field_EC; - int field_F0; - int field_F4; - int field_F8; - int field_FC; - int field_100; - int field_104; - union - { - struct - { - unsigned __int16 skillStaff; - unsigned __int16 skillSword; - unsigned __int16 skillDagger; - unsigned __int16 skillAxe; - unsigned __int16 skillSpear; - unsigned __int16 skillBow; - unsigned __int16 skillMace; - unsigned __int16 skillBlaster; - unsigned __int16 skillShield; - unsigned __int16 skillLeather; - unsigned __int16 skillChain; - unsigned __int16 skillPlate; - unsigned __int16 skillFire; - unsigned __int16 skillAir; - unsigned __int16 skillWater; - unsigned __int16 skillEarth; - unsigned __int16 skillSpirit; - unsigned __int16 skillMind; - unsigned __int16 skillBody; - unsigned __int16 skillLight; - unsigned __int16 skillDark; - unsigned __int16 skillItemId; - unsigned __int16 skillMerchant; - unsigned __int16 skillRepair; - unsigned __int16 skillBodybuilding; - unsigned __int16 skillMeditation; - unsigned __int16 skillPerception; - unsigned __int16 skillDiplomacy; - unsigned __int16 skillThievery; - unsigned __int16 skillDisarmTrap; - unsigned __int16 skillDodge; - unsigned __int16 skillUnarmed; - unsigned __int16 skillMonsterId; - unsigned __int16 skillArmsmaster; - unsigned __int16 skillStealing; - unsigned __int16 skillAlchemy; - unsigned __int16 skillLearning; - }; - std::array<unsigned __int16, 37> pActiveSkills; - }; - unsigned char _achieved_awards_bits[64]; - PlayerSpells spellbook; - char field__1F5[2]; // used to be [31] - int pure_luck_used; - int pure_speed_used; - int pure_intellect_used; - int pure_endurance_used; - int pure_willpower_used; - int pure_accuracy_used; - int pure_might_used; - union //214h - { - struct - { - std::array<ItemGen, 126> pInventoryItemList; - std::array<ItemGen, 12> pEquippedItems; - }; - std::array<ItemGen, 138> pOwnItems; - }; - - std::array<int, 126> pInventoryMatrix; - __int16 sResFireBase; - __int16 sResAirBase; - __int16 sResWaterBase; - __int16 sResEarthBase; - __int16 field_177C; - __int16 sResMagicBase; - __int16 sResSpiritBase; - __int16 sResMindBase; - __int16 sResBodyBase; - __int16 sResLightBase; - __int16 sResDarkBase; - __int16 sResFireBonus; - __int16 sResAirBonus; - __int16 sResWaterBonus; - __int16 sResEarthBonus; - __int16 field_1792; - __int16 sResMagicBonus; - __int16 sResSpiritBonus; - __int16 sResMindBonus; - __int16 sResBodyBonus; - __int16 sResLightBonus; - __int16 sResDarkBonus; - std::array<SpellBuff, 24> pPlayerBuffs; - unsigned int uVoiceID; - int uPrevVoiceID; - int uPrevFace; - int field_192C; - int field_1930; - unsigned __int16 uTimeToRecovery; - char field_1936; - char field_1937; - unsigned int uSkillPoints; - int sHealth; - int sMana; - unsigned int uBirthYear; - PlayerEquipment pEquipment; - int field_1988[49]; - char field_1A4C; - char field_1A4D; - char lastOpenedSpellbookPage; - unsigned __int8 uQuickSpell; - char playerEventBits[64]; - char _some_attack_bonus; - char field_1A91; - char _melee_dmg_bonus; - char field_1A93; - char _ranged_atk_bonus; - char field_1A95; - char _ranged_dmg_bonus; - char field_1A97; - char uFullHealthBonus; - char _health_related; - char uFullManaBonus; - char _mana_related; - CHARACTER_EXPRESSION_ID expression; - unsigned __int16 uExpressionTimePassed; - unsigned __int16 uExpressionTimeLength; - __int16 field_1AA2; - int _expression21_animtime; - int _expression21_frameset; - std::array<LloydBeacon, 5> pInstalledBeacons; - char uNumDivineInterventionCastsThisDay; - char uNumArmageddonCasts; - char uNumFireSpikeCasts; - char field_1B3B; -}; -#pragma pack(pop) - -void __fastcall DamagePlayerFromMonster(unsigned int uObjID, int a2, struct Vec3_int_ *pPos, signed int a4); -bool IsDwarfPresentInParty(bool b); -bool ShouldLoadTexturesForRaceAndGender(unsigned int _this); -int PlayerCreation_GetUnspentAttributePointCount(); -int CycleCharacter(bool backwards); -unsigned int SkillToMastery(unsigned int skill_value); - -extern NZIArray<struct Player *, 5> pPlayers; \ No newline at end of file
--- a/Player.swig Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -%module Player -%{ - #include "Player.h" -%} - -%include "../../../Player.h" \ No newline at end of file
--- a/SpriteObject.cpp Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1975 +0,0 @@ -#define _CRTDBG_MAP_ALLOC -#include <stdlib.h> -#include <crtdbg.h> - -#define _CRT_SECURE_NO_WARNINGS -#include "Engine/Graphics/Sprites.h" -#include "Engine/Graphics/BSPModel.h" -#include "SpriteObject.h" -#include "Party.h" -#include "TurnEngine.h" -#include "OurMath.h" -#include "ObjectList.h" -#include "Engine/Graphics/Outdoor.h" -#include "Engine/Graphics/ParticleEngine.h" -#include "Timer.h" -#include "Game.h" -#include "LOD.h" -#include "Actor.h" -#include "Events.h" -#include "AudioPlayer.h" -#include "Engine/Graphics/Level/Decoration.h" - -#include "MM7.h" - -#include "stru298.h" -#include "Random.h" - - - - - - - - -size_t uNumSpriteObjects; -std::array<SpriteObject, MAX_SPRITE_OBJECTS> pSpriteObjects; - -//----- (00404828) -------------------------------------------------------- -SpriteObject::SpriteObject() -{ - field_22_glow_radius_multiplier = 1; - uSoundID = 0; - uFacing = 0; - vVelocity.z = 0; - vVelocity.y = 0; - vVelocity.x = 0; - uType = 0; - uObjectDescID = 0; - field_61 = 0; - field_60_distance_related_prolly_lod = 0; - field_20 = 0; - uSpriteFrameID = 0; - spell_skill = 0; - spell_level = 0; - spell_id = 0; - field_54 = 0; -} - -//----- (0042F5ED) -------------------------------------------------------- -int SpriteObject::Create(int yaw, int pitch, int a4, int a5) -{ - signed int v6; // ebx@2 - int v13; // ST2C_4@20 - Vec3_int_ v17; // [sp-20h] [bp-30h]@11 - int angle; // [sp+Ch] [bp-4h]@1 - int a5a; // [sp+20h] [bp+10h]@20 - - angle = yaw; - if (!uObjectDescID) - return -1; - - v6 = 1000; - for (uint i = 0; i < MAX_SPRITE_OBJECTS; ++i) - if (!pSpriteObjects[i].uObjectDescID) - { - v6 = i; - break; - } - - if ( v6 >= 1000 ) - return -1; - field_64.x = vPosition.x; - field_64.y = vPosition.y; - field_64.z = vPosition.z; - - assert(sizeof(SpriteObject) == 0x70); - - switch (a5) - { - case 0: - break; //do nothing - case 1: - Vec3_int_::Rotate(24, stru_5C6E00->uIntegerHalfPi + uFacing, 0, vPosition, &vPosition.x, - &vPosition.y, &vPosition.z); - break; - case 2: - Vec3_int_::Rotate(8, stru_5C6E00->uIntegerHalfPi + uFacing, 0, vPosition, &vPosition.x, - &vPosition.y, &vPosition.z); - break; - case 3: - Vec3_int_::Rotate(8, uFacing - stru_5C6E00->uIntegerHalfPi, 0, vPosition, &vPosition.x, - &vPosition.y, &vPosition.z); - break; - case 4: - Vec3_int_::Rotate(24, uFacing - stru_5C6E00->uIntegerHalfPi, 0, vPosition, &vPosition.x, - &vPosition.y, &vPosition.z); - break; - default: - assert(false); - return 0; - break; - } - - if ( a4 ) - { - v13 = fixpoint_mul(stru_5C6E00->Cos(angle), stru_5C6E00->Cos(pitch)); - a5a = fixpoint_mul(stru_5C6E00->Sin(angle), stru_5C6E00->Cos(pitch)); - vVelocity.x = fixpoint_mul(v13, a4); - vVelocity.y = fixpoint_mul(a5a, a4); - vVelocity.z = fixpoint_mul(stru_5C6E00->Sin(pitch), a4); - } - else - { - vVelocity.y = 0; - vVelocity.x = 0; - vVelocity.z = 0; - } - - memcpy(&pSpriteObjects[v6], this, sizeof(*this)); - if ( v6 >= (signed int)uNumSpriteObjects ) - uNumSpriteObjects = v6 + 1; - return v6; -} - -//----- (00471C03) -------------------------------------------------------- -void SpriteObject::UpdateObject_fn0_ODM(unsigned int uLayingItemID) -{ - ObjectDesc *object; // ebx@1 - int v6; // eax@1 - int v7; // ecx@1 - int v8; // edi@1 - int v9; // eax@4 -// int v17; // ST10_4@25 - //signed int v19; // eax@28 - //Actor *v20; // edi@31 - int v21; // eax@41 -// int v22; // ecx@43 -// __int16 v23; // bx@45 -// char v24; // al@46 - signed int i; // edi@50 - int v26; // edi@52 - int v27; // eax@52 - __int16 v28; // cx@55 - int v29; // eax@55 - //signed int v30; // edi@59 - BSPModel *bmodel; // ecx@61 - ODMFace *face; // edi@61 -// int v33; // eax@62 -// int v34; // ecx@62 - int v35; // eax@63 - int v36; // ecx@67 - __int16 v37; // ax@67 - int v38; // eax@72 - //int v39; // eax@72 -// unsigned __int64 v40; // qax@72 -// int v41; // eax@72 -// unsigned __int8 v42; // sf@74 -// unsigned __int8 v43; // of@74 - int v44; // eax@77 -// __int16 v45; // bx@81 -// int v46; // eax@85 -// const char *v47; // [sp-8h] [bp-B0h]@83 -// enum TEXTURE_TYPE v48; // [sp-4h] [bp-ACh]@46 - int v49; // [sp+Ch] [bp-9Ch]@52 - int v50; // [sp+10h] [bp-98h]@52 - Vec3_int_ v51; // [sp+14h] [bp-94h]@11 - Particle_sw Dst; // [sp+20h] [bp-88h]@45 - int v54; // [sp+8Ch] [bp-1Ch]@1 - int v55; // [sp+90h] [bp-18h]@1 - int v56; // [sp+94h] [bp-14h]@11 - int v57; // [sp+98h] [bp-10h]@1 - int v58; // [sp+9Ch] [bp-Ch]@1 - int on_water; // [sp+A0h] [bp-8h]@1 - int v60; // [sp+A4h] [bp-4h]@11 - - v58 = 0; - object = &pObjectList->pObjects[pSpriteObjects[uLayingItemID].uObjectDescID]; - v57 = IsTerrainSlopeTooHigh(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y); - v55 = 0; - v6 = ODM_GetFloorLevel(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uHeight, &on_water, &v55, 0); - v7 = v6; - v54 = v6; - v8 = v6 + 1; - if ( pSpriteObjects[uLayingItemID].vPosition.z <= v6 + 1 ) - { - if ( on_water ) - { - v9 = v6 + 60; - if ( v55 ) - v9 = v6 + 30; - sub_42F960_create_object(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, v9); - SpriteObject::OnInteraction(uLayingItemID); - } - } - else - v58 = 1; - if ( !(object->uFlags & OBJECT_DESC_NO_GRAVITY) ) - { - if ( v58 ) - { - pSpriteObjects[uLayingItemID].vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); - goto LABEL_13; - } - if ( v57 ) - { - pSpriteObjects[uLayingItemID].vPosition.z = v8; - ODM_GetTerrainNormalAt(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, &v51); - pSpriteObjects[uLayingItemID].vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); - v56 = abs(v51.y * pSpriteObjects[uLayingItemID].vVelocity.y + v51.z * pSpriteObjects[uLayingItemID].vVelocity.z + v51.x * pSpriteObjects[uLayingItemID].vVelocity.x) >> 16; - //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.x) >> 16); - pSpriteObjects[uLayingItemID].vVelocity.x += fixpoint_mul(v56, v51.x); - //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.y) >> 16); - pSpriteObjects[uLayingItemID].vVelocity.y += fixpoint_mul(v56, v51.y); - //v60 = ((unsigned __int64)(v56 * (signed __int64)v51.z) >> 16); - pSpriteObjects[uLayingItemID].vVelocity.z += fixpoint_mul(v56, v51.z); - v7 = v54; - goto LABEL_13; - } - if ( object->uFlags & OBJECT_DESC_INTERACTABLE ) - { - if ( pSpriteObjects[uLayingItemID].vPosition.z < v7 ) - pSpriteObjects[uLayingItemID].vPosition.z = v8; - if ( !_46BFFA_check_object_intercept(uLayingItemID, 0) ) - return; - } - pSpriteObjects[uLayingItemID].vPosition.z = v8; - if ( !(object->uFlags & OBJECT_DESC_BOUNCE) || (v21 = -pSpriteObjects[uLayingItemID].vVelocity.z >> 1, pSpriteObjects[uLayingItemID].vVelocity.z = v21, (signed __int16)v21 < 10) ) - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - - pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.x); - pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.y); - pSpriteObjects[uLayingItemID].vVelocity.z = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.z); - if ( (pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y - + pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x) < 400 ) - { - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - memset(&Dst, 0, 0x68u); - Dst.x = (double)pSpriteObjects[uLayingItemID].vPosition.x; - Dst.y = (double)pSpriteObjects[uLayingItemID].vPosition.y; - Dst.z = (double)pSpriteObjects[uLayingItemID].vPosition.z; - Dst.r = 0.0; - Dst.g = 0.0; - Dst.b = 0.0; - if (object->uFlags & OBJECT_DESC_TRIAL_FIRE ) - { - Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; - Dst.uDiffuse = 0xFF3C1E; - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - } - else if ( object->uFlags & OBJECT_DESC_TRIAL_LINE) - { - Dst.type = ParticleType_Line; - Dst.uDiffuse = rand(); - Dst.timeToLive = 64; - Dst.uTextureID = 0; - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - } - else if ( object->uFlags & OBJECT_DESC_TRIAL_PARTICLE ) - { - Dst.type = ParticleType_Bitmap | ParticleType_8; - Dst.uDiffuse = rand(); - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - } - return; - } - } -LABEL_13: - if ( pSpriteObjects[uLayingItemID].vPosition.x >= -0x8000 && pSpriteObjects[uLayingItemID].vPosition.x <= 0x8000 - && pSpriteObjects[uLayingItemID].vPosition.y >= -0x8000 && pSpriteObjects[uLayingItemID].vPosition.y <= 0x8000 - && pSpriteObjects[uLayingItemID].vPosition.z > v7 && pSpriteObjects[uLayingItemID].vPosition.z <= 13000 - || !(object->uFlags & OBJECT_DESC_INTERACTABLE) ) - goto LABEL_92; - if ( pSpriteObjects[uLayingItemID].vPosition.z < v7 ) - pSpriteObjects[uLayingItemID].vPosition.z = v8; - if ( _46BFFA_check_object_intercept(uLayingItemID, 0) ) - { -LABEL_92: - stru_721530.field_0 = 0; - stru_721530.prolly_normal_d = object->uRadius; - stru_721530.height = object->uHeight; - stru_721530.field_8_radius = 0; - stru_721530.field_70 = 0; - for ( v55 = 0; v55 < 100; ++v55 ) - { - stru_721530.position.x = pSpriteObjects[uLayingItemID].vPosition.x; - stru_721530.normal.x = stru_721530.position.x; - stru_721530.uSectorID = 0; - stru_721530.position.y = pSpriteObjects[uLayingItemID].vPosition.y; - stru_721530.normal.y = pSpriteObjects[uLayingItemID].vPosition.y; - stru_721530.position.z = pSpriteObjects[uLayingItemID].vPosition.z + stru_721530.prolly_normal_d + 1; - stru_721530.normal.z = stru_721530.position.z; - stru_721530.velocity.x = pSpriteObjects[uLayingItemID].vVelocity.x; - stru_721530.velocity.y = pSpriteObjects[uLayingItemID].vVelocity.y; - stru_721530.velocity.z = pSpriteObjects[uLayingItemID].vVelocity.z; - if ( stru_721530._47050A(0) ) - return; - _46E889_collide_against_bmodels(0); - _46E26D_collide_against_sprites(WorldPosToGridCellX(pSpriteObjects[uLayingItemID].vPosition.x), WorldPosToGridCellZ(pSpriteObjects[uLayingItemID].vPosition.y)); - if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) != OBJECT_Player) - _46EF01_collision_chech_player(0); - if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Actor) - { - if (( PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) >= 0 ) - &&( PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) < (signed int)(uNumActors - 1) )) - { - for (v56 =0; v56 < uNumActors; ++v56) - { - if ( pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].GetActorsRelation(&pActors[v56]) ) - Actor::_46DF1A_collide_against_actor(v56, 0); - } - } - } - else - { - for ( i = 0; i < (signed int)uNumActors; ++i ) - Actor::_46DF1A_collide_against_actor(i, 0); - } - v26 = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; - v27 = ODM_GetFloorLevel( stru_721530.normal2.x, stru_721530.normal2.y, stru_721530.normal2.z - stru_721530.prolly_normal_d - 1, - object->uHeight, &v49, &v50, 0); - if ( on_water && v26 < v27 + 60 ) - { - if ( v50 ) - v44 = v27 + 30; - else - v44 = v54 + 60; - sub_42F960_create_object(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, v44); - SpriteObject::OnInteraction(uLayingItemID); - return; - } - if ( stru_721530.field_7C >= stru_721530.field_6C ) - { - pSpriteObjects[uLayingItemID].vPosition.x = stru_721530.normal2.x; - pSpriteObjects[uLayingItemID].vPosition.y = stru_721530.normal2.y; - pSpriteObjects[uLayingItemID].vPosition.z = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; - pSpriteObjects[uLayingItemID].uSectorID = LOWORD(stru_721530.uSectorID); - memset(&Dst, 0, 0x68u); - Dst.x = (double)pSpriteObjects[uLayingItemID].vPosition.x; - Dst.y = (double)pSpriteObjects[uLayingItemID].vPosition.y; - Dst.z = (double)pSpriteObjects[uLayingItemID].vPosition.z; - Dst.r = 0.0; - Dst.g = 0.0; - Dst.b = 0.0; - if ( object->uFlags & OBJECT_DESC_TRIAL_FIRE ) - { - Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; - Dst.uDiffuse = 0xFF3C1E; - Dst.timeToLive = (unsigned __int8)( rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( object->uFlags & OBJECT_DESC_TRIAL_LINE ) - { - Dst.type = ParticleType_Line; - Dst.uTextureID = 0; - Dst.uDiffuse = rand(); - Dst.timeToLive = 64; - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - { - Dst.type = ParticleType_Bitmap | ParticleType_8; - Dst.uDiffuse = rand(); - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - } - return; - } - //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16); - pSpriteObjects[uLayingItemID].vPosition.x += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x); - //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16); - pSpriteObjects[uLayingItemID].vPosition.y += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y); - //v60 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16); - v28 = LOWORD(stru_721530.uSectorID); - pSpriteObjects[uLayingItemID].vPosition.z += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z); - v29 = pSpriteObjects[uLayingItemID].vPosition.z; - pSpriteObjects[uLayingItemID].uSectorID = v28; - stru_721530.field_70 += stru_721530.field_7C; - if ( object->uFlags & OBJECT_DESC_INTERACTABLE ) - { - if ( v29 < v54 ) - pSpriteObjects[uLayingItemID].vPosition.z = v54 + 1; - if ( !_46BFFA_check_object_intercept(uLayingItemID, stru_721530.uFaceID) ) - return; - } - if (PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration) - break; - if (PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel) - { - bmodel = &pOutdoor->pBModels[(signed int)stru_721530.uFaceID >> 9]; - face = &bmodel->pFaces[PID_ID(stru_721530.uFaceID) & 0x3F]; - if ( face->uPolygonType == POLYGON_Floor ) - { - pSpriteObjects[uLayingItemID].vPosition.z = bmodel->pVertices.pVertices[face->pVertexIDs[0]].z + 1; - if ( pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x - + pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y >= 400 ) - { - if ( face->uAttributes & FACE_UNKNOW2 ) - EventProcessor(face->sCogTriggeredID, 0, 1); - } - else - { - LOWORD(v35) = 0; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = v35; - } - } - else - { - v56 = abs(face->pFacePlane.vNormal.x * pSpriteObjects[uLayingItemID].vVelocity.x - + face->pFacePlane.vNormal.y * pSpriteObjects[uLayingItemID].vVelocity.y - + face->pFacePlane.vNormal.z * pSpriteObjects[uLayingItemID].vVelocity.z) >> 16; - if ( (stru_721530.speed >> 3) > v56 ) - v56 = stru_721530.speed >> 3; - //v57 = fixpoint_mul(v56, face->pFacePlane.vNormal.x); - //v58 = fixpoint_mul(v56, face->pFacePlane.vNormal.y); - v60 = fixpoint_mul(v56, face->pFacePlane.vNormal.z); - pSpriteObjects[uLayingItemID].vVelocity.x += 2 * fixpoint_mul(v56, face->pFacePlane.vNormal.x); - pSpriteObjects[uLayingItemID].vVelocity.y += 2 * fixpoint_mul(v56, face->pFacePlane.vNormal.y); - if ( face->pFacePlane.vNormal.z <= 32000 ) - v37 = 2 * (short)v60; - else - { - v36 = v60; - pSpriteObjects[uLayingItemID].vVelocity.z += (signed __int16)v60; - v58 = fixpoint_mul(0x7D00, v36); - v37 = fixpoint_mul(32000, v36); - } - pSpriteObjects[uLayingItemID].vVelocity.z += v37; - if ( face->uAttributes & FACE_UNKNOW2 ) - EventProcessor(face->sCogTriggeredID, 0, 1); - } - } -LABEL_74: - pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.x); - pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.y); - pSpriteObjects[uLayingItemID].vVelocity.z = fixpoint_mul(58500, pSpriteObjects[uLayingItemID].vVelocity.z); - } - v57 = integer_sqrt(pSpriteObjects[uLayingItemID].vVelocity.x * pSpriteObjects[uLayingItemID].vVelocity.x - + pSpriteObjects[uLayingItemID].vVelocity.y * pSpriteObjects[uLayingItemID].vVelocity.y); - v38 = stru_5C6E00->Atan2(pSpriteObjects[uLayingItemID].vPosition.x - pLevelDecorations[PID_ID(stru_721530.uFaceID)].vPosition.x, - pSpriteObjects[uLayingItemID].vPosition.y - pLevelDecorations[PID_ID(stru_721530.uFaceID)].vPosition.y); - pSpriteObjects[uLayingItemID].vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v38), v57); - pSpriteObjects[uLayingItemID].vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v38 - stru_5C6E00->uIntegerHalfPi), v57); - goto LABEL_74; - } -} - -//----- (0047136C) -------------------------------------------------------- -void SpriteObject::UpdateObject_fn0_BLV(unsigned int uLayingItemID) -{ - SpriteObject *pSpriteObject; // esi@1 - ObjectDesc *pObject; // edi@1 -// int v9; // ecx@16 -// __int16 v10; // di@18 -// int v14; // ebx@34 - signed int v15; // ebx@46 - int v17; // eax@50 -// int v18; // eax@52 -// int v19; // ecx@52 -// Vec3_short_ *v20; // ecx@53 - __int16 v22; // ax@57 - int v23; // edi@62 -// unsigned __int8 v27; // sf@64 -// unsigned __int8 v28; // of@64 -// __int16 v29; // di@67 -// char v30; // al@68 - Particle_sw Dst; // [sp+Ch] [bp-84h]@18 - unsigned int uFaceID; // [sp+7Ch] [bp-14h]@4 - int v39; // [sp+80h] [bp-10h]@33 - int v40; // [sp+84h] [bp-Ch]@28 - int v42; // [sp+8Ch] [bp-4h]@4 - - pSpriteObject = &pSpriteObjects[uLayingItemID]; - pObject = &pObjectList->pObjects[pSpriteObject->uObjectDescID]; - pSpriteObject->uSectorID = pIndoor->GetSector(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z); - v42 = BLV_GetFloorLevel(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z, pSpriteObject->uSectorID, &uFaceID); - if ( abs(pSpriteObject->vPosition.x) > 32767 - || abs(pSpriteObject->vPosition.y) > 32767 - || abs(pSpriteObject->vPosition.z) > 20000 - || v42 <= -30000 - && (pSpriteObject->uSectorID == 0)) -// || (v42 = _46CEC3_get_floor_level(pSpriteObject->vPosition.x, pSpriteObject->vPosition.y, pSpriteObject->vPosition.z, v4, &uFaceID), v42 == -30000)) ) - { - SpriteObject::OnInteraction(uLayingItemID); - return; - } - if ( pObject->uFlags & OBJECT_DESC_NO_GRAVITY )//íå ïàäàþùèå îáúåêòû - { -LABEL_25: - stru_721530.field_0 = 0; - stru_721530.prolly_normal_d = pObject->uRadius; - stru_721530.field_84 = -1; - stru_721530.height = pObject->uHeight; - stru_721530.field_8_radius = 0; - stru_721530.field_70 = 0; - for ( uFaceID = 0; uFaceID < 100; uFaceID++ ) - { - stru_721530.position.x = pSpriteObject->vPosition.x; - stru_721530.position.y = pSpriteObject->vPosition.y; - stru_721530.position.z = stru_721530.prolly_normal_d + pSpriteObject->vPosition.z + 1; - - stru_721530.normal.x = stru_721530.position.x; - stru_721530.normal.y = stru_721530.position.y; - stru_721530.normal.z = stru_721530.position.z; - - stru_721530.velocity.x = pSpriteObject->vVelocity.x; - stru_721530.velocity.y = pSpriteObject->vVelocity.y; - stru_721530.velocity.z = pSpriteObject->vVelocity.z; - - stru_721530.uSectorID = pSpriteObject->uSectorID; - if ( stru_721530._47050A(0) ) - return; - - for ( v40 = 0; v40 < 100; ++v40 ) - { - _46E44E_collide_against_faces_and_portals(0); - _46E0B2_collide_against_decorations(); - if (PID_TYPE(pSpriteObject->spell_caster_pid) != OBJECT_Player) - _46EF01_collision_chech_player(1); - if (PID_TYPE(pSpriteObject->spell_caster_pid) == OBJECT_Actor) - { - for ( v42 = 0; v42 < (signed int)uNumActors; ++v42 ) - { - if( pActors[pSpriteObject->spell_caster_pid >> 3].pMonsterInfo.uID != pActors[v42].pMonsterInfo.uID ) - //not sure: pMonsterList->pMonsters[v39b->word_000086_some_monster_id-1].uToHitRadius - Actor::_46DF1A_collide_against_actor(v42, pMonsterList->pMonsters[pActors[v42].word_000086_some_monster_id-1].uToHitRadius); - } - } - else - { - for ( v42 = 0; v42 < (signed int)uNumActors; v42++ ) - Actor::_46DF1A_collide_against_actor(v42, pMonsterList->pMonsters[pActors[v42].word_000086_some_monster_id-1].uToHitRadius); - } - if ( _46F04E_collide_against_portals() ) - break; - } - if ( stru_721530.field_7C >= stru_721530.field_6C ) - { - pSpriteObject->vPosition.x = stru_721530.normal2.x; - pSpriteObject->vPosition.y = stru_721530.normal2.y; - pSpriteObject->vPosition.z = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1; - pSpriteObject->uSectorID = LOWORD(stru_721530.uSectorID); - if ( !(HIBYTE(pObject->uFlags) & 1) ) - return; - memset(&Dst, 0, 0x68u); - Dst.x = (double)pSpriteObject->vPosition.x; - Dst.y = (double)pSpriteObject->vPosition.y; - Dst.z = (double)pSpriteObject->vPosition.z; - Dst.r = 0.0; - Dst.g = 0.0; - Dst.b = 0.0; - if ( pObject->uFlags & OBJECT_DESC_TRIAL_FIRE ) - { - Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; - Dst.uDiffuse = 0xFF3C1E; - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( pObject->uFlags & OBJECT_DESC_TRIAL_LINE ) - { - Dst.type = ParticleType_Line; - Dst.uDiffuse = rand(); - Dst.timeToLive = 64; - Dst.uTextureID = 0; - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( pObject->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - { - Dst.type = ParticleType_Bitmap | ParticleType_8; - Dst.uDiffuse = rand(); - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - } - return; - } - //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16; - pSpriteObject->vPosition.x += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x); - //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16; - pSpriteObject->vPosition.y += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y); - //v40 = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16; - pSpriteObject->vPosition.z += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z); - pSpriteObject->uSectorID = stru_721530.uSectorID; - stru_721530.field_70 += stru_721530.field_7C; - if ( pObject->uFlags & OBJECT_DESC_INTERACTABLE && !_46BFFA_check_object_intercept(uLayingItemID, stru_721530.uFaceID) ) - return; - v15 = (signed int)stru_721530.uFaceID >> 3; - if (PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration) - { - v40 = integer_sqrt(pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y); - v23 = stru_5C6E00->Atan2(pSpriteObject->vPosition.x - pLevelDecorations[v15].vPosition.x, - pSpriteObject->vPosition.y - pLevelDecorations[v15].vPosition.y); - pSpriteObject->vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v23), v40); - pSpriteObject->vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v23), v40); - } - if (PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel) - { - stru_721530.field_84 = (signed int)PID_ID(stru_721530.uFaceID); - if ( pIndoor->pFaces[v15].uPolygonType != POLYGON_Floor ) - { - v42 = abs(pIndoor->pFaces[v15].pFacePlane_old.vNormal.x * pSpriteObject->vVelocity.x - + pIndoor->pFaces[v15].pFacePlane_old.vNormal.y * pSpriteObject->vVelocity.y - + pIndoor->pFaces[v15].pFacePlane_old.vNormal.z * pSpriteObject->vVelocity.z) >> 16; - if ( (stru_721530.speed >> 3) > v42 ) - v42 = stru_721530.speed >> 3; - pSpriteObject->vVelocity.x += 2 * fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.x); - pSpriteObject->vVelocity.y += 2 * fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.y); - v39 = fixpoint_mul(v42, pIndoor->pFaces[v15].pFacePlane_old.vNormal.z); - if ( pIndoor->pFaces[v15].pFacePlane_old.vNormal.z <= 32000 ) - v22 = 2 * v39; - else - { - pSpriteObject->vVelocity.z += v39; - v22 = fixpoint_mul(32000, v39); - } - pSpriteObject->vVelocity.z += v22; - if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) - EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); - pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); - pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); - pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); - continue; - } - if ( pObject->uFlags & OBJECT_DESC_BOUNCE ) - { - v17 = -pSpriteObject->vVelocity.z / 2; - pSpriteObject->vVelocity.z = v17; - if ( (signed __int16)v17 < 10 ) - pSpriteObject->vVelocity.z = 0; - if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) - EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); - pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); - pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); - pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); - continue; - } - pSpriteObject->vVelocity.z = 0; - if ( pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y >= 400 ) - { - if ( pIndoor->pFaces[v15].uAttributes & FACE_UNKNOW2 ) - EventProcessor(pIndoor->pFaceExtras[pIndoor->pFaces[v15].uFaceExtraID].uEventID, 0, 1); - pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); - pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); - pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); - continue; - } - pSpriteObject->vVelocity.z = 0; - pSpriteObject->vVelocity.y = 0; - pSpriteObject->vVelocity.x = 0; - pSpriteObject->vPosition.z = pIndoor->pVertices[*pIndoor->pFaces[v15].pVertexIDs].z + 1; - } - pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); - pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); - pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); - } - } - //äëÿ ïàäàþùèõ îáúåêòîâ(äëÿ ïðèìåðà âûáðîñ âåùè èç èíâåíòàðÿ) - if ( v42 <= pSpriteObject->vPosition.z - 3 ) - { - pSpriteObject->vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); - goto LABEL_25; - } - if ( !(pObject->uFlags & OBJECT_DESC_INTERACTABLE) || _46BFFA_check_object_intercept(uLayingItemID, 0) ) - { - pSpriteObject->vPosition.z = v42 + 1; - if ( pIndoor->pFaces[uFaceID].uPolygonType == POLYGON_Floor ) - pSpriteObject->vVelocity.z = 0; - else - { - if ( pIndoor->pFaces[uFaceID].pFacePlane_old.vNormal.z < 45000 ) - pSpriteObject->vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength(); - } - pSpriteObject->vVelocity.x = fixpoint_mul(58500, pSpriteObject->vVelocity.x); - pSpriteObject->vVelocity.y = fixpoint_mul(58500, pSpriteObject->vVelocity.y); - pSpriteObject->vVelocity.z = fixpoint_mul(58500, pSpriteObject->vVelocity.z); - if ( pSpriteObject->vVelocity.x * pSpriteObject->vVelocity.x + pSpriteObject->vVelocity.y * pSpriteObject->vVelocity.y < 400 ) - { - pSpriteObject->vVelocity.x = 0; - pSpriteObject->vVelocity.y = 0; - pSpriteObject->vVelocity.z = 0; - if ( !(pObject->uFlags & OBJECT_DESC_NO_SPRITE) ) - return; - memset(&Dst, 0, 0x68u); - Dst.x = (double)pSpriteObject->vPosition.x; - Dst.y = (double)pSpriteObject->vPosition.y; - Dst.z = (double)pSpriteObject->vPosition.z; - Dst.r = 0.0; - Dst.g = 0.0; - Dst.b = 0.0; - if ( pObject->uFlags & OBJECT_DESC_TRIAL_FIRE ) - { - Dst.type = ParticleType_Bitmap | ParticleType_Rotating | ParticleType_8; - Dst.uDiffuse = 0xFF3C1E; - Dst.flt_28 = 1.0; - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar01", TEXTURE_DEFAULT); - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( pObject->uFlags & OBJECT_DESC_TRIAL_LINE ) - { - Dst.type = ParticleType_Line; - Dst.uDiffuse = rand(); - Dst.timeToLive = 64; - Dst.uTextureID = 0; - Dst.flt_28 = 1.0; - pGame->pParticleEngine->AddParticle(&Dst); - return; - } - else if ( pObject->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - { - Dst.type = ParticleType_Bitmap | ParticleType_8; - Dst.uDiffuse = rand(); - Dst.flt_28 = 1.0; - Dst.timeToLive = (unsigned __int8)(rand() & 0x80) + 128; - Dst.uTextureID = pBitmaps_LOD->LoadTexture("effpar03", TEXTURE_DEFAULT); - pGame->pParticleEngine->AddParticle(&Dst); - } - return; - } - goto LABEL_25; - } -} -// 46DF1A: using guessed type int __fastcall 46DF1A_collide_against_actor(int, int); - -//----- (00438E35) -------------------------------------------------------- -void SpriteObject::ExplosionTraps() -{ - MapInfo *pMapInfo; // esi@1 - int dir_x; // ebx@1 - int v7; // edx@2 - unsigned int v10; // eax@7 - signed int v11; // ebx@8 - signed int v13; // edi@20 - int dir_y; // [sp+Ch] [bp-Ch]@1 - int dir_z; // [sp+10h] [bp-8h]@1 - DAMAGE_TYPE pDamageType; // [sp+14h] [bp-4h]@14 - - pMapInfo = &pMapStats->pInfos[pMapStats->GetMapInfo(pCurrentMapName)]; - dir_x = abs(pParty->vPosition.x - this->vPosition.x); - dir_y = abs(pParty->vPosition.y - this->vPosition.y); - dir_z = abs(pParty->vPosition.z + pParty->sEyelevel - this->vPosition.z); - if ( dir_x < dir_y ) - { - v7 = dir_x; - dir_x = dir_y; - dir_y = v7; - } - if ( dir_x < dir_z ) - { - v7 = dir_x; - dir_x = dir_z; - dir_z = v7; - } - if ( dir_y < dir_z ) - { - v7 = dir_z; - dir_z = dir_y; - dir_y = v7; - } - v10 = ((unsigned int)(11 * dir_y) >> 5) + (dir_z / 4) + dir_x; - if ( (signed int)v10 <= 768 ) - { - v11 = 5; - if ( pMapInfo->Trap_D20 ) - { - for ( uint i = 0; i < pMapInfo->Trap_D20; ++i ) - v11 += rand() % 20 + 1; - } - switch ( this->uType ) - { - case 811: - pDamageType = DMGT_FIRE; - break; - case 812: - pDamageType = DMGT_ELECTR; - break; - case 813: - pDamageType = DMGT_COLD; - break; - case 814: - pDamageType = DMGT_BODY; - break; - default: - return; - } - for ( uint i = 1; i <= 4; ++i ) - { - if ( pPlayers[i]->CanAct() && (v13 = pPlayers[i]->GetPerception() + 20, rand() % v13 > 20) ) - pPlayers[i]->PlaySound(SPEECH_6, 0); - else - pPlayers[i]->ReceiveDamage(v11, pDamageType); - } - } -} - -//----- (0042F933) -------------------------------------------------------- -void SpriteObject::OnInteraction(unsigned int uLayingItemID) -{ - pSpriteObjects[uLayingItemID].uObjectDescID = 0; - if ( pParty->bTurnBasedModeOn == 1 ) - { - if (pSpriteObjects[uLayingItemID].uAttributes & 4 ) - { - pSpriteObjects[uLayingItemID].uAttributes &= 0xFFFB;//~0x00000004 - --pTurnEngine->pending_actions; - } - } -} - - -//----- (0042FA22) -------------------------------------------------------- -void CompactLayingItemsList() -{ - int new_obj_pos = 0; - - for ( int i = 0; i < MAX_SPRITE_OBJECTS; ++i ) - { - if ( pSpriteObjects[i].uObjectDescID ) - { - if ( i != new_obj_pos )// - { - memcpy(&pSpriteObjects[new_obj_pos], &pSpriteObjects[i],sizeof(SpriteObject)); - pSpriteObjects[i].uObjectDescID = 0; - } - new_obj_pos++; - } - } - uNumSpriteObjects = new_obj_pos; -} -//----- (00408896) -------------------------------------------------------- -void SpriteObject::InitializeSpriteObjects() -{ - for (uint i = 0; i < uNumSpriteObjects; ++i) - { - SpriteObject* item = &pSpriteObjects[i]; - - if (item->uType && (item->uSoundID & 8 || pObjectList->pObjects[item->uType].uFlags & OBJECT_DESC_UNPICKABLE)) - SpriteObject::OnInteraction(i); - } -} -//----- (0046BEF1) -------------------------------------------------------- -void SpriteObject::_46BEF1_apply_spells_aoe() -{ - //SpriteObject *v1; // edi@1 - //Actor *v2; // esi@2 - //__int16 v3; // fps@4 - //unsigned __int8 v4; // c0@4 - //unsigned __int8 v5; // c3@4 - //signed int v6; // [sp+8h] [bp-4h]@1 - - int v7,v9,v10,v11; - __debugbreak();//Ritor1 - if ( (signed int)uNumActors > 0 ) - { - for ( uint i = 0; i < uNumActors; ++i ) - { - if ( pActors[i].CanAct() ) - { - //UNDEF(v3); - //.text:0046BF26 movsx eax, word ptr [esi-2] - //.text:0046BF2A sub eax, [edi+4] - //.text:0046BF31 mov [ebp+var_8], eax - //.text:0046BF37 fild [ebp+var_8] - // v7 pushed to stack - v7 = pActors[i].vPosition.x - this->vPosition.x; - - //.text:0046BF2D movsx ecx, word ptr [esi+2] - //v8 = pActors[i].vPosition.z; - - //.text:0046BF34 movsx eax, word ptr [esi] - //.text:0046BF3A sub eax, [edi+8] - //.text:0046BF3D mov [ebp+var_8], eax - //.text:0046BF44 fild [ebp+var_8] - // v9 pushed to stack - v9 = pActors[i].vPosition.y - this->vPosition.y; - - //.text:0046BF40 movsx eax, word ptr [esi-6] - //.text:0046BF47 sar eax, 1 - //.text:0046BF49 add eax, ecx - //.text:0046BF4B sub eax, [edi+0Ch] - //.text:0046BF4E mov [ebp+var_8], eax - //.text:0046BF51 fild [ebp+var_8] - //.text:0046BF58 fld st - // v10 pushed to stack, two times - v10 = pActors[i].uActorHeight / 2 + pActors[i].vPosition.z - this->vVelocity.y; - - //.text:0046BF54 movsx eax, word ptr [esi-8] - //.text:0046BF5A add eax, 100h - //.text:0046BF63 mov ecx, eax - //v11 = this->vVelocity.x; - - //.text:0046BF5F fmul st, st(1) - // stack: v10*v10, v10, v9, v7 - //.text:0046BF61 fld st(2) - // stack: v7, v10*v10, v10, v9, v7 - - - //.text:0046BF65 fmul st, st(3) - // stack: v7*v9, v10*v10, v10, v9, v7 - - //.text:0046BF67 imul ecx, eax - v11 = this->vVelocity.x * this->vVelocity.x; - - //.text:0046BF6A faddp st(1), st - // stack: v10*v10+v7*v9, v10, v9, v7 - //.text:0046BF6C fld st(3) - // stack: v7, v10*v10+v7*v9, v10, v9, v7 - //.text:0046BF6E fmul st, st(4) - // stack: v7*v7, v10*v10+v7*v9, v10, v9, v7 - //.text:0046BF70 faddp st(1), st - // stack: v10*v10+v7*v9+v7*v7, v10, v9, v7 - - //.text:0046BF72 mov [ebp+var_8], ecx - //.text:0046BF75 fild [ebp+var_8] - // v11 pushed to stack - - //.text:0046BF78 fcompp - // if ( v11 > v10*v10+v7*v9+v7*v7 ) - // stack: v10, v9, v7 - - //.text:0046BF7A fstp st - // stack: v9, v7 - - //.text:0046BF7C fnstsw ax - //.text:0046BF7E fstp st - // stack: v7 - - //.text:0046BF80 test ah, 41h - //.text:0046BF83 fstp st - //.text:0046BF85 jnz short loc_46BFDD - - if ( v11 >= v7 * v7 + v9 * v9 + v10 * v10 ) - { - if ( pActors[i].DoesDmgTypeDoDamage((DAMAGE_TYPE)0xAu) ) - { - pActors[i].pActorBuffs[this->spell_id].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(this->spell_level << 7) * 0.033333335), - this->spell_skill, 4, 0, 0); - HIWORD(pActors[i].uAttributes) |= 8; - } - } - } - } - } -} - - -//----- (0042F7EB) -------------------------------------------------------- -bool SpriteObject::sub_42F7EB_DropItemAt(unsigned int uSpriteID, int x, int y, int z, int a4, int count, int a7, unsigned __int16 attributes, ItemGen *a9) -{ - unsigned __int16 pObjectDescID; // ax@7 - SpriteObject pSpellObject; // [sp+Ch] [bp-78h]@1 - - pSpellObject.stru_24.Reset(); - if ( a9 ) - memcpy(&pSpellObject.stru_24, a9, sizeof(pSpellObject.stru_24)); - pSpellObject.spell_skill = 0; - pSpellObject.spell_level = 0; - pSpellObject.spell_id = 0; - pSpellObject.field_54 = 0; - pSpellObject.uType = uSpriteID; - pObjectDescID = 0; - for ( uint i = 0; i < (signed int)pObjectList->uNumObjects; ++i ) - { - if ( (short)uSpriteID == pObjectList->pObjects[i].uObjectID ) - pObjectDescID = i; - } - pSpellObject.uObjectDescID = pObjectDescID; - pSpellObject.vPosition.x = x; - pSpellObject.vPosition.y = y; - pSpellObject.vPosition.z = z; - pSpellObject.uSoundID = 0; - pSpellObject.uAttributes = attributes; - pSpellObject.uSectorID = pIndoor->GetSector(x, y, z); - pSpellObject.uSpriteFrameID = 0; - pSpellObject.spell_caster_pid = 0; - pSpellObject.spell_target_pid = 0; - if ( !(pSpellObject.uAttributes & 0x10) ) - { - if ( pItemsTable->uAllItemsCount ) - { - for ( uint i = 1; i < pItemsTable->uAllItemsCount; ++i ) - { - if ( pItemsTable->pItems[i].uSpriteID == uSpriteID ) - pSpellObject.stru_24.uItemID = i; - } - } - } - if ( a7 ) - { - if ( count > 0 ) - { - for ( uint i = count; i; --i ) - { - pSpellObject.uFacing = rand() % (signed int)stru_5C6E00->uIntegerDoublePi; - pSpellObject.Create((signed __int16)pSpellObject.uFacing, - ((signed int)stru_5C6E00->uIntegerHalfPi / 2) + (rand() % ((signed int)stru_5C6E00->uIntegerHalfPi / 2)), a4, 0); - - } - } - } - else - { - pSpellObject.uFacing = 0; - if ( count > 0 ) - { - for ( uint i = count; i; --i ) - { - pSpellObject.Create((signed __int16)pSpellObject.uFacing, stru_5C6E00->uIntegerHalfPi, a4, 0); - } - } - } - return true; -} - -//----- (0042F960) -------------------------------------------------------- -void SpriteObject::sub_42F960_create_object(int x, int y, int z) -{ - unsigned __int16 v7; // ax@5 - signed int v8; // eax@6 - signed int v9; // eax@7 - - SpriteObject a1; // [sp+Ch] [bp-70h]@1 - //SpriteObject::SpriteObject(&a1); - a1.stru_24.Reset(); - - a1.spell_skill = 0; - a1.spell_level = 0; - a1.spell_id = 0; - a1.field_54 = 0; - a1.uType = 800; - v7 = 0; - for ( uint i = 0; i < (signed int)pObjectList->uNumObjects; ++i ) - { - if ( a1.uType == pObjectList->pObjects[i].uObjectID ) - v7 = i; - } - a1.uObjectDescID = v7; - a1.vPosition.x = x; - a1.vPosition.y = y; - a1.vPosition.z = z; - a1.uSoundID = 0; - a1.uAttributes = 0; - a1.uSectorID = pIndoor->GetSector(x, y, z); - a1.uSpriteFrameID = 0; - a1.spell_caster_pid = 0; - a1.spell_target_pid = 0; - v8 = a1.Create(0, 0, 0, 0); - if ( v8 != -1 ) - { - v9 = 8 * v8; - LOBYTE(v9) = v9 | 2; - pAudioPlayer->PlaySound((SoundID)(SOUND_GoldReceived|0x14), v9, 0, -1, 0, 0, 0, 0); - } -} - -//----- (0046BFFA) -------------------------------------------------------- -bool __fastcall _46BFFA_check_object_intercept(unsigned int uLayingItemID, signed int a2) -{ - ObjectDesc *object; // ebx@1 - unsigned int v8; // eax@19 - signed int v10; // ebx@19 - char *v11; // edx@20 - unsigned __int16 v12; // ax@23 - int v13; // eax@27 - int v16; // eax@36 - __int16 v18; // di@37 - signed int v19; // edx@37 - unsigned __int16 v22; // ax@41 - signed int v24; // ebx@46 - char *v25; // edx@47 - signed int v34; // edx@65 - unsigned __int16 v36; // ax@69 - int v37; // ST14_4@72 - int v38; // eax@72 - int v39; // ST10_4@72 - int v40; // ST0C_4@72 - unsigned __int8 v44; // zf@79 - int v47; // eax@81 - signed int v52; // ebx@93 - signed int v56; // ebx@98 - unsigned __int16 v58; // ax@102 - unsigned __int16 v59; // ax@107 - signed int v61; // ebx@107 - unsigned __int16 v63; // ax@111 - int v64; // ebx@114 - signed int v65; // eax@114 - signed int v69; // ebx@124 - unsigned __int16 v71; // ax@128 - unsigned int v72; // ebx@131 - int v78; // eax@133 - signed int v81; // edx@140 - unsigned __int16 v83; // ax@144 - signed int v86; // ebx@151 - unsigned __int16 v88; // ax@155 - unsigned int v89; // eax@158 - int v90; // ST34_4@159 - int v91; // eax@159 - unsigned int v92; // eax@163 - unsigned __int16 v95; // ax@181 - unsigned __int16 v96; // ax@184 - int v97; // eax@185 - char v100; // ST18_1@198 - int v102; // eax@198 - signed int v106; // eax@208 - unsigned int v107; // edx@220 - signed int v108; // ebx@225 - signed int v110; // ebx@234 - unsigned __int16 v112; // ax@238 - unsigned __int16 v113; // si@241 - int v114; // eax@242 - int v115; // eax@245 - signed int v119; // ebx@251 - unsigned __int16 v121; // ax@255 - int v124; // eax@267 - int v125; // [sp-20h] [bp-4Ch]@28 - char v132; // [sp-8h] [bp-34h]@131 - char v134; // [sp-4h] [bp-30h]@131 - signed int v135; // [sp-4h] [bp-30h]@217 - int v136; // [sp+Ch] [bp-20h]@208 - int v137; // [sp+10h] [bp-1Ch]@208 - signed int v138; // [sp+14h] [bp-18h]@207 - signed int v139; // [sp+18h] [bp-14h]@208 - signed int v141; // [sp+1Ch] [bp-10h]@117 - unsigned int v142; // [sp+1Ch] [bp-10h]@158 - signed int v143; // [sp+1Ch] [bp-10h]@172 - signed int v146; // [sp+20h] [bp-Ch]@60 - int v147; // [sp+20h] [bp-Ch]@72 - signed int v148; // [sp+20h] [bp-Ch]@158 - unsigned __int16 v150; // [sp+20h] [bp-Ch]@208 - signed int v152; // [sp+24h] [bp-8h]@208 - - object = &pObjectList->pObjects[pSpriteObjects[uLayingItemID].uObjectDescID]; - //v151 = PID_TYPE(a2); - if (PID_TYPE(a2) == OBJECT_Actor) - { - if (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Actor - && !pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].GetActorsRelation(&pActors[PID_ID(a2)])) - return 1; - } - else - { - if (PID_TYPE(a2) == OBJECT_Player && PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) == OBJECT_Player) - return 1; - } - if (pParty->bTurnBasedModeOn == 1) - { - if (pSpriteObjects[uLayingItemID].uAttributes & 4) - { - --pTurnEngine->pending_actions; - pSpriteObjects[uLayingItemID].uAttributes &= 0xFFFB;//~0x00000004 - } - } - if (PID_TYPE(a2) == OBJECT_BModel && PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid) != OBJECT_Player) - { - if (PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid) < 500) //bugfix PID_ID(v2->spell_caster_pid)==1000 - pActors[PID_ID(pSpriteObjects[uLayingItemID].spell_caster_pid)].uAttributes |= ACTOR_UNKNOW5; - } - - //v6 = v2->uType; - //v7 = v2->uType; - - switch (pSpriteObjects[uLayingItemID].uType) - { - - case 1060: - case 2030: - case 9010: - { - //v9 = 0; - if (PID_TYPE(a2) == 6 || PID_TYPE(a2) == 5 || !PID_TYPE(a2)) - return 1; - if (PID_TYPE(a2) != 2) - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v95 = 0; - for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) - v95 = v52; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!pSpriteObjects[uLayingItemID].uSoundID) - v97 = 0; - else - v97 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); - return 0; - } - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; - v121 = 0; - for (v119 = 0; v119 < (signed int)pObjectList->uNumObjects; ++v119) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v119].uObjectID) - v121 = v119; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v121; - if (!v121) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v13 = 8 * uLayingItemID; - LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); - pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); - return 0; - } - - - case 500: - case 505: - case 510: - case 515: - case 520: - case 525: - case 530: - case 535: - case 540: - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v12 = 0; - for (v10 = 0; v10 < (signed int)pObjectList->uNumObjects; ++v10) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v10].uObjectID) - v12 = v10; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v12; - if (!v12) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (pSpriteObjects[uLayingItemID].uType == 555) - { - v13 = 8 * uLayingItemID; - LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); - pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); - } - return 0; - } - - case 545: - case 550: - { - if (pSpriteObjects[uLayingItemID].stru_24.uItemID != 405 && pSpriteObjects[uLayingItemID].stru_24.uSpecEnchantmentType != 3) - { - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - sub_43A97E(uLayingItemID, a2); - SpriteObject::OnInteraction(uLayingItemID); - if (pSpriteObjects[uLayingItemID].uSoundID == 0) - v16 = 0; - else - v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); - return 0; - } - v18 = 0; - pSpriteObjects[uLayingItemID].uType = 600; - v22 = 0; - for (v19 = 0; v19 < (signed int)pObjectList->uNumObjects; ++v19) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v19].uObjectID) - v22 = v19; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v22; - if (!v22) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = v18; - pSpriteObjects[uLayingItemID].vVelocity.y = v18; - pSpriteObjects[uLayingItemID].vVelocity.x = v18; - pSpriteObjects[uLayingItemID].uSpriteFrameID = v18; - v12 = 0; - for (v10; v10 < (signed int)v8; ++v10) - { - v11 += 56; - if (pSpriteObjects[uLayingItemID].uType != *(short *)v11) - v12 = v10; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v12; - if (!v12) - SpriteObject::OnInteraction(uLayingItemID); - v44 = pSpriteObjects[uLayingItemID].uType == 555; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!v44) - { - v13 = 8 * uLayingItemID; - LOBYTE(v13) = PID(OBJECT_Item, uLayingItemID); - pAudioPlayer->PlaySound(SOUND_8, v13, 0, -1, 0, 0, 0, 0); - return 0; - } - return 0; - } - - case 600: - { - pSpriteObjects[uLayingItemID].uType = 601; - v36 = 0; - for (v34 = 0; v34 < (signed int)pObjectList->uNumObjects; ++v34) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v34].uObjectID) - v36 = v34; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v36; - if (!v36) - SpriteObject::OnInteraction(uLayingItemID); - v37 = pSpriteObjects[uLayingItemID].vPosition.z; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - v38 = 8 * uLayingItemID; - v39 = pSpriteObjects[uLayingItemID].vPosition.y; - LOBYTE(v38) = PID(OBJECT_Item, uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - v40 = pSpriteObjects[uLayingItemID].vPosition.x; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v147 = v38; - AttackerInfo.Add(v38, 512, v40, v39, v37, 0, 0); - if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); - pAudioPlayer->PlaySound(SOUND_8, v147, 0, -1, 0, 0, 0, 0); - return 0; - } - - case 1010: - case 1100: - case 2060: - case 3010: - case 3030: - case 3060: - case 4000: - case 4030: - case 4050: - case 4100: - case 6010: - case 6090: - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v95 = 0; - for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) - v95 = v52; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - v96 = pSpriteObjects[uLayingItemID].uSoundID; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!v96) - v97 = 0; - else - v97 = (signed __int16)v96 + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); - return 0; - } - - - case 555: - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v18 = 0; - v22 = 0; - v25 = (char *)&pObjectList->pObjects->uObjectID; - for (v24 = 0; v24 < (signed int)pObjectList->uNumObjects; ++v24) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v24].uObjectID) - v22 = v24; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v22; - if (v22 == v18) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = v18; - pSpriteObjects[uLayingItemID].vVelocity.y = v18; - pSpriteObjects[uLayingItemID].vVelocity.x = v18; - pSpriteObjects[uLayingItemID].uSpriteFrameID = v18; - return 0; - } - - case 3090: - { - //v9 = 0; - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 2; - v63 = 0; - for (v61 = 0; v61 < (signed int)pObjectList->uNumObjects; ++v61) - { - if (v59 == pObjectList->pObjects[v61].uObjectID) - v63 = v61; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v63; - if (!v63) - SpriteObject::OnInteraction(uLayingItemID); - v64 = pSpriteObjects[uLayingItemID].uFacing - stru_5C6E00->uIntegerDoublePi; - v44 = pSpriteObjects[uLayingItemID].spell_skill == 4; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - v65 = 7; - if (v44) - v65 = 9; - if (v65 > 0) - { - v141 = v65; - do - { - v64 += (signed int)stru_5C6E00->uIntegerHalfPi / 2; - pSpriteObjects[uLayingItemID].Create(v64, 0, 1000, 0); - --v141; - } while (v141); - } - SpriteObject::OnInteraction(uLayingItemID); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v16 = 0; - else - v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); - return 0; - } - - case 3092: - { - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType - 1; - v58 = 0; - for (v56 = 0; v56 < (signed int)pObjectList->uNumObjects; ++v56) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v56].uObjectID) - v58 = v56; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v58; - if (!v58) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - sub_43A97E(uLayingItemID, a2); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v16 = 0; - else - v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); - return 0; - } - - case 4070: - { - if (PID_TYPE(a2) == 6 || PID_TYPE(a2) == 5 || !PID_TYPE(a2)) - return 1; - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; - v71 = 0; - for (v69 = 0; v69 < (signed int)pObjectList->uNumObjects; ++v69) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v69].uObjectID) - v71 = v69; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v71; - if (!v71) - SpriteObject::OnInteraction(uLayingItemID); - v134 = 0; - v72 = uLayingItemID; - v132 = 0; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - AttackerInfo.Add(PID(OBJECT_Item, v72), 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v132, v134); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v78 = 0; - else - v78 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, pSpriteObjects[uLayingItemID].vPosition.x, 0, -1, 0, v78, 0, 0); - return 0; - } - - case 4090: - { - //v9 = 0; - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 2; - v88 = 0; - for (v86 = 0; v86 < (signed int)pObjectList->uNumObjects; ++v86) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v86].uObjectID) - v88 = v86; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v88; - if (!v88) - SpriteObject::OnInteraction(uLayingItemID); - v89 = pSpriteObjects[uLayingItemID].uFacing - stru_5C6E00->uIntegerDoublePi; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - v142 = v89; - v148 = 7; - do - { - pRnd->SetRange(-128, 128); - v90 = pRnd->GetInRange(); - pRnd->SetRange(5, 500); - v91 = pRnd->GetInRange(); - v142 += (signed int)stru_5C6E00->uIntegerHalfPi >> 1; - pSpriteObjects[uLayingItemID].Create(v90 + v142, 0, v91, 0); - --v148; - } while (v148); - SpriteObject::OnInteraction(uLayingItemID); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v16 = 0; - else - v16 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v16, 0, 0); - return 0; - } - - case 4092: - { - pSpriteObjects[uLayingItemID].uType = 4091; - v83 = 0; - for (v81 = 0; v81 < (signed int)pObjectList->uNumObjects; ++v81) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v81].uObjectID) - v83 = v81; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v83; - if (!v83) - SpriteObject::OnInteraction(uLayingItemID); - v134 = 0; - //v72 = uLayingItemID; - v132 = pSpriteObjects[uLayingItemID].field_61; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - AttackerInfo.Add(PID(OBJECT_Item, uLayingItemID), 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v132, v134); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v78 = 0; - else - v78 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, pSpriteObjects[uLayingItemID].vPosition.x, 0, -1, 0, v78, 0, 0); - return 0; - } - - case 8010: - { - if (PID_TYPE(a2) == 3 - && MonsterStats::BelongsToSupertype(pActors[PID_ID(a2)].pMonsterInfo.uID, MONSTER_SUPERTYPE_UNDEAD)) - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - //v9 = 0; - v95 = 0; - for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) - v95 = v52; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - v96 = pSpriteObjects[uLayingItemID].uSoundID; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!v96) - v97 = 0; - else - v97 = (signed __int16)v96 + 4; - v92 = uLayingItemID; - v124 = 8 * v92; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); - return 0; - } - - case 7030: - case 7090: - case 8000: - case 8090: - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v95 = 0; - for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) - v95 = v52; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - v96 = pSpriteObjects[uLayingItemID].uSoundID; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!v96) - v97 = 0; - else - v97 = (signed __int16)v96 + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); - return 0; - } - - case 6040: - case 8030: - case 9030: - { - v143 = 17030; - switch (pSpriteObjects[uLayingItemID].uType) - { - case 0x1798u: - v143 = 15040; - break; - case 0xFAAu: - v143 = 13010; - break; - case 0x2346u: - v143 = 18030; - break; - } - v138 = 1; - if (PID_TYPE(a2) != OBJECT_Actor) - { - if (pSpriteObjects[uLayingItemID].uType != 9030 || pSpriteObjects[uLayingItemID].spell_skill != 4) - { - SpriteObject::OnInteraction(uLayingItemID); - return 0; - } - pSpriteObjects[uLayingItemID]._46BEF1_apply_spells_aoe(); - if (!v138) - { - ++pSpriteObjects[uLayingItemID].uType; - v112 = 0; - for (v110 = 0; v110 < (signed int)pObjectList->uNumObjects; ++v110) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v110].uObjectID) - v112 = v110; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v112; - if (!v112) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v113 = pSpriteObjects[uLayingItemID].uSoundID; - if (v113) - v114 = (signed __int16)v113 + 4; - else - v114 = 0; - v115 = 8 * uLayingItemID; - LOBYTE(v115) = PID(OBJECT_Item, uLayingItemID); - v125 = v143 + 1; - pAudioPlayer->PlaySound((SoundID)v125, v115, 0, -1, 0, v114, 0, 0); - } - else - SpriteObject::OnInteraction(uLayingItemID); - return 0; - } - v106 = a2; - v150 = 0; - v139 = PID_ID(v106); - v137 = pSpriteObjects[uLayingItemID].spell_level; - v152 = pSpriteObjects[uLayingItemID].spell_skill; - v136 = pSpriteObjects[uLayingItemID].spell_id; - if (pSpriteObjects[uLayingItemID].uType == 9030) - { - v150 = 2; - if (v152 == 2) - v150 = 3; - else - { - if (v152 >= 3) - v150 = 4; - } - pActors[v139].uAttributes |= ACTOR_AGGRESSOR; - v107 = v135; - } - if (pSpriteObjects[uLayingItemID].uType == 6040) - { - v135 = 7; - v107 = v135; - } - else - { - if (pSpriteObjects[uLayingItemID].uType == 8030) - { - v135 = 9; - v107 = v135; - } - else - { - if (pSpriteObjects[uLayingItemID].uType != 9030) - { - v107 = v136; - } - if (pSpriteObjects[uLayingItemID].uType == 9030) - { - v135 = 10; - v107 = v135; - } - } - } - if (pSpriteObjects[uLayingItemID].uType != 9030 || v152 != 4) - { - v108 = v139; - if (pActors[v139].DoesDmgTypeDoDamage((DAMAGE_TYPE)v107)) - { - v138 = 0; - if (pSpriteObjects[uLayingItemID].uType == 8030) - { - pActors[v108].uAIState = Standing; - pActors[v108].UpdateAnimation(); - } - pActors[v108].pActorBuffs[v136].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(v137 << 7) * 0.033333335), - v152, v150, 0, 0); - } - } - else - { - pSpriteObjects[uLayingItemID]._46BEF1_apply_spells_aoe(); - } - pSpriteObjects[uLayingItemID].spell_level = 0; - pSpriteObjects[uLayingItemID].spell_skill = 0; - pSpriteObjects[uLayingItemID].spell_id = 0; - if (!v138) - { - ++pSpriteObjects[uLayingItemID].uType; - v112 = 0; - for (v110 = 0; v110 < (signed int)pObjectList->uNumObjects; ++v110) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v110].uObjectID) - v112 = v110; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v112; - if (!v112) - SpriteObject::OnInteraction(uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v113 = pSpriteObjects[uLayingItemID].uSoundID; - if (v113) - v114 = (signed __int16)v113 + 4; - else - v114 = 0; - v115 = 8 * uLayingItemID; - LOBYTE(v115) = PID(OBJECT_Item, uLayingItemID); - v125 = v143 + 1; - pAudioPlayer->PlaySound((SoundID)v125, v115, 0, -1, 0, v114, 0, 0); - } - else - SpriteObject::OnInteraction(uLayingItemID); - return 0; - } - - case 9040: - { - sub_43A97E(uLayingItemID, a2); - ++pSpriteObjects[uLayingItemID].uType; - v95 = 0; - for (v52 = 0; v52 < (signed int)pObjectList->uNumObjects; ++v52) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v52].uObjectID) - v95 = v52; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - v96 = pSpriteObjects[uLayingItemID].uSoundID; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - if (!v96) - v97 = 0; - else - v97 = (signed __int16)v96 + 4; - v124 = 8 * uLayingItemID; - LOBYTE(v124) = v124 | 2; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v124, 0, -1, 0, v97, 0, 0); - return 0; - } - - /* - case 1080: - case 2100: - { - if (PID_TYPE(a2) != 3) - { - //v32 = 0; - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; - v46 = 0; - for (v146 = 0; v146 < (signed int)pObjectList->uNumObjects; ++v146) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v146].uObjectID) - v46 = v146; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v46; - if (!v46) - SpriteObject::OnInteraction(uLayingItemID); - v100 = pSpriteObjects[uLayingItemID].field_61; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v102 = 8 * uLayingItemID; - LOBYTE(v102) = PID(OBJECT_Item, uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - AttackerInfo.Add(v102, 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v100, 0); - if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v47 = 0; - else - v47 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v102, 0, -1, 0, v47, 0, 0); - return 0; - } - return 1; - }*/ - - case 1080: - case 2100: - { - if (PID_TYPE(a2) == 3) - return 1; - //else go to next case - } - - case 1050: - case 9080: - { - v95 = 0; - pSpriteObjects[uLayingItemID].uType = pSpriteObjects[uLayingItemID].uType + 1; - for (v146 = 0; v146 < (signed int)pObjectList->uNumObjects; ++v146) - { - if (pSpriteObjects[uLayingItemID].uType == pObjectList->pObjects[v146].uObjectID) - v95 = v146; - } - pSpriteObjects[uLayingItemID].uObjectDescID = v95; - if (!v95) - SpriteObject::OnInteraction(uLayingItemID); - v100 = pSpriteObjects[uLayingItemID].field_61; - pSpriteObjects[uLayingItemID].uSpriteFrameID = 0; - v102 = 8 * uLayingItemID; - LOBYTE(v102) = PID(OBJECT_Item, uLayingItemID); - pSpriteObjects[uLayingItemID].vVelocity.x = 0; - pSpriteObjects[uLayingItemID].vVelocity.y = 0; - pSpriteObjects[uLayingItemID].vVelocity.z = 0; - AttackerInfo.Add(v102, 512, pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, v100, 0); - if (object->uFlags & OBJECT_DESC_TRIAL_PARTICLE) - trail_particle_generator.GenerateTrailParticles(pSpriteObjects[uLayingItemID].vPosition.x, pSpriteObjects[uLayingItemID].vPosition.y, pSpriteObjects[uLayingItemID].vPosition.z, object->uParticleTrailColor); - if (!pSpriteObjects[uLayingItemID].uSoundID) - v47 = 0; - else - v47 = (signed __int16)pSpriteObjects[uLayingItemID].uSoundID + 4; - v125 = word_4EE088_sound_ids[pSpriteObjects[uLayingItemID].spell_id - 1] + 1; - pAudioPlayer->PlaySound((SoundID)v125, v102, 0, -1, 0, v47, 0, 0); - return 0; - } - - default: - return 0; - } - -} - -//----- (0043A97E) -------------------------------------------------------- -void __fastcall sub_43A97E(unsigned int uLayingItemID, signed int a2) -{ - if (PID_TYPE(a2) == OBJECT_Player) - { - layingitem_vel_50FDFC.x = pSpriteObjects[uLayingItemID].vVelocity.x; - layingitem_vel_50FDFC.y = pSpriteObjects[uLayingItemID].vVelocity.y; - layingitem_vel_50FDFC.z = pSpriteObjects[uLayingItemID].vVelocity.z; - - Vec3_int_::Normalize(&layingitem_vel_50FDFC.x, &layingitem_vel_50FDFC.y, &layingitem_vel_50FDFC.z); - DamagePlayerFromMonster(PID(OBJECT_Item, uLayingItemID), pSpriteObjects[uLayingItemID].field_61, &layingitem_vel_50FDFC, -1); - } - else if (PID_TYPE(a2) == OBJECT_Actor) - { - layingitem_vel_50FDFC.x = pSpriteObjects[uLayingItemID].vVelocity.x; - layingitem_vel_50FDFC.y = pSpriteObjects[uLayingItemID].vVelocity.y; - layingitem_vel_50FDFC.z = pSpriteObjects[uLayingItemID].vVelocity.z; - - Vec3_int_::Normalize(&layingitem_vel_50FDFC.x, &layingitem_vel_50FDFC.y, &layingitem_vel_50FDFC.z); - switch (PID_TYPE(pSpriteObjects[uLayingItemID].spell_caster_pid)) - { - case OBJECT_Actor: - Actor::ActorDamageFromMonster(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC, pSpriteObjects[uLayingItemID].field_61); - break; - case OBJECT_Player: - Actor::DamageMonsterFromParty(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC); - break; - case OBJECT_Item: - ItemDamageFromActor(PID(OBJECT_Item, uLayingItemID), PID_ID(a2), &layingitem_vel_50FDFC); - break; - } - } -}
--- a/SpriteObject.h Thu Sep 18 23:59:29 2014 +0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -#pragma once -#include "Items.h" - -enum -{ - OBJECT_40 = 0x40 - , OBJECT_ATTACHED_TO_ACTOR = 0x80 -}; - -#define MAX_SPRITE_OBJECTS 1000 -/* 72 */ -#pragma pack(push, 1) -struct SpriteObject -{ - inline bool AttachedToActor() const {return (uAttributes & OBJECT_ATTACHED_TO_ACTOR) != 0;} - - SpriteObject(); - int Create(int yaw, int pitch, int a4, int a5); - void _46BEF1_apply_spells_aoe(); - void ExplosionTraps(); - - static void UpdateObject_fn0_BLV(unsigned int uLayingItemID); - static void UpdateObject_fn0_ODM(unsigned int uLayingItemID); - static void OnInteraction(unsigned int uLayingItemID); - static bool sub_42F7EB_DropItemAt(unsigned int uSpriteID, int x, int y, int z, int a4, int count, int a7, unsigned __int16 attributes, ItemGen *a9); - static void sub_42F960_create_object(int x, int y, int z); - static void InitializeSpriteObjects(); - - - unsigned __int16 uType; - unsigned __int16 uObjectDescID; - struct Vec3_int_ vPosition; - struct Vec3_short_ vVelocity; - unsigned __int16 uFacing; - unsigned __int16 uSoundID; - unsigned __int16 uAttributes; - __int16 uSectorID; - unsigned __int16 uSpriteFrameID; - __int16 field_20; - __int16 field_22_glow_radius_multiplier; - struct ItemGen stru_24; - int spell_id; - int spell_level; - int spell_skill; - int field_54; - int spell_caster_pid; - int spell_target_pid; - char field_60_distance_related_prolly_lod; - char field_61; - char field_62[2]; - Vec3_int_ field_64; -}; -#pragma pack(pop) - - -void CompactLayingItemsList(); - -extern size_t uNumSpriteObjects; -extern std::array<SpriteObject, MAX_SPRITE_OBJECTS> pSpriteObjects; - -bool __fastcall _46BFFA_check_object_intercept(unsigned int uLayingItemID, signed int a2); -void __fastcall sub_43A97E(unsigned int uLayingItemID, signed int a2); // idb