diff Engine/Spells/Spells.cpp @ 2499:68cdef6879a0

engine folder
author Ritor1
date Fri, 19 Sep 2014 02:57:42 +0600
parents
children a77c34acdbc9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Engine/Spells/Spells.cpp	Fri Sep 19 02:57:42 2014 +0600
@@ -0,0 +1,741 @@
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdlib.h>
+#include "../ErrorHandling.h"
+
+#include "Spells.h"
+#include "Engine/Graphics/Overlays.h"
+#include "../LOD.h"
+#include "../texts.h"
+
+#include "../Party.h"
+#include "../OurMath.h"
+#include "Engine/Objects/SpriteObject.h"
+#include "Engine/Objects/ObjectList.h"
+#include "Engine/Graphics/Indoor.h"
+#include "AudioPlayer.h"
+#include "Engine/Objects/Actor.h"
+#include "../Game.h"
+#include "stru6.h"
+
+
+std::array<TownPortalData, 6> TownPortalList = //4ECBB8
+{{
+ {Vec3_int_(-5121, 2107, 1), 1536, 0, 21, 0},
+ {Vec3_int_(-15148, -10240, 1473), 0, 0, 4, 0},
+ {Vec3_int_(-10519, 5375, 753), 512, 0, 3, 0},
+ {Vec3_int_(3114, -11055, 513), 0, 0, 10, 0},
+ {Vec3_int_(-158, 7624, 1), 512, 0, 7, 0},
+ {Vec3_int_(-1837, -4247, 65), 65, 0, 8, 0}
+}} ;
+
+struct SpellStats *pSpellStats;
+
+
+std::array<stru324_spell, 103> stru_4E3ACC =
+{{
+  {10, 0},
+  {1000, 0}, {1010, 0}, {1020, 0}, {1030, 0}, {1040, 0}, {1050, 0}, {1060, 0}, {1070, 0}, {1080, 0}, {1090, 0}, {1100, 0},
+  {2000, 0}, {2010, 0}, {2020, 0}, {2030, 0}, {2040, 0}, {2050, 0}, {2060, 0}, {2070, 0}, {2080, 0}, {2090, 0}, {2100, 0},
+  {3000, 0}, {3010, 0}, {3020, 0}, {3030, 0}, {3040, 0}, {3050, 0}, {3060, 0}, {3070, 0}, {3080, 0}, {3090, 0}, {3100, 0},
+  {4000, 0}, {4010, 0}, {4020, 0}, {4030, 0}, {4040, 0}, {4050, 0}, {4060, 0}, {4070, 0}, {4080, 0}, {4090, 0}, {4100, 0},
+  {5000, 0}, {5010, 0}, {5020, 0}, {5030, 0}, {5040, 0}, {5050, 0}, {5060, 0}, {5070, 0}, {5080, 0}, {5090, 0}, {5100, 0},
+  {6000, 0}, {6010, 0}, {6020, 0}, {6030, 0}, {6040, 0}, {6050, 0}, {6060, 0}, {6070, 0}, {6080, 0}, {6090, 0}, {6100, 0},
+  {7000, 0}, {7010, 0}, {7020, 0}, {7030, 0}, {7040, 0}, {7050, 0}, {7060, 0}, {7070, 0}, {7080, 0}, {7090, 0}, {7100, 0},
+  {8000, 0}, {8010, 0}, {8020, 0}, {8030, 0}, {8040, 0}, {8050, 0}, {8060, 0}, {8070, 0}, {8080, 0}, {8090, 0}, {8100, 0},
+  {9000, 0}, {9010, 0}, {9020, 0}, {9030, 0}, {9040, 0}, {9050, 0}, {9060, 0}, {9070, 0}, {9080, 0}, {9090, 0}, {9100, 0},
+  {545, 0},
+  {545, 0},
+  {555, 0}
+}};
+
+
+
+SpellData::SpellData( __int16 innormalMana, __int16 inExpertLevelMana, __int16 inMasterLevelMana, __int16 inMagisterLevelMana,
+                     __int16 inNormalLevelRecovery, __int16 inExpertLevelRecovery, __int16 inMasterLevelRecovery, __int16 inMagisterLevelRecovery,
+                     __int8 inbaseDamage, __int8 inbonusSkillDamage, __int16 instats ):
+uNormalLevelMana(innormalMana),
+uExpertLevelMana(inExpertLevelMana),
+uMasterLevelMana(inMasterLevelMana),
+uMagisterLevelMana(inMagisterLevelMana),
+uNormalLevelRecovery(inNormalLevelRecovery),
+uExpertLevelRecovery(inExpertLevelRecovery),
+uMasterLevelRecovery(inMasterLevelRecovery),
+uMagisterLevelRecovery(inMagisterLevelRecovery),
+baseDamage(inbaseDamage),
+bonusSkillDamage(inbonusSkillDamage),
+stats(instats)
+{
+
+}
+
+ //9 spellbook pages  11 spells per page 9*11 =99 +1 zero struct at 0. It counted from 1!
+std::array<SpellData, 100> pSpellDatas={{
+					 SpellData(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+
+             SpellData(1, 1, 1, 1, 60, 60, 60, 40, 0, 0, 0),//0 fire
+	           SpellData(2, 2, 2, 2, 110, 110, 100, 90, 3, 3, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(5, 5, 5, 5, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 100, 100, 90, 80, 0, 6, 0),
+	           SpellData(10, 10, 10, 10, 150, 150, 150, 150, 0, 6, 0),
+	           SpellData(15, 15, 15, 15, 120, 120, 120, 120, 0, 6, 0),
+	           SpellData(20, 20, 20, 20, 100, 100, 100, 90, 8, 1, 0),
+	           SpellData(25, 25, 25, 25, 100, 100, 100, 90, 12, 1, 0),
+	           SpellData(30, 30, 30, 30, 90, 90, 90, 90, 15, 15, 0),
+
+	           SpellData(1, 1, 1, 0, 60, 60, 60, 60, 0, 0, 0),  //1 air
+	           SpellData(2, 2, 2, 2, 120, 120, 120, 100, 0, 0, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 110, 100, 90, 80, 2, 1, 0),
+	           SpellData(5, 5, 5, 5,  90, 90,  70, 50, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(10, 10, 10, 10, 100, 100, 90, 70, 0, 8, 0),
+	           SpellData(15, 15, 15, 15, 200, 200, 200, 200, 0, 0, 0),
+	           SpellData(20, 20, 20, 20, 100, 100, 100, 90, 10, 10, 0),
+	           SpellData(25, 25, 25, 25, 250, 250, 250, 250, 0, 0, 0),
+	           SpellData(30, 30, 30, 30, 90, 90, 90, 90, 20, 1, 0),
+
+	           SpellData(1, 1, 1, 1, 60, 60, 60, 20, 0, 0, 0),  //2 water
+	           SpellData(2, 2, 2, 2, 110, 100, 90, 70, 2, 2, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 110, 100, 90, 80, 0, 4, 0),
+	           SpellData(5, 5, 5, 5, 150, 150, 150, 150, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 200, 200, 200, 200, 0, 0, 0),
+	           SpellData(10, 10, 10, 10, 100, 100, 90, 80, 9, 9, 0),
+	           SpellData(15, 15, 15, 15, 140, 140, 140, 140, 0, 0, 0),
+	           SpellData(20, 20, 20, 20, 200, 200, 200, 200, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 80, 80, 80, 80, 12, 3, 0),
+	           SpellData(30, 30, 30, 30, 250, 250, 250, 250, 0, 0, 0),
+
+	           SpellData(1, 1, 1, 1, 80, 80, 80, 80, 0, 0, 0),  //3 earth
+	           SpellData(2, 2, 2, 2, 100, 100, 100, 100, 0, 0, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 110, 100, 90, 80, 5, 3, 0),
+	           SpellData(5, 5, 5, 5, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 100, 100, 90, 80, 0, 9, 0),
+	           SpellData(10, 10, 10, 10, 140, 140, 140, 140, 0, 0, 0),
+	           SpellData(15, 15, 15, 15, 90, 90, 90, 80, 0, 8, 0),
+	           SpellData(20, 20, 20, 20, 150, 150, 150, 150, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 100, 100, 100, 90, 20, 1, 0),
+	           SpellData(30, 30, 30, 30, 90, 90, 90, 90, 25, 0, 0),
+
+	           SpellData(1, 1, 1, 1, 100, 100, 100, 100, 0, 0, 0),  //4 spirit
+	           SpellData(2, 2, 2, 2, 100, 100, 100, 100, 0, 0, 0),
+	           SpellData(3, 3, 3, 3, 90, 90, 90, 90, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(5, 5, 5, 5, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(10, 10, 10, 10, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(15, 15, 15, 15, 100, 100, 100, 100, 10, 8, 0),
+	           SpellData(20, 20, 20, 20, 240, 240, 240, 240, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 150, 150, 150, 150, 0, 0, 0),
+	           SpellData(30, 30, 30, 30, 1000, 1000, 1000, 1000, 0, 0, 0),
+
+	           SpellData(1, 1, 1, 1, 120, 120, 120, 120, 0, 0, 0),  //5 mind
+	           SpellData(2, 2, 2, 2, 110, 110, 110, 110, 3, 3, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 110, 100, 90, 80, 0, 0, 0),
+	           SpellData(5, 5, 5, 5, 100, 100, 100, 100, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(10, 10, 10, 10, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(15, 15, 15, 15, 80, 80, 80, 80, 0, 0, 0),
+	           SpellData(20, 20, 20, 20, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 110, 110, 110, 100, 12, 12, 0),
+	           SpellData(30, 30, 30, 30, 120, 120, 120, 120, 0, 0, 0),
+
+	           SpellData(1, 1, 1, 1, 120, 120, 120, 120, 0, 0, 0),  //6 body
+	           SpellData(2, 2, 2, 2, 100, 100, 100, 100, 0, 0, 0),
+	           SpellData(3, 3, 3, 3, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(4, 4, 4, 4, 110, 100, 90, 80, 8, 2, 0),
+	           SpellData(5, 5, 5, 5, 110, 110, 110, 110, 0, 0, 0),
+	           SpellData(8, 8, 8, 8, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(10, 10, 10, 10, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(15, 15, 15, 15, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(20, 20, 20, 20, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 110, 110, 110, 100, 30, 5, 0),
+	           SpellData(30, 30, 30, 30, 100, 100, 100, 100, 0, 0, 0),
+
+	           SpellData(5, 5, 5, 5, 110, 100, 90, 80, 0, 4, 0),   //7 light
+	           SpellData(10, 10, 10, 10, 120, 110, 100, 90, 16, 16, 0),
+	           SpellData(15, 15, 15, 15, 120, 110, 100, 90, 0, 0, 0),
+	           SpellData(20, 20, 20, 20, 160, 140, 120, 100, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 140, 140, 140, 140, 0, 0, 0),
+	           SpellData(30, 30, 30, 30, 500, 500, 500, 500, 0, 0, 0),
+	           SpellData(35, 35, 35, 35, 135, 135, 120, 100, 25, 1, 0),
+	           SpellData(40, 40, 40, 40, 500, 500, 500, 500, 0, 0, 0),
+	           SpellData(45, 45, 45, 45, 250, 250, 250, 250, 0, 0, 0),
+	           SpellData(50, 50, 50, 50, 150, 150, 150, 135, 20, 20, 0),
+	           SpellData(55, 55, 55, 55, 300, 300, 300, 300, 0, 0, 0),
+
+	           SpellData(10, 10, 10, 10, 140, 140, 140, 140, 0, 0, 0),  //8 dark
+	           SpellData(15, 15, 15, 15, 120, 110, 100, 90, 25, 10, 0),
+	           SpellData(20, 20, 20, 20, 120, 100, 90, 120, 0, 0, 0),
+	           SpellData(25, 25, 25, 25, 120, 120, 120, 120, 0, 0, 0),
+	           SpellData(30, 30, 30, 30, 90, 90, 80, 70, 6, 6, 0),
+	           SpellData(35, 35, 35, 35, 120, 120, 100, 80, 0, 0, 0),
+	           SpellData(40, 40, 40, 40, 110, 110, 110, 110, 0, 0, 0),
+	           SpellData(45, 45, 45, 45, 200, 200, 200, 150, 0, 0, 0),
+	           SpellData(50, 50, 50, 50, 120, 120, 120, 100, 0, 25, 0),
+	           SpellData(55, 55, 55, 55, 250, 250, 250, 250, 50, 1, 0),
+	           SpellData(60, 60, 60, 60, 300, 300, 300, 300, 25, 8, 0)
+  }};
+
+std::array<unsigned int, 25> wand_spell_ids =
+{
+// 135 Wand of Fire               136 Wand of Sparks             137 Wand of Poison             138 Wand of Stunning           139 Wand of Harm
+  SPELL_FIRE_FIRE_BOLT,           SPELL_AIR_SPARKS,              SPELL_WATER_POISON_SPRAY,      SPELL_EARTH_STUN,              SPELL_BODY_HARM,
+// 140 Fairy Wand of Light        141 Fairy Wand of Ice          142 Fairy Wand of Lashing      143 Fairy Wand of Mind         144 Fairy Wand of Swarms
+  SPELL_LIGHT_LIGHT_BOLT,         SPELL_WATER_ICE_BOLT,          SPELL_SPIRIT_SPIRIT_LASH,      SPELL_MIND_MIND_BLAST,         SPELL_EARTH_DEADLY_SWARM,
+// 145 Alacorn Wand of Fireballs  146 Alacorn Wand of Acid       147 Alacorn Wand of Lightning  148 Alacorn Wand of Blades     149 Alacorn Wand of Charms
+  SPELL_FIRE_FIREBALL,            SPELL_WATER_ACID_BURST,        SPELL_AIR_LIGHNING_BOLT,       SPELL_EARTH_BLADES,            SPELL_MIND_CHARM,
+// 150 Arcane Wand of Blasting    151 Arcane Wand of The Fist    152 Arcane Wand of Rocks       153 Arcane Wand of Paralyzing  154 Arcane Wand of Clouds
+  SPELL_WATER_ICE_BLAST,          SPELL_BODY_FLYING_FIST,        SPELL_EARTH_ROCK_BLAST,        SPELL_LIGHT_PARALYZE,          SPELL_DARK_TOXIC_CLOUD,
+// 155 Mystic Wand of Implosion   156 Mystic Wand of Distortion  157 Mystic Wand of Sharpmetal  158 Mystic Wand of Shrinking   159 Mystic Wand of Incineration
+  SPELL_AIR_IMPLOSION,            SPELL_EARTH_MASS_DISTORTION,   SPELL_DARK_SHARPMETAL,         SPELL_DARK_SHRINKING_RAY,      SPELL_FIRE_INCINERATE
+};
+
+
+std::array<std::array<unsigned char, 12>, 9> pSpellbookSpellIndices = // 4E2430
+	{{  //0   1   2   3  4    5   6  7    8  9   10  11
+		{0,  3,  1,  8, 11,  7,  4, 10,  6,  2,  5,  9},
+		{0, 11,  2,  9,  6,  8,  5, 10,  3,  7,  1,  4},
+		{0,  4,  8,  9,  1, 10,  3, 11,  7,  6,  2,  5}, 
+		{0,  7, 10,  8,  2, 11,  1,  5,  3,  6,  4,  9},
+		{0,  5, 10, 11,  7,  2,  8,  1,  4,  9,  3,  6},
+		{0,  5,  9,  8,  3,  7,  6,  4,  1, 11,  2, 10}, 
+		{0,  1,  6,  9,  3,  5,  8, 11,  7, 10,  4,  2},
+		{0,  1, 10, 11,  9,  4,  3,  6,  5,  7,  8,  2},
+		{0,  9,  3,  7,  1,  5,  2, 10, 11,  8,  6,  4}
+}};
+
+	std::array<std::array<struct SpellBookIconPos, 12>, 9> pIconPos={{
+
+		 {  0,   0,  17,  13, 115,   2, 217,  15,
+		 299,   6,  28, 125, 130, 133, 294, 114,
+      11, 232, 134, 233, 237, 171, 296, 231},
+
+		 {  0,   0, 19,   9, 117,   3, 206,  13,	
+		 285,   7,  16, 123, 113, 101, 201, 118,
+		 317, 110,  11, 230, 149, 236, 296, 234},
+
+		 {  0,   0,  17,   9, 140,   0, 210,  34,
+		 293,   5,   15,  98,  78, 121, 175, 136,
+     301, 115,   15, 226, 154, 225, 272, 220},
+
+		 { 0,    0,   7,   9, 156,   2, 277,   9,
+		  11, 117, 111,  82, 180, 102, 303, 108,
+		  10, 229, 120, 221, 201, 217, 296, 225},
+
+		 {  0,   0,  18,   8,  89,  15, 192,  14,
+		 292,   7,  22, 129, 125, 146, 217, 136,
+		 305, 115,  22, 226, 174, 237, 290, 231},
+
+     { 0,    0,  18,  12, 148,   9, 292,   7,
+     17, 122, 121,  99, 220,  87, 293, 112,
+     13, 236, 128, 213, 220, 223, 315, 223},
+
+     {  0,   0,  23,  14, 127,   8, 204, 0,
+     306,   8,  14, 115, 122, 132, 200, 116,
+     293, 122,  20, 228, 154, 228, 294, 239},
+
+     {  0,   0,  19,  14, 124,  10, 283,  12,
+     8, 105, 113,  89, 190,  82, 298, 108,
+     18, 181, 101, 204, 204, 203, 285, 218},
+
+		 {  0,   0, 18,  17, 110,  16, 201,  15,
+		 307,  15, 18, 148, 125, 166, 201, 123,
+     275, 120, 28, 235, 217, 222, 324, 216}}};
+
+
+//----- (0042EB31) --------------------------------------------------------
+bool SpellBuff::NotExpired()
+{
+  return (signed __int64)this->uExpireTime > 0 ? true:false;
+}
+
+
+//----- (00458585) --------------------------------------------------------
+void SpellBuff::Reset()
+{
+  uSkill = 0;
+  uPower = 0;
+  uExpireTime = 0i64;
+  uCaster = 0;
+  uFlags = 0;
+  if (uOverlayID)
+  {
+    pOtherOverlayList->pOverlays[uOverlayID - 1].Reset();
+    pOtherOverlayList->bRedraw = true;
+    uOverlayID = 0;
+  }
+}
+
+//----- (004585CA) --------------------------------------------------------
+bool SpellBuff::IsBuffExpiredToTime( __int64 time_end )
+    {
+  if (uExpireTime && (uExpireTime < time_end))
+  {
+    uExpireTime = 0;
+    uPower = 0;
+    uSkill = 0;
+    uOverlayID = 0;
+    return true;
+  }
+  return false;
+}
+
+//----- (004584E0) --------------------------------------------------------
+bool SpellBuff::Apply( signed __int64 uExpireTime, unsigned __int16 uSkillLevel, unsigned __int16 uPower, int uOverlayID, unsigned __int8 caster )
+    {
+  if (this->uExpireTime && (uExpireTime < this->uExpireTime))
+    return false;
+
+  this->uSkill = uSkillLevel;
+  this->uPower = uPower;
+  this->uExpireTime = uExpireTime;
+  if (this->uOverlayID && this->uOverlayID != uOverlayID)
+  {
+    pOtherOverlayList->pOverlays[this->uOverlayID - 1].Reset();
+    pOtherOverlayList->bRedraw = true;
+    this->uOverlayID = 0;
+  }
+  this->uOverlayID = uOverlayID;
+  this->uCaster = caster;
+
+  return true;
+}
+
+//----- (0045384A) --------------------------------------------------------
+void SpellStats::Initialize()
+{
+  std::map<std::string, SPELL_SCHOOL, ci_less> spellSchoolMaps;
+  spellSchoolMaps["fire"] = SPELL_SCHOOL_FIRE;
+  spellSchoolMaps["air"] = SPELL_SCHOOL_AIR;
+  spellSchoolMaps["water"] = SPELL_SCHOOL_WATER;
+  spellSchoolMaps["earth"] = SPELL_SCHOOL_EARTH;
+  spellSchoolMaps["spirit"] = SPELL_SCHOOL_SPIRIT;
+  spellSchoolMaps["mind"] = SPELL_SCHOOL_MIND;
+  spellSchoolMaps["body"] = SPELL_SCHOOL_BODY;
+  spellSchoolMaps["light"] = SPELL_SCHOOL_LIGHT;
+  spellSchoolMaps["dark"] = SPELL_SCHOOL_DARK;
+  spellSchoolMaps["magic"] = SPELL_SCHOOL_MAGIC;
+
+	char* test_string;
+
+	free(pSpellsTXT_Raw);
+	pSpellsTXT_Raw = (char *)pEvents_LOD->LoadRaw("spells.txt", 0);
+
+	strtok(pSpellsTXT_Raw, "\r");
+	for(int i=1; i<100; ++i) 
+  {
+    if (((i % 11) - 1 )==0)
+      strtok(NULL, "\r");
+    test_string=strtok(NULL, "\r")+1;
+    auto tokens = Tokenize(test_string, '\t');
+    pInfos[i].pName=RemoveQuotes(tokens[2]);
+    auto findResult = spellSchoolMaps.find(tokens[3]);
+    pInfos[i].uSchool = findResult == spellSchoolMaps.end() ? SPELL_SCHOOL_NONE : findResult->second;
+    pInfos[i].pShortName=RemoveQuotes(tokens[4]);
+    pInfos[i].pDescription=RemoveQuotes(tokens[5]);
+    pInfos[i].pBasicSkillDesc=RemoveQuotes(tokens[6]);
+    pInfos[i].pExpertSkillDesc=RemoveQuotes(tokens[7]);
+    pInfos[i].pMasterSkillDesc=RemoveQuotes(tokens[8]);
+    pInfos[i].pGrandmasterSkillDesc=RemoveQuotes(tokens[9]);
+    pSpellDatas[i].stats |= strchr(tokens[10], 'm') || strchr(tokens[10], 'M') ? 1 : 0;
+    pSpellDatas[i].stats |= strchr(tokens[10], 'e') || strchr(tokens[10], 'E') ? 2 : 0;
+    pSpellDatas[i].stats |= strchr(tokens[10], 'c') || strchr(tokens[10], 'C') ? 4 : 0;
+    pSpellDatas[i].stats |= strchr(tokens[10], 'x') || strchr(tokens[10], 'X') ? 8 : 0;
+  }
+}
+//----- (00448DF8) --------------------------------------------------------
+void __fastcall EventCastSpell(int uSpellID, int uSkillLevel, int uSkill, int fromx, int fromy, int fromz, int tox, int toy, int toz)//sub_448DF8
+{
+  int v9; // esi@1
+  signed __int64 v10; // st7@4
+  signed __int64 v11; // st6@4
+  signed __int64 v12; // st5@4
+  double v13; // st7@6
+  int v14; // ST44_4@7
+  uint skillMasteryPlusOne; // ebx@9
+  uint v16; // edx@15
+  int i; // esi@42
+  int j; // esi@60
+  unsigned __int64 v36; // qax@99
+//  SpellBuff *v37; // ecx@99
+  int v38; // esi@103
+  signed __int64 v39; // qax@105
+  int v42; // esi@111
+  int v43; // ebx@111
+  int v47; // [sp-4h] [bp-B8h]@35
+  int v49; // [sp+0h] [bp-B4h]@35
+  int v55; // [sp+28h] [bp-8Ch]@7
+  unsigned int yaw; // [sp+30h] [bp-84h]@7
+  int pitch; // [sp+34h] [bp-80h]@7
+  int v60; // [sp+ACh] [bp-8h]@1
+  int a6_4; // [sp+C8h] [bp+14h]@117
+  int a7c; // [sp+CCh] [bp+18h]@29
+  int a7d; // [sp+CCh] [bp+18h]@55
+  signed __int64 xSquared; // [sp+D0h] [bp+1Ch]@6
+  int a8b; // [sp+D0h] [bp+1Ch]@37
+  int a8c; // [sp+D0h] [bp+1Ch]@55
+  signed __int64 ySquared; // [sp+D4h] [bp+20h]@6
+
+  v9 = 0;
+  skillMasteryPlusOne = uSkillLevel + 1;
+  //spellnum_ = uSpellID;
+  v60 = 0;
+  if ( tox || toy || toz )
+  {
+    v10 = tox - fromx;
+    v11 = toy - fromy;
+    v12 = toz - fromz;
+  }
+  else
+  {
+    v10 = pParty->vPosition.x - fromx;
+    v11 = pParty->vPosition.y - fromy;
+    v12 = (pParty->vPosition.z + pParty->sEyelevel) - fromz;
+  }
+  v13 = sqrt(long double(v10 * v10 + v11 * v11 + v12 * v12));
+  if ( v13 <= 1.0 )
+  {
+    v55 = 1;
+    yaw = 0;
+    pitch = 0;
+  }
+  else
+  {
+    v55 = (int)v13;
+    ySquared = v11 * v11;
+    xSquared = v10 * v10;
+    v14 = (int)sqrt(long double(xSquared + ySquared));
+    yaw = stru_5C6E00->Atan2((int)v10, (int)v11);
+    pitch = stru_5C6E00->Atan2(v14, (int)v12);
+  }
+  Assert(skillMasteryPlusOne > 0 && skillMasteryPlusOne <= 4, "Invalid mastery level");
+
+  SpriteObject a1; // [sp+38h] [bp-7Ch]@12
+  //SpriteObject::SpriteObject(&a1);
+
+  switch ( uSpellID )
+  {
+    case SPELL_FIRE_FIRE_BOLT:
+    case SPELL_FIRE_FIREBALL:
+    case SPELL_AIR_LIGHNING_BOLT:
+    case SPELL_WATER_ICE_BOLT:
+    case SPELL_WATER_ACID_BURST:
+    case SPELL_WATER_ICE_BLAST:
+    case SPELL_EARTH_BLADES:
+    case SPELL_EARTH_ROCK_BLAST:
+    case SPELL_WATER_POISON_SPRAY:
+    case SPELL_AIR_SPARKS:
+    case SPELL_EARTH_DEATH_BLOSSOM:
+      a1.uType = stru_4E3ACC[uSpellID].uType;
+      a1.stru_24.Reset();
+      a1.spell_id = uSpellID;
+      a1.spell_level = uSkill;
+      a1.spell_skill = skillMasteryPlusOne;
+      v16 = 0;
+      while (v16 < pObjectList->uNumObjects)
+      {
+        if ( a1.uType == pObjectList->pObjects[v16].uObjectID)
+        {
+          break;
+        }
+        v16++;
+      }
+      a1.uObjectDescID = v16;
+      a1.vPosition.x = fromx;
+      a1.vPosition.y = fromy;
+      a1.vPosition.z = fromz;
+      a1.uAttributes = 16;
+      a1.uSectorID = pIndoor->GetSector(fromx, fromy, fromz);
+      a1.field_60_distance_related_prolly_lod = v55;
+      a1.uSpriteFrameID = 0;
+      a1.spell_caster_pid = 8000 | OBJECT_Item;
+      a1.uSoundID = 0;
+      break;
+  }
+
+  switch ( uSpellID )
+  {
+    case SPELL_FIRE_FIRE_BOLT:
+    case SPELL_FIRE_FIREBALL:
+    case SPELL_AIR_LIGHNING_BOLT:
+    case SPELL_WATER_ICE_BOLT:
+    case SPELL_WATER_ACID_BURST:
+    case SPELL_WATER_ICE_BLAST:
+    case SPELL_EARTH_BLADES:
+    case SPELL_EARTH_ROCK_BLAST:
+      //v20 = yaw;
+      a1.spell_target_pid = 0;
+      a1.uFacing = yaw;
+      a1.uSoundID = 0;
+      v49 = pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed;
+      a1.Create(yaw, pitch, v49, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_WATER_POISON_SPRAY:
+      switch ( skillMasteryPlusOne )
+      {
+        case 1:
+          v60 = 1;
+          break;
+        case 2:
+          v60 = 3;
+          break;
+        case 3:
+          v60 = 5;
+          break;
+        case 4:
+          v60 = 7;
+          break;
+      }
+      a1.spell_target_pid = 0;
+      a1.uFacing = yaw;
+      if ( v60 == 1 )
+      {
+        v49 = pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed;
+        a1.Create(yaw, pitch, v49, 0);
+      }
+      else
+      {
+        a7c = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360;
+        a8b = a7c / (v60 - 1);
+        for ( i = a7c / -2; i <= a7c / 2; i += a8b )
+        {
+          a1.uFacing = i + yaw;
+          a1.Create((signed __int16)(i + (short)yaw), pitch, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0);
+        }
+      }
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_AIR_SPARKS:
+      switch ( skillMasteryPlusOne )
+      {
+        case 1:
+          v60 = 3;
+          break;
+        case 2:
+          v60 = 5;
+          break;
+        case 3:
+          v60 = 7;
+          break;
+        case 4:
+          v60 = 9;
+          break;
+      }
+      a7d = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360;
+      a8c = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360 / (v60 - 1);
+      a1.spell_target_pid = 4;
+      for ( j = a7d / -2; j <= a7d / 2; j += a8c )
+      {
+        a1.uFacing = j + yaw;
+        a1.Create((signed __int16)(j + (short)yaw), pitch, pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0);
+      }
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_EARTH_DEATH_BLOSSOM:
+      if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
+        return;
+      a1.spell_target_pid = 4;
+      v49 = pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed;
+      v47 = (signed int)stru_5C6E00->uIntegerHalfPi / 2;
+      a1.Create(yaw, v47, v49, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+
+    case SPELL_FIRE_HASTE:
+      if ( skillMasteryPlusOne > 0 )
+      {
+        if ( skillMasteryPlusOne <= 2 )
+          v9 = 60 * (uSkill + 60);
+        else if ( skillMasteryPlusOne == 3 )
+          v9 = 180 * (uSkill + 20);
+        else if ( skillMasteryPlusOne == 4 )
+          v9 = 240 * (uSkill + 15);
+      }
+      for (uint i = 0; i < 4; ++i)
+        if (pParty->pPlayers[i].IsWeak())
+          return;
+      pParty->pPartyBuffs[PARTY_BUFF_HASTE].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)(v9 * 128) * 0.033333335), skillMasteryPlusOne, 0, 0, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 1);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 2);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 3);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);//звук алтаря
+      return;
+    case SPELL_AIR_SHIELD:
+    case SPELL_EARTH_STONESKIN:
+    case SPELL_SPIRIT_HEROISM:
+      switch ( skillMasteryPlusOne )
+      {
+        case 1:
+        case 2:
+          v9 = 300 * (uSkill + 12);
+          break;
+        case 3:
+          v9 = 900 * (uSkill + 4);
+          break;
+        case 4:
+          v9 = 3600 * (uSkill + 1);
+          break;
+      }
+      switch ( uSpellID )
+      {
+        case SPELL_AIR_SHIELD:
+          v60 = 0;
+          uSkill = 14;
+          break;
+        case SPELL_EARTH_STONESKIN:
+          v60 = uSkill + 5;
+          uSkill = 15;
+          break;
+        case SPELL_SPIRIT_HEROISM:
+          v60 = uSkill + 5;
+          uSkill = 9;
+          break;
+      }
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 1);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 2);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 3);
+      v36 = pParty->uTimePlayed + (signed int)(signed __int64)((double)(v9 << 7) * 0.033333335);
+      pParty->pPartyBuffs[uSkill].Apply(v36, skillMasteryPlusOne, v60, 0, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_FIRE_IMMOLATION:
+      if (skillMasteryPlusOne == 4)
+        v38 = 600 * uSkill;
+      else
+        v38 = 60 * uSkill;
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 1);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 2);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 3);
+      v39 = (signed __int64)((double)(v38 << 7) * 0.033333335);
+      v36 = pParty->uTimePlayed + v39;
+      pParty->pPartyBuffs[PARTY_BUFF_IMMOLATION].Apply(v36, skillMasteryPlusOne, uSkill, 0, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_FIRE_PROTECTION_FROM_FIRE:
+    case SPELL_AIR_PROTECTION_FROM_AIR:
+    case SPELL_WATER_PROTECTION_FROM_WATER:
+    case SPELL_EARTH_PROTECTION_FROM_EARTH:
+    case SPELL_MIND_PROTECTION_FROM_MIND:
+    case SPELL_BODY_PROTECTION_FROM_BODY:
+      a6_4 = 3600 * uSkill;
+      switch (skillMasteryPlusOne)
+      {
+      case 1:
+        v60 = uSkill;
+        break;
+      case 2:
+        v60 = 2 * uSkill;
+        break;
+      case 3:
+        v60 = 3 * uSkill;
+        break;
+      case 4:
+        v60 = 4 * uSkill;
+        break;
+      }
+      switch ( uSpellID )
+      {
+      case SPELL_FIRE_PROTECTION_FROM_FIRE:
+        uSkill = PARTY_BUFF_RESIST_FIRE;
+        break;
+      case SPELL_AIR_PROTECTION_FROM_AIR:
+        uSkill = PARTY_BUFF_RESIST_AIR;
+        break;
+      case SPELL_WATER_PROTECTION_FROM_WATER:
+        uSkill = PARTY_BUFF_RESIST_WATER;
+        break;
+      case SPELL_EARTH_PROTECTION_FROM_EARTH:
+        uSkill = PARTY_BUFF_RESIST_EARTH;
+        break;
+      case SPELL_MIND_PROTECTION_FROM_MIND:
+        uSkill = PARTY_BUFF_RESIST_MIND;
+        break;
+      case SPELL_BODY_PROTECTION_FROM_BODY:
+        uSkill = PARTY_BUFF_RESIST_BODY;
+        break;
+      }
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 1);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 2);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 3);
+      pParty->pPartyBuffs[uSkill].Apply(pParty->uTimePlayed + (signed int)(signed __int64)((double)a6_4 * 4.2666669), skillMasteryPlusOne, v60, 0, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    case SPELL_LIGHT_DAY_OF_THE_GODS :
+      switch (skillMasteryPlusOne)
+      {
+      case 2:
+        v42 = 10800 * uSkill;
+        v43 = 3 * uSkill + 10;
+        break;
+      case 3:
+        v42 = 18000 * uSkill;
+        v43 = 5 * uSkill + 10;
+        break;
+      case 4:
+        v42 = 14400 * uSkill;
+        v43 = 4 * uSkill + 10;
+        break;
+      }
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 0);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 1);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 2);
+      pGame->pStru6Instance->SetPlayerBuffAnim(uSpellID, 3);
+      v39 = (signed __int64)((double)(v42 << 7) * 0.033333335);
+      v36 = pParty->uTimePlayed + v39;
+      pParty->pPartyBuffs[PARTY_BUFF_DAY_OF_GODS].Apply(v36, skillMasteryPlusOne, v43, 0, 0);
+      pAudioPlayer->PlaySound((SoundID)word_4EE088_sound_ids[uSpellID], 0, 0, fromx, fromy, 0, 0, 0);
+      return;
+    default:
+      return;
+  }
+}
+//----- (00427769) --------------------------------------------------------
+bool sub_427769_isSpellQuickCastableOnShiftClick(unsigned int uSpellID)
+{
+  return ( pSpellDatas[uSpellID].stats & 0xC ) != 0;
+}
+//----- (0043AFE3) --------------------------------------------------------
+int _43AFE3_calc_spell_damage(int spellId, int spellLevel, signed int skillMastery, int currentHp)
+{
+  int result; // eax@1
+  unsigned int v5; // [sp-4h] [bp-8h]@9
+
+  result = 0;
+  if ( spellId == SPELL_FIRE_FIRE_SPIKE )
+  {
+    switch (skillMastery)
+    {
+    case 1:
+    case 2:
+      v5 = 6;
+    case 3:
+      v5 = 8;
+    case 4:
+      v5 = 10;
+    default:
+      return 0;
+    }
+    result = GetDiceResult(spellLevel, v5);
+  }
+  else if ( spellId == SPELL_EARTH_MASS_DISTORTION )
+    result = currentHp * (pSpellDatas[SPELL_EARTH_MASS_DISTORTION].baseDamage + 2 * spellLevel) / 100;
+  else
+    result = pSpellDatas[spellId].baseDamage 
+    + GetDiceResult(spellLevel, pSpellDatas[spellId].bonusSkillDamage);
+
+  return result;
+}
\ No newline at end of file