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,&param_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,&param_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