Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

Как создать плагин для HD мода

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 25 авг 2021, 09:41

 Update
Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include <bitset>
#include "..\..\HotA\homm3.h"

#define SPELLS_MAX 128
#define ANIMS_MAX 128
#define ADVSPELLS_NUM 10
#define SPECABIL_NUM 11
#define ARTIFACTS_NUM 144

#define SPELLS_NUM 87
#define SPL_FEAR_NEW 81
#define SPL_POISON_NEW 82
#define SPL_DISEASE_NEW 83
#define SPL_AGING_NEW 84
#define SPL_DEATH_CLOUD_NEW 85
#define SPL_DEATH_BLOW_NEW 86

#define ANIMS_NUM 89
#define ANIM_FEAR_NEW 83
#define ANIM_POISON_NEW 84
#define ANIM_DISEASE_NEW 85
#define ANIM_AGING_NEW 86
#define ANIM_DEATH_CLOUD_NEW 87
#define ANIM_DEATH_BLOW_NEW 88

Patcher* _P;
PatcherInstance* _PI;

struct _ComboArtInfo_ {
   int index;
   std::bitset<160> parts;
};

struct _MagicAnim_ {
   char* defName;
   char* name;
   int type;
};

#define o_ComboArtInfo (*(_ComboArtInfo_**)0x660B6C)
#define o_MagicAnim ((_MagicAnim_*)0x641E18)

_Spell_ spell[SPELLS_MAX];
_MagicAnim_ anim[ANIMS_MAX];
//char iniPath[MAX_PATH];

char spellIndirectTableA[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  2,  3,  4,  4,  4,  4,  4,
    5,  5,  5,  5,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    6,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  5,
    4,  4,  4,  7,  8,  9, 10, 10, 10, 10,
   // Special Abilities (you cannot cast them anyway)
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
   4, 4, 4, 4, 5, 4
};

char spellIndirectTableB[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
   10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
   17, 17, 17, 17, 17, 18, 17, 19, 20, 20,
   21, 17, 17, 22, 17, 17, 17, 23, 17, 17,
   17, 17, 17, 17, 17, 17, 17,  7, 17, 24,
   17, 17, 17, 25, 26, 27, 28, 29, 30, 31,
   // Special Abilities
   32, 33, 34, 17, 17, 34, 37, 37, 35, 37,
   36,
   // New Spells (starting from Fear #81)
   17, 17, 17, 17, 11, 17
};

char spellIndirectTableC[] = {
   // Spells (starting from Shield #27)
    0,  1,  2,  3,  4,  5,  6,  7, 32,  8,
   32, 32, 32, 32,  9, 10, 11, 12, 13, 14,
   32, 15, 16, 17, 18, 19, 20, 21, 22, 23,
   32, 24, 25, 26, 27, 28, 32, 32, 32, 32,
   32, 32, 32,
   // Special Abilities
   32, 29, 32, 30, 32, 31, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
   32, 32, 32, 32, 32, 32
};

bool shrineSpells[SPELLS_MAX];

int __stdcall afterInit(LoHook* h, HookContext* c)
{
   // Spell Table
   for (int i = 0; i < SPL_FEAR_NEW; ++i)
      spell[i] = o_Spell[i];

   // Fear
   spell[SPL_FEAR_NEW].type = -1;
   spell[SPL_FEAR_NEW].wav_name = "FearRoE.wav";
   spell[SPL_FEAR_NEW].animation_ix = ANIM_FEAR_NEW;
   spell[SPL_FEAR_NEW].flags = 0x20415;
   spell[SPL_FEAR_NEW].name = "Fear";
   spell[SPL_FEAR_NEW].short_name = "Fear";
   spell[SPL_FEAR_NEW].level = 4;
   spell[SPL_FEAR_NEW].school_flags = 8;
   spell[SPL_FEAR_NEW].mana_cost[0] = 16;
   spell[SPL_FEAR_NEW].mana_cost[1] = 8;
   spell[SPL_FEAR_NEW].mana_cost[2] = 8;
   spell[SPL_FEAR_NEW].mana_cost[3] = 8;
   spell[SPL_FEAR_NEW].eff_power = 0;
   spell[SPL_FEAR_NEW].effect[0] = 75;
   spell[SPL_FEAR_NEW].effect[1] = 75;
   spell[SPL_FEAR_NEW].effect[2] = 50;
   spell[SPL_FEAR_NEW].effect[3] = 25;
   spell[SPL_FEAR_NEW].chance2get_var[0] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[1] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[2] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[3] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[4] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[5] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[6] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[7] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[8] = 10;
   spell[SPL_FEAR_NEW].ai_value[0] = 50;
   spell[SPL_FEAR_NEW].ai_value[1] = 50;
   spell[SPL_FEAR_NEW].ai_value[2] = 50;
   spell[SPL_FEAR_NEW].ai_value[3] = 50;
   spell[SPL_FEAR_NEW].description[0] =
      "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n";
   spell[SPL_FEAR_NEW].description[1] =
      "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n";
   spell[SPL_FEAR_NEW].description[2] =
      "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n";
   spell[SPL_FEAR_NEW].description[3] =
      "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";

   // Poison
   spell[SPL_POISON_NEW].type = -1;
   spell[SPL_POISON_NEW].wav_name = "Poison.wav";
   spell[SPL_POISON_NEW].animation_ix = ANIM_POISON_NEW;
   spell[SPL_POISON_NEW].flags = 0x1015;
   spell[SPL_POISON_NEW].name = "Poison";
   spell[SPL_POISON_NEW].short_name = "Poison";
   spell[SPL_POISON_NEW].level = 4;
   spell[SPL_POISON_NEW].school_flags = 8;
   spell[SPL_POISON_NEW].mana_cost[0] = 20;
   spell[SPL_POISON_NEW].mana_cost[1] = 16;
   spell[SPL_POISON_NEW].mana_cost[2] = 16;
   spell[SPL_POISON_NEW].mana_cost[3] = 16;
   spell[SPL_POISON_NEW].eff_power = 0;
   spell[SPL_POISON_NEW].effect[0] = 0;
   spell[SPL_POISON_NEW].effect[1] = 0;
   spell[SPL_POISON_NEW].effect[2] = 0;
   spell[SPL_POISON_NEW].effect[3] = 0;
   spell[SPL_POISON_NEW].chance2get_var[0] = 10;
   spell[SPL_POISON_NEW].chance2get_var[1] = 10;
   spell[SPL_POISON_NEW].chance2get_var[2] = 10;
   spell[SPL_POISON_NEW].chance2get_var[3] = 10;
   spell[SPL_POISON_NEW].chance2get_var[4] = 10;
   spell[SPL_POISON_NEW].chance2get_var[5] = 10;
   spell[SPL_POISON_NEW].chance2get_var[6] = 10;
   spell[SPL_POISON_NEW].chance2get_var[7] = 10;
   spell[SPL_POISON_NEW].chance2get_var[8] = 10;
   spell[SPL_POISON_NEW].ai_value[0] = 50;
   spell[SPL_POISON_NEW].ai_value[1] = 50;
   spell[SPL_POISON_NEW].ai_value[2] = 50;
   spell[SPL_POISON_NEW].ai_value[3] = 50;
   spell[SPL_POISON_NEW].description[0] =
      "{Poison}\n\nPoison Description.\n";
   spell[SPL_POISON_NEW].description[1] =
      "{Basic Poison}\n\nBasic Poison Description.\n";
   spell[SPL_POISON_NEW].description[2] =
      "{Advanced Poison}\n\nAdvanced Poison Description.\n";
   spell[SPL_POISON_NEW].description[3] =
      "{Expert Poison}\n\nExpert Poison Description.\n";

   // Disease
   spell[SPL_DISEASE_NEW].type = -1;
   spell[SPL_DISEASE_NEW].wav_name = "Disease.wav";
   spell[SPL_DISEASE_NEW].animation_ix = ANIM_DISEASE_NEW;
   spell[SPL_DISEASE_NEW].flags = 0x1015;
   spell[SPL_DISEASE_NEW].name = "Disease";
   spell[SPL_DISEASE_NEW].short_name = "Disease";
   spell[SPL_DISEASE_NEW].level = 4;
   spell[SPL_DISEASE_NEW].school_flags = 8;
   spell[SPL_DISEASE_NEW].mana_cost[0] = 16;
   spell[SPL_DISEASE_NEW].mana_cost[1] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[2] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[3] = 12;
   spell[SPL_DISEASE_NEW].eff_power = 0;
   spell[SPL_DISEASE_NEW].effect[0] = 0;
   spell[SPL_DISEASE_NEW].effect[1] = 0;
   spell[SPL_DISEASE_NEW].effect[2] = 0;
   spell[SPL_DISEASE_NEW].effect[3] = 0;
   spell[SPL_DISEASE_NEW].chance2get_var[0] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[1] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[2] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[3] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[4] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[5] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[6] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[7] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[8] = 10;
   spell[SPL_DISEASE_NEW].ai_value[0] = 50;
   spell[SPL_DISEASE_NEW].ai_value[1] = 50;
   spell[SPL_DISEASE_NEW].ai_value[2] = 50;
   spell[SPL_DISEASE_NEW].ai_value[3] = 50;
   spell[SPL_DISEASE_NEW].description[0] =
      "{Disease}\n\nDisease Description.\n";
   spell[SPL_DISEASE_NEW].description[1] =
      "{Basic Disease}\n\nBasic Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[2] =
      "{Advanced Disease}\n\nAdvanced Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[3] =
      "{Expert Disease}\n\nExpert Disease Description.\n";

   // Aging
   spell[SPL_AGING_NEW].type = -1;
   spell[SPL_AGING_NEW].wav_name = "Age.wav";
   spell[SPL_AGING_NEW].animation_ix = ANIM_AGING_NEW;
   spell[SPL_AGING_NEW].flags = 0x1015;
   spell[SPL_AGING_NEW].name = "Aging";
   spell[SPL_AGING_NEW].short_name = "Aging";
   spell[SPL_AGING_NEW].level = 5;
   spell[SPL_AGING_NEW].school_flags = 2;
   spell[SPL_AGING_NEW].mana_cost[0] = 25;
   spell[SPL_AGING_NEW].mana_cost[1] = 20;
   spell[SPL_AGING_NEW].mana_cost[2] = 20;
   spell[SPL_AGING_NEW].mana_cost[3] = 20;
   spell[SPL_AGING_NEW].eff_power = 0;
   spell[SPL_AGING_NEW].effect[0] = 0;
   spell[SPL_AGING_NEW].effect[1] = 0;
   spell[SPL_AGING_NEW].effect[2] = 0;
   spell[SPL_AGING_NEW].effect[3] = 0;
   spell[SPL_AGING_NEW].chance2get_var[0] = 10;
   spell[SPL_AGING_NEW].chance2get_var[1] = 10;
   spell[SPL_AGING_NEW].chance2get_var[2] = 10;
   spell[SPL_AGING_NEW].chance2get_var[3] = 10;
   spell[SPL_AGING_NEW].chance2get_var[4] = 10;
   spell[SPL_AGING_NEW].chance2get_var[5] = 10;
   spell[SPL_AGING_NEW].chance2get_var[6] = 10;
   spell[SPL_AGING_NEW].chance2get_var[7] = 10;
   spell[SPL_AGING_NEW].chance2get_var[8] = 10;
   spell[SPL_AGING_NEW].ai_value[0] = 50;
   spell[SPL_AGING_NEW].ai_value[1] = 50;
   spell[SPL_AGING_NEW].ai_value[2] = 50;
   spell[SPL_AGING_NEW].ai_value[3] = 50;
   spell[SPL_AGING_NEW].description[0] =
      "{Aging}\n\nAging Description.\n";
   spell[SPL_AGING_NEW].description[1] =
      "{Basic Aging}\n\nBasic Aging Description.\n";
   spell[SPL_AGING_NEW].description[2] =
      "{Advanced Aging}\n\nAdvanced Aging Description.\n";
   spell[SPL_AGING_NEW].description[3] =
      "{Expert Aging}\n\nExpert Aging Description.\n";

   // Death Cloud
   spell[SPL_DEATH_CLOUD_NEW].type = 0;
   spell[SPL_DEATH_CLOUD_NEW].wav_name = "Deathcld.wav";
   spell[SPL_DEATH_CLOUD_NEW].animation_ix = ANIM_DEATH_CLOUD_NEW;
   spell[SPL_DEATH_CLOUD_NEW].flags = 0x8281;
   spell[SPL_DEATH_CLOUD_NEW].name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].short_name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].level = 5;
   spell[SPL_DEATH_CLOUD_NEW].school_flags = 8;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_CLOUD_NEW].eff_power = 40;
   spell[SPL_DEATH_CLOUD_NEW].effect[0] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[1] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[2] = 60;
   spell[SPL_DEATH_CLOUD_NEW].effect[3] = 120;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_CLOUD_NEW].description[0] =
      "{Death Cloud}\n\nDeath Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[1] =
      "{Basic Death Cloud}\n\nBasic Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[2] =
      "{Advanced Death Cloud}\n\nAdvanced Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[3] =
      "{Expert Death Cloud}\n\nExpert Death Cloud Description.\n";

   // Death Blow
   spell[SPL_DEATH_BLOW_NEW].type = 1;
   spell[SPL_DEATH_BLOW_NEW].wav_name = "Deathblo.wav";
   spell[SPL_DEATH_BLOW_NEW].animation_ix = ANIM_DEATH_BLOW_NEW;
   spell[SPL_DEATH_BLOW_NEW].flags = 0x1015;
   spell[SPL_DEATH_BLOW_NEW].name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].short_name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].level = 5;
   spell[SPL_DEATH_BLOW_NEW].school_flags = 2;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_BLOW_NEW].eff_power = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[0] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[1] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[2] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[3] = 0;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_BLOW_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_BLOW_NEW].description[0] =
      "{Death Blow}\n\nDeath Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[1] =
      "{Basic Death Blow}\n\nBasic Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[2] =
      "{Advanced Death Blow}\n\nAdvanced Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[3] =
      "{Expert Death Blow}\n\nExpert Death Blow Description.\n";

   _PI->WriteDword(0x687FA8, (int)&spell);

   // Magic Animation Table
   for (int i = 0; i < ANIM_FEAR_NEW; ++i)
      anim[i] = o_MagicAnim[i];

   // Fear
   anim[ANIM_FEAR_NEW].defName = "C07spE0.def";
   anim[ANIM_FEAR_NEW].name = "Fear";
   anim[ANIM_FEAR_NEW].type = 0x101;

   // Poison
   anim[ANIM_POISON_NEW].defName = "sp11_.def";
   anim[ANIM_POISON_NEW].name = "Poison";
   anim[ANIM_POISON_NEW].type = 1;

   // Disease
   anim[ANIM_DISEASE_NEW].defName = "sp05_.def";
   anim[ANIM_DISEASE_NEW].name = "Disease";
   anim[ANIM_DISEASE_NEW].type = 1;

   // Aging
   anim[ANIM_AGING_NEW].defName = "sp01_.def";
   anim[ANIM_AGING_NEW].name = "Aging";
   anim[ANIM_AGING_NEW].type = 1;

   // Death Cloud
   anim[ANIM_DEATH_CLOUD_NEW].defName = "sp04_.def";
   anim[ANIM_DEATH_CLOUD_NEW].name = "DeathCloud";
   anim[ANIM_DEATH_CLOUD_NEW].type = 1;

   // Death Blow
   anim[ANIM_DEATH_BLOW_NEW].defName = "sp03_.def";
   anim[ANIM_DEATH_BLOW_NEW].name = "DeathBlow";
   anim[ANIM_DEATH_BLOW_NEW].type = 1;

   int AnimAddrDefName[] = {0x43F77E, 0x43FB6A, 0x4963FB, 0x4965CF, 0x5A5036, 0x5A6B14, 0x5A7A74, 0x5A962C};
   int AnimAddrName[] = {0x4689C4, 0x49651A, 0x4966CD, 0x5A6D2D, 0x5A7B06};
   
   for (int i = 0; i < sizeof(AnimAddrDefName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrDefName[i], (int)&anim->defName);

   for (int i = 0; i < sizeof(AnimAddrName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrName[i], (int)&anim->name);

   _PI->WriteDword(0x43E503, (int)&anim->type);
   
   return EXEC_DEFAULT;
}

int __stdcall disableCreatureSpells(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;

   return EXEC_DEFAULT;
}

int __stdcall shrineSpellsInit(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;   
   
   memcpy(&shrineSpells, &o_GameMgr->disabled_shrines, sizeof(shrineSpells) / sizeof(bool));   

   c->return_address = 0x4C2641;
   return NO_EXEC_DEFAULT;
}

int __fastcall fillShrines(_GameMgr_* game, int unused_edx, int shrineFlags)
{
   int availSpellsNum = 0;

   for (int i = 0; i < SPELLS_NUM; ++i)
   {
      int lvl = o_Spell[i].level - 1;
      if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         ++availSpellsNum;
   }

   int spell = 0;
   int chosenSpell = 0;

   if (availSpellsNum)
   {
      int rndSpell = Randint(0, availSpellsNum - 1);
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         {
            if (spell == rndSpell) break;
            ++spell;
         }
         ++chosenSpell;
      }
     
      shrineSpells[chosenSpell] = true;
   }
   else
   {
      spell = 0;
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !game->disabled_shrines[i])
         {
            shrineSpells[i] = false;
            ++spell;
         }
      }
     
      chosenSpell = spell ? fillShrines(game, unused_edx, shrineFlags) : ID_NONE;
   }

   return chosenSpell; 
}

int __stdcall DeathCloud(LoHook* h, HookContext* c)
{
   if (c->edx == SPL_DEATH_CLOUD_NEW)
   {
      CALL_5(void, __thiscall, 0x5A4C80, o_BattleMgr, *(int*)(c->ebp + 0xC), SPL_DEATH_CLOUD_NEW, c->esi, *(int*)(c->ebp + 0x1C));
   
      c->return_address = 0x5A2368;
      return NO_EXEC_DEFAULT;
   }

   return EXEC_DEFAULT;
}

void __fastcall updateSpellsFromArtifacts(_Hero_* hero)
{
   for (int iSpell = 0; iSpell < SPELLS_MAX; ++iSpell)
      if (hero->spell[iSpell] > 1) hero->spell[iSpell] = 0;

   for (int iSlot = 0; iSlot < 19; ++iSlot)
   {
      if (hero->doll_art[iSlot].id != ID_NONE)
      {
         if (hero->doll_art[iSlot].id == AID_SPELL_SCROLL)
         {
            if (hero->doll_art[iSlot].mod < SPELLS_NUM && !hero->spell[hero->doll_art[iSlot].mod])
               hero->spell[hero->doll_art[iSlot].mod] = 2;
         }
         else if (o_ArtInfo[hero->doll_art[iSlot].id].new_spell)
         {
            std::bitset<SPELLS_MAX> spells;
            CALL_2(int, __fastcall, 0x4D95C0, &spells, hero->doll_art[iSlot].id);

            for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
            {
               if (spells[iSpell] && !hero->spell[iSpell])
                  hero->spell[iSpell] = 2;
            }

            int comboArtIndex = o_ArtInfo[hero->doll_art[iSlot].id].supercomposite;
            if (comboArtIndex != -1)
            {
               for (int iArt = 0; iArt < ARTIFACTS_NUM; ++iArt)
               {
                  if (o_ComboArtInfo[comboArtIndex].parts[iArt] && o_ArtInfo[iArt].new_spell)
                  {
                     std::bitset<SPELLS_MAX> spells;
                     CALL_2(int, __fastcall, 0x4D95C0, &spells, iArt);

                     for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
                     {
                        if (spells[iSpell] && !hero->spell[iSpell])
                           hero->spell[iSpell] = 2;
                     }
                  }
               }
            }
         }
      }
   }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   static bool plugin_On = false;
   if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
   {
      if ( !plugin_On )
      {
         plugin_On = true;
         _P = GetPatcher();
         _PI = _P->CreateInstance("HD.Plugin.H3.NewSpells");

         //GetCurrentDirectoryA(sizeof(iniPath), iniPath);
         //strcat(iniPath, "\\NewSpells.ini");

         // Moving and Expanding Spell Table
         _PI->WriteLoHook(0x4EE1C1, afterInit);
               
         // nwcthereisnospoon
         _PI->WriteByte (0x402902, SPELLS_NUM);

         // "(Already learned)" Text
         _PI->WriteDword(0x40D97C, 0x3EA);
         
         // AI
         _PI->WriteDword(0x41FBDF, 0x3EA);
         _PI->WriteByte (0x41FC91, SPELLS_NUM);
         _PI->WriteDword(0x425C72, 0x3EA);
         _PI->WriteDword(0x425E98, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x427039, 0x3EA);
         _PI->WriteDword(0x427044, 0x3EA);
         _PI->WriteByte (0x427085, SPELLS_NUM);
         _PI->WriteDword(0x4329C1, 0x3EA);
         _PI->WriteDword(0x432A43, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x432CDE, 0x3EA);
         _PI->WriteDword(0x432D1E, SPELLS_NUM * sizeof(_Spell_));
         // ------------
         // Adventure AI
         // ------------
         _PI->WriteDword(0x430AE5, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x4E57CC, 0x3EA + SPL_SUMMON_BOAT);
         _PI->WriteDword(0x56B346, 0x3EA + SPL_TOWN_PORTAL);
         _PI->WriteDword(0x56B7EA, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x56B93F, 0x3EA + SPL_FLY);
         _PI->WriteDword(0x56B99A, 0x3EA + SPL_WATER_WALK);
         // Battle AI
         _PI->WriteDword(0x43C6F2, SPELLS_NUM * sizeof(_Spell_));
         // Master Genie AI Spell Weighting
         _PI->WriteDword(0x43C21B, SPELLS_NUM * sizeof(_Spell_));
         // AI Quick Battle
         _PI->WriteDword(0x433026, 0x3EA);
         _PI->WriteDword(0x433719, 0x3EA);
         _PI->WriteDword(0x43940C, 0x3EA);
         _PI->WriteDword(0x43C561, 0x3EA);
         // AI Spell Scrolls?
         _PI->WriteDword(0x52A97A, 0x3EA);
         _PI->WriteDword(0x52A9B6, SPELLS_NUM * sizeof(_Spell_));
         
         // Can cast?
         _PI->WriteDword(0x447551, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteDword(0x447C7D, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x447CC8, SPELLS_NUM * sizeof(_Spell_));
         
         // Cheats in battle
         _PI->WriteByte (0x471C57, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x48647A, 0x23);
         _PI->WriteJmp  (0x486485, 0x486498);
         
         _PI->WriteByte (0x4864B0, SPELLS_NUM);
         
         // Load Game?
         _PI->WriteByte (0x48A34B, SPELLS_NUM);
         
         // Scholar Secondary Skill
         _PI->WriteByte (0x4A2743, SPELLS_NUM);

         // New Game?
         _PI->WriteByte (0x4C244D, SPELLS_NUM);
         _PI->WriteByte (0x4C246F, SPELLS_NUM);
         _PI->WriteDword(0x4C24C9, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x4C250E, SPELLS_NUM);
         _PI->WriteDword(0x4C2557, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C260D, SPELLS_NUM * sizeof(_Spell_));

         _PI->WriteByte (0x4E67AC, SPELLS_NUM);
         
         // Cheat Menu?
         _PI->WriteByte (0x4F508B, SPELLS_NUM);
         _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_));
                           
         // Pyramids
         _PI->WriteByte (0x4C170D, SPELLS_NUM);
                 
         // Shrines
         _PI->WriteDword(0x4C92C5, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C9347, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C93C0, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteByte (0x4CEC4F, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x4D8F2E, 0x23);
         _PI->WriteJmp  (0x4D8F36, 0x4D8F49);
         
         _PI->WriteByte (0x4D8F53, SPELLS_NUM);
         _PI->WriteByte (0x4D8F8A, SPELLS_NUM);
         
         // Tome of Air Magic
         _PI->WriteDword(0x4D962D, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Fire Magic
         _PI->WriteDword(0x4D9681, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Water Magic
         _PI->WriteDword(0x4D96D6, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Earth Magic
         _PI->WriteDword(0x4D972E, SPELLS_NUM * sizeof(_Spell_));
         // Spellbinder's Hat
         _PI->WriteDword(0x4D9771, SPELLS_NUM * sizeof(_Spell_));
         
         // Scholars
         _PI->WriteByte (0x5012B7, SPELLS_NUM);
         
         _PI->WriteDword(0x527ACB, 0x3EA);
         _PI->WriteDword(0x527B08, SPELLS_NUM * sizeof(_Spell_));

         // RMG
         _PI->WriteDword(0x534C4B, SPELLS_NUM * sizeof(_Spell_));
         
         // RMG Spell Scrolls
         _PI->WriteDword(0x5353D5, SPELLS_NUM);
         _PI->WriteByte (0x53542B, SPELLS_NUM);
         
         // Spell Book
         _PI->WriteDword(0x59CD5E, 0x3EA);
         _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_));

         // Cast Spell
         _PI->WriteDword(0x5A1AD6, SPELLS_NUM * sizeof(_Spell_));

         // Mage Guild
         _PI->WriteByte (0x5BEA2C, SPELLS_NUM);
         _PI->WriteByte (0x5BEA70, SPELLS_NUM);
         _PI->WriteByte (0x5BEAAD, SPELLS_NUM);
         _PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEB48, SPELLS_NUM);
         _PI->WriteByte (0x5BEB71, SPELLS_NUM);
         _PI->WriteByte (0x5BEBB2, SPELLS_NUM);
         _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEC1B, SPELLS_NUM);
                 
         // Conflux Grail
         _PI->WriteDword(0x5BE512, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BE56E, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5D7464, SPELLS_NUM);
         
         // ---------------------------
         // New _Hero_.spell[140] field
         // ---------------------------
         _PI->WriteCodePatch(0x4D8B72, "%n", 8);
         _PI->WriteCodePatch(0x4D8F7F, "%n", 8);
         _PI->WriteCodePatch(0x4D95AF, "%n", 7);

         // ----------------------------------------
         // New _GameMgr_.disabled_spells[140] field
         // ----------------------------------------
         _PI->WriteByte(0x4C16ED, 4); // Pyramids
         _PI->WriteByte(0x4C254C, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x4C25F1, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x501297, 4); // Scholars
         _PI->WriteByte(0x5BEA55, 4); // Mage Guild
                         
         _PI->WriteDword(0x52AE1C, 0x3EA);

         // ------
         // Battle
         // ------
         _PI->WriteByte (0x4963E9, ANIMS_NUM);
         _PI->WriteByte (0x4965BD, ANIMS_NUM);
         _PI->WriteByte (0x502405, SPELLS_NUM);
         _PI->WriteByte (0x502451, SPELLS_NUM);
         _PI->WriteByte (0x5024CF, SPELLS_NUM);
         _PI->WriteByte (0x502515, SPELLS_NUM);
         _PI->WriteByte (0x502E62, SPELLS_NUM);
         _PI->WriteByte (0x502EB7, SPELLS_NUM);
         _PI->WriteByte (0x59EFD9, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x59EFE4, (int)&spellIndirectTableA);
         _PI->WriteByte (0x5A064E, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x5A0659, (int)&spellIndirectTableB);
         //_PI->WriteDword(0x4446FD, (int)&spellIndirectTableC);
                 
         // --------------------------------------------------
         // New _BattleStack_.active_spell_duration[162] field
         // --------------------------------------------------
         _PI->WriteDword(0x43788D, 162);
         _PI->WriteCodePatch(0x437880, "%n", 19);
         _PI->WriteDword(0x53D314, 162);
         _PI->WriteDword(0x43E3DF, SPELLS_NUM);
         _PI->WriteByte (0x443F63, SPELLS_NUM);
         _PI->WriteByte (0x446F03, SPELLS_NUM);
         _PI->WriteByte (0x5A1907, SPELLS_NUM);
         _PI->WriteByte (0x5A1995, SPELLS_NUM);
         _PI->WriteByte (0x5A84C8, SPELLS_NUM);
         _PI->WriteByte (0x5A852F, SPELLS_NUM);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteJmp  (0x444694, 0x4450C2);
         
         // Disable creature spells
         _PI->WriteLoHook(0x4C2567, disableCreatureSpells);

         // Shrine Spells
         _PI->WriteLoHook(0x4C2625, shrineSpellsInit);
         _PI->WriteHiHook(0x4C9260, SPLICE_, DIRECT_, THISCALL_, fillShrines);
         
         // Death Cloud
         _PI->WriteLoHook(0x5A0F4C, DeathCloud);

         // Artifacts (incl. Spell Scrolls);
         _PI->WriteHiHook(0x4D9840, SPLICE_, DIRECT_, THISCALL_, updateSpellsFromArtifacts);
      }
   }

   return TRUE;
}
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 25 авг 2021, 09:49

А что изменилось или добавилось в апдейте?
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 25 авг 2021, 09:55

Прошёлся по коду, добавил пропущенные адреса. Теперь заклинания должны сниматься корректно (но нужно, конечно, тестить). Буду теперь пробовать пилить Антимолитву.

Так, что-то пропустил. Вылетает на проверке эффектов заклинаний :smile14:

Описка. Вместо _PI->WriteDword(0x53D314, 162); нужно _PI->WriteDword(0x43D314, 162);

Что-то починил, что-то сломал :smile1: Теперь проблемы со взвешиванием заклинаний AI.

Нашёл ошибку (была при копировании массива active_spell_duration):

 
Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include <bitset>
#include "..\..\HotA\homm3.h"

#define SPELLS_MAX 128
#define ANIMS_MAX 128
#define ADVSPELLS_NUM 10
#define SPECABIL_NUM 11
#define ARTIFACTS_NUM 144

#define SPELLS_NUM 87
#define SPL_FEAR_NEW 81
#define SPL_POISON_NEW 82
#define SPL_DISEASE_NEW 83
#define SPL_AGING_NEW 84
#define SPL_DEATH_CLOUD_NEW 85
#define SPL_DEATH_BLOW_NEW 86

#define ANIMS_NUM 89
#define ANIM_FEAR_NEW 83
#define ANIM_POISON_NEW 84
#define ANIM_DISEASE_NEW 85
#define ANIM_AGING_NEW 86
#define ANIM_DEATH_CLOUD_NEW 87
#define ANIM_DEATH_BLOW_NEW 88

Patcher* _P;
PatcherInstance* _PI;

struct _ComboArtInfo_ {
   int index;
   std::bitset<160> parts;
};

struct _MagicAnim_ {
   char* defName;
   char* name;
   int type;
};

#define o_ComboArtInfo (*(_ComboArtInfo_**)0x660B6C)
#define o_MagicAnim ((_MagicAnim_*)0x641E18)

_Spell_ spell[SPELLS_MAX];
_MagicAnim_ anim[ANIMS_MAX];
//char iniPath[MAX_PATH];

char spellIndirectTableA[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  2,  3,  4,  4,  4,  4,  4,
    5,  5,  5,  5,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    6,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  5,
    4,  4,  4,  7,  8,  9, 10, 10, 10, 10,
   // Special Abilities (you cannot cast them anyway)
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
   4, 4, 4, 4, 5, 4
};

char spellIndirectTableB[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
   10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
   17, 17, 17, 17, 17, 18, 17, 19, 20, 20,
   21, 17, 17, 22, 17, 17, 17, 23, 17, 17,
   17, 17, 17, 17, 17, 17, 17,  7, 17, 24,
   17, 17, 17, 25, 26, 27, 28, 29, 30, 31,
   // Special Abilities
   32, 33, 34, 17, 17, 34, 37, 37, 35, 37,
   36,
   // New Spells (starting from Fear #81)
   17, 17, 17, 17, 11, 17
};

char spellIndirectTableC[] = {
   // Spells (starting from Shield #27)
    0,  1,  2,  3,  4,  5,  6,  7, 32,  8,
   32, 32, 32, 32,  9, 10, 11, 12, 13, 14,
   32, 15, 16, 17, 18, 19, 20, 21, 22, 23,
   32, 24, 25, 26, 27, 28, 32, 32, 32, 32,
   32, 32, 32,
   // Special Abilities
   32, 29, 32, 30, 32, 31, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
   32, 32, 32, 32, 32, 32
};

bool shrineSpells[SPELLS_MAX];

int __stdcall afterInit(LoHook* h, HookContext* c)
{
   // Spell Table
   for (int i = 0; i < SPL_FEAR_NEW; ++i)
      spell[i] = o_Spell[i];

   // Fear
   spell[SPL_FEAR_NEW].type = -1;
   spell[SPL_FEAR_NEW].wav_name = "FearRoE.wav";
   spell[SPL_FEAR_NEW].animation_ix = ANIM_FEAR_NEW;
   spell[SPL_FEAR_NEW].flags = 0x20415;
   spell[SPL_FEAR_NEW].name = "Fear";
   spell[SPL_FEAR_NEW].short_name = "Fear";
   spell[SPL_FEAR_NEW].level = 4;
   spell[SPL_FEAR_NEW].school_flags = 8;
   spell[SPL_FEAR_NEW].mana_cost[0] = 16;
   spell[SPL_FEAR_NEW].mana_cost[1] = 8;
   spell[SPL_FEAR_NEW].mana_cost[2] = 8;
   spell[SPL_FEAR_NEW].mana_cost[3] = 8;
   spell[SPL_FEAR_NEW].eff_power = 0;
   spell[SPL_FEAR_NEW].effect[0] = 75;
   spell[SPL_FEAR_NEW].effect[1] = 75;
   spell[SPL_FEAR_NEW].effect[2] = 50;
   spell[SPL_FEAR_NEW].effect[3] = 25;
   spell[SPL_FEAR_NEW].chance2get_var[0] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[1] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[2] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[3] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[4] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[5] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[6] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[7] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[8] = 10;
   spell[SPL_FEAR_NEW].ai_value[0] = 50;
   spell[SPL_FEAR_NEW].ai_value[1] = 50;
   spell[SPL_FEAR_NEW].ai_value[2] = 50;
   spell[SPL_FEAR_NEW].ai_value[3] = 50;
   spell[SPL_FEAR_NEW].description[0] =
      "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n";
   spell[SPL_FEAR_NEW].description[1] =
      "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n";
   spell[SPL_FEAR_NEW].description[2] =
      "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n";
   spell[SPL_FEAR_NEW].description[3] =
      "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";

   // Poison
   spell[SPL_POISON_NEW].type = -1;
   spell[SPL_POISON_NEW].wav_name = "Poison.wav";
   spell[SPL_POISON_NEW].animation_ix = ANIM_POISON_NEW;
   spell[SPL_POISON_NEW].flags = 0x1015;
   spell[SPL_POISON_NEW].name = "Poison";
   spell[SPL_POISON_NEW].short_name = "Poison";
   spell[SPL_POISON_NEW].level = 4;
   spell[SPL_POISON_NEW].school_flags = 8;
   spell[SPL_POISON_NEW].mana_cost[0] = 20;
   spell[SPL_POISON_NEW].mana_cost[1] = 16;
   spell[SPL_POISON_NEW].mana_cost[2] = 16;
   spell[SPL_POISON_NEW].mana_cost[3] = 16;
   spell[SPL_POISON_NEW].eff_power = 0;
   spell[SPL_POISON_NEW].effect[0] = 0;
   spell[SPL_POISON_NEW].effect[1] = 0;
   spell[SPL_POISON_NEW].effect[2] = 0;
   spell[SPL_POISON_NEW].effect[3] = 0;
   spell[SPL_POISON_NEW].chance2get_var[0] = 10;
   spell[SPL_POISON_NEW].chance2get_var[1] = 10;
   spell[SPL_POISON_NEW].chance2get_var[2] = 10;
   spell[SPL_POISON_NEW].chance2get_var[3] = 10;
   spell[SPL_POISON_NEW].chance2get_var[4] = 10;
   spell[SPL_POISON_NEW].chance2get_var[5] = 10;
   spell[SPL_POISON_NEW].chance2get_var[6] = 10;
   spell[SPL_POISON_NEW].chance2get_var[7] = 10;
   spell[SPL_POISON_NEW].chance2get_var[8] = 10;
   spell[SPL_POISON_NEW].ai_value[0] = 50;
   spell[SPL_POISON_NEW].ai_value[1] = 50;
   spell[SPL_POISON_NEW].ai_value[2] = 50;
   spell[SPL_POISON_NEW].ai_value[3] = 50;
   spell[SPL_POISON_NEW].description[0] =
      "{Poison}\n\nPoison Description.\n";
   spell[SPL_POISON_NEW].description[1] =
      "{Basic Poison}\n\nBasic Poison Description.\n";
   spell[SPL_POISON_NEW].description[2] =
      "{Advanced Poison}\n\nAdvanced Poison Description.\n";
   spell[SPL_POISON_NEW].description[3] =
      "{Expert Poison}\n\nExpert Poison Description.\n";

   // Disease
   spell[SPL_DISEASE_NEW].type = -1;
   spell[SPL_DISEASE_NEW].wav_name = "Disease.wav";
   spell[SPL_DISEASE_NEW].animation_ix = ANIM_DISEASE_NEW;
   spell[SPL_DISEASE_NEW].flags = 0x1015;
   spell[SPL_DISEASE_NEW].name = "Disease";
   spell[SPL_DISEASE_NEW].short_name = "Disease";
   spell[SPL_DISEASE_NEW].level = 4;
   spell[SPL_DISEASE_NEW].school_flags = 8;
   spell[SPL_DISEASE_NEW].mana_cost[0] = 16;
   spell[SPL_DISEASE_NEW].mana_cost[1] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[2] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[3] = 12;
   spell[SPL_DISEASE_NEW].eff_power = 0;
   spell[SPL_DISEASE_NEW].effect[0] = 0;
   spell[SPL_DISEASE_NEW].effect[1] = 0;
   spell[SPL_DISEASE_NEW].effect[2] = 0;
   spell[SPL_DISEASE_NEW].effect[3] = 0;
   spell[SPL_DISEASE_NEW].chance2get_var[0] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[1] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[2] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[3] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[4] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[5] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[6] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[7] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[8] = 10;
   spell[SPL_DISEASE_NEW].ai_value[0] = 50;
   spell[SPL_DISEASE_NEW].ai_value[1] = 50;
   spell[SPL_DISEASE_NEW].ai_value[2] = 50;
   spell[SPL_DISEASE_NEW].ai_value[3] = 50;
   spell[SPL_DISEASE_NEW].description[0] =
      "{Disease}\n\nDisease Description.\n";
   spell[SPL_DISEASE_NEW].description[1] =
      "{Basic Disease}\n\nBasic Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[2] =
      "{Advanced Disease}\n\nAdvanced Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[3] =
      "{Expert Disease}\n\nExpert Disease Description.\n";

   // Aging
   spell[SPL_AGING_NEW].type = -1;
   spell[SPL_AGING_NEW].wav_name = "Age.wav";
   spell[SPL_AGING_NEW].animation_ix = ANIM_AGING_NEW;
   spell[SPL_AGING_NEW].flags = 0x1015;
   spell[SPL_AGING_NEW].name = "Aging";
   spell[SPL_AGING_NEW].short_name = "Aging";
   spell[SPL_AGING_NEW].level = 5;
   spell[SPL_AGING_NEW].school_flags = 2;
   spell[SPL_AGING_NEW].mana_cost[0] = 25;
   spell[SPL_AGING_NEW].mana_cost[1] = 20;
   spell[SPL_AGING_NEW].mana_cost[2] = 20;
   spell[SPL_AGING_NEW].mana_cost[3] = 20;
   spell[SPL_AGING_NEW].eff_power = 0;
   spell[SPL_AGING_NEW].effect[0] = 0;
   spell[SPL_AGING_NEW].effect[1] = 0;
   spell[SPL_AGING_NEW].effect[2] = 0;
   spell[SPL_AGING_NEW].effect[3] = 0;
   spell[SPL_AGING_NEW].chance2get_var[0] = 10;
   spell[SPL_AGING_NEW].chance2get_var[1] = 10;
   spell[SPL_AGING_NEW].chance2get_var[2] = 10;
   spell[SPL_AGING_NEW].chance2get_var[3] = 10;
   spell[SPL_AGING_NEW].chance2get_var[4] = 10;
   spell[SPL_AGING_NEW].chance2get_var[5] = 10;
   spell[SPL_AGING_NEW].chance2get_var[6] = 10;
   spell[SPL_AGING_NEW].chance2get_var[7] = 10;
   spell[SPL_AGING_NEW].chance2get_var[8] = 10;
   spell[SPL_AGING_NEW].ai_value[0] = 50;
   spell[SPL_AGING_NEW].ai_value[1] = 50;
   spell[SPL_AGING_NEW].ai_value[2] = 50;
   spell[SPL_AGING_NEW].ai_value[3] = 50;
   spell[SPL_AGING_NEW].description[0] =
      "{Aging}\n\nAging Description.\n";
   spell[SPL_AGING_NEW].description[1] =
      "{Basic Aging}\n\nBasic Aging Description.\n";
   spell[SPL_AGING_NEW].description[2] =
      "{Advanced Aging}\n\nAdvanced Aging Description.\n";
   spell[SPL_AGING_NEW].description[3] =
      "{Expert Aging}\n\nExpert Aging Description.\n";

   // Death Cloud
   spell[SPL_DEATH_CLOUD_NEW].type = 0;
   spell[SPL_DEATH_CLOUD_NEW].wav_name = "Deathcld.wav";
   spell[SPL_DEATH_CLOUD_NEW].animation_ix = ANIM_DEATH_CLOUD_NEW;
   spell[SPL_DEATH_CLOUD_NEW].flags = 0x8281;
   spell[SPL_DEATH_CLOUD_NEW].name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].short_name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].level = 5;
   spell[SPL_DEATH_CLOUD_NEW].school_flags = 8;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_CLOUD_NEW].eff_power = 40;
   spell[SPL_DEATH_CLOUD_NEW].effect[0] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[1] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[2] = 60;
   spell[SPL_DEATH_CLOUD_NEW].effect[3] = 120;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_CLOUD_NEW].description[0] =
      "{Death Cloud}\n\nDeath Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[1] =
      "{Basic Death Cloud}\n\nBasic Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[2] =
      "{Advanced Death Cloud}\n\nAdvanced Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[3] =
      "{Expert Death Cloud}\n\nExpert Death Cloud Description.\n";

   // Death Blow
   spell[SPL_DEATH_BLOW_NEW].type = 1;
   spell[SPL_DEATH_BLOW_NEW].wav_name = "Deathblo.wav";
   spell[SPL_DEATH_BLOW_NEW].animation_ix = ANIM_DEATH_BLOW_NEW;
   spell[SPL_DEATH_BLOW_NEW].flags = 0x1015;
   spell[SPL_DEATH_BLOW_NEW].name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].short_name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].level = 5;
   spell[SPL_DEATH_BLOW_NEW].school_flags = 2;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_BLOW_NEW].eff_power = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[0] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[1] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[2] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[3] = 0;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_BLOW_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_BLOW_NEW].description[0] =
      "{Death Blow}\n\nDeath Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[1] =
      "{Basic Death Blow}\n\nBasic Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[2] =
      "{Advanced Death Blow}\n\nAdvanced Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[3] =
      "{Expert Death Blow}\n\nExpert Death Blow Description.\n";

   _PI->WriteDword(0x687FA8, (int)&spell);

   // Magic Animation Table
   for (int i = 0; i < ANIM_FEAR_NEW; ++i)
      anim[i] = o_MagicAnim[i];

   // Fear
   anim[ANIM_FEAR_NEW].defName = "C07spE0.def";
   anim[ANIM_FEAR_NEW].name = "Fear";
   anim[ANIM_FEAR_NEW].type = 0x101;

   // Poison
   anim[ANIM_POISON_NEW].defName = "sp11_.def";
   anim[ANIM_POISON_NEW].name = "Poison";
   anim[ANIM_POISON_NEW].type = 1;

   // Disease
   anim[ANIM_DISEASE_NEW].defName = "sp05_.def";
   anim[ANIM_DISEASE_NEW].name = "Disease";
   anim[ANIM_DISEASE_NEW].type = 1;

   // Aging
   anim[ANIM_AGING_NEW].defName = "sp01_.def";
   anim[ANIM_AGING_NEW].name = "Aging";
   anim[ANIM_AGING_NEW].type = 1;

   // Death Cloud
   anim[ANIM_DEATH_CLOUD_NEW].defName = "sp04_.def";
   anim[ANIM_DEATH_CLOUD_NEW].name = "DeathCloud";
   anim[ANIM_DEATH_CLOUD_NEW].type = 1;

   // Death Blow
   anim[ANIM_DEATH_BLOW_NEW].defName = "sp03_.def";
   anim[ANIM_DEATH_BLOW_NEW].name = "DeathBlow";
   anim[ANIM_DEATH_BLOW_NEW].type = 1;

   int AnimAddrDefName[] = {0x43F77E, 0x43FB6A, 0x4963FB, 0x4965CF, 0x5A5036, 0x5A6B14, 0x5A7A74, 0x5A962C};
   int AnimAddrName[] = {0x4689C4, 0x49651A, 0x4966CD, 0x5A6D2D, 0x5A7B06};
   
   for (int i = 0; i < sizeof(AnimAddrDefName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrDefName[i], (int)&anim->defName);

   for (int i = 0; i < sizeof(AnimAddrName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrName[i], (int)&anim->name);

   _PI->WriteDword(0x43E503, (int)&anim->type);
   
   return EXEC_DEFAULT;
}

int __stdcall disableCreatureSpells(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;

   return EXEC_DEFAULT;
}

int __stdcall shrineSpellsInit(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;   
   
   memcpy(&shrineSpells, &o_GameMgr->disabled_shrines, sizeof(shrineSpells) / sizeof(bool));   

   c->return_address = 0x4C2641;
   return NO_EXEC_DEFAULT;
}

int __fastcall fillShrines(_GameMgr_* game, int unused_edx, int shrineFlags)
{
   int availSpellsNum = 0;

   for (int i = 0; i < SPELLS_NUM; ++i)
   {
      int lvl = o_Spell[i].level - 1;
      if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         ++availSpellsNum;
   }

   int spell = 0;
   int chosenSpell = 0;

   if (availSpellsNum)
   {
      int rndSpell = Randint(0, availSpellsNum - 1);
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         {
            if (spell == rndSpell) break;
            ++spell;
         }
         ++chosenSpell;
      }
     
      shrineSpells[chosenSpell] = true;
   }
   else
   {
      spell = 0;
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !game->disabled_shrines[i])
         {
            shrineSpells[i] = false;
            ++spell;
         }
      }
     
      chosenSpell = spell ? fillShrines(game, unused_edx, shrineFlags) : ID_NONE;
   }

   return chosenSpell; 
}

int __stdcall DeathCloud(LoHook* h, HookContext* c)
{
   if (c->edx == SPL_DEATH_CLOUD_NEW)
   {
      CALL_5(void, __thiscall, 0x5A4C80, o_BattleMgr, *(int*)(c->ebp + 0xC), SPL_DEATH_CLOUD_NEW, c->esi, *(int*)(c->ebp + 0x1C));
   
      c->return_address = 0x5A2368;
      return NO_EXEC_DEFAULT;
   }

   return EXEC_DEFAULT;
}

void __fastcall updateSpellsFromArtifacts(_Hero_* hero)
{
   for (int iSpell = 0; iSpell < SPELLS_MAX; ++iSpell)
      if (hero->spell[iSpell] > 1) hero->spell[iSpell] = 0;

   for (int iSlot = 0; iSlot < 19; ++iSlot)
   {
      if (hero->doll_art[iSlot].id != ID_NONE)
      {
         if (hero->doll_art[iSlot].id == AID_SPELL_SCROLL)
         {
            if (hero->doll_art[iSlot].mod < SPELLS_NUM && !hero->spell[hero->doll_art[iSlot].mod])
               hero->spell[hero->doll_art[iSlot].mod] = 2;
         }
         else if (o_ArtInfo[hero->doll_art[iSlot].id].new_spell)
         {
            std::bitset<SPELLS_MAX> spells;
            CALL_2(int, __fastcall, 0x4D95C0, &spells, hero->doll_art[iSlot].id);

            for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
            {
               if (spells[iSpell] && !hero->spell[iSpell])
                  hero->spell[iSpell] = 2;
            }

            int comboArtIndex = o_ArtInfo[hero->doll_art[iSlot].id].supercomposite;
            if (comboArtIndex != -1)
            {
               for (int iArt = 0; iArt < ARTIFACTS_NUM; ++iArt)
               {
                  if (o_ComboArtInfo[comboArtIndex].parts[iArt] && o_ArtInfo[iArt].new_spell)
                  {
                     std::bitset<SPELLS_MAX> spells;
                     CALL_2(int, __fastcall, 0x4D95C0, &spells, iArt);

                     for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
                     {
                        if (spells[iSpell] && !hero->spell[iSpell])
                           hero->spell[iSpell] = 2;
                     }
                  }
               }
            }
         }
      }
   }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   static bool plugin_On = false;
   if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
   {
      if ( !plugin_On )
      {
         plugin_On = true;
         _P = GetPatcher();
         _PI = _P->CreateInstance("HD.Plugin.H3.NewSpells");

         //GetCurrentDirectoryA(sizeof(iniPath), iniPath);
         //strcat(iniPath, "\\NewSpells.ini");

         // Moving and Expanding Spell Table
         _PI->WriteLoHook(0x4EE1C1, afterInit);
               
         // nwcthereisnospoon
         _PI->WriteByte (0x402902, SPELLS_NUM);

         // "(Already learned)" Text
         _PI->WriteDword(0x40D97C, 0x3EA);
         
         // AI
         _PI->WriteDword(0x41FBDF, 0x3EA);
         _PI->WriteByte (0x41FC91, SPELLS_NUM);
         _PI->WriteDword(0x425C72, 0x3EA);
         _PI->WriteDword(0x425E98, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x427039, 0x3EA);
         _PI->WriteDword(0x427044, 0x3EA);
         _PI->WriteByte (0x427085, SPELLS_NUM);
         _PI->WriteDword(0x4329C1, 0x3EA);
         _PI->WriteDword(0x432A43, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x432CDE, 0x3EA);
         _PI->WriteDword(0x432D1E, SPELLS_NUM * sizeof(_Spell_));
         // ------------
         // Adventure AI
         // ------------
         _PI->WriteDword(0x430AE5, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x4E57CC, 0x3EA + SPL_SUMMON_BOAT);
         _PI->WriteDword(0x56B346, 0x3EA + SPL_TOWN_PORTAL);
         _PI->WriteDword(0x56B7EA, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x56B93F, 0x3EA + SPL_FLY);
         _PI->WriteDword(0x56B99A, 0x3EA + SPL_WATER_WALK);
         // Battle AI
         _PI->WriteDword(0x43C6F2, SPELLS_NUM * sizeof(_Spell_));
         // Master Genie AI Spell Weighting
         _PI->WriteDword(0x43C21B, SPELLS_NUM * sizeof(_Spell_));
         // AI Quick Battle
         _PI->WriteDword(0x433026, 0x3EA);
         _PI->WriteDword(0x433719, 0x3EA);
         _PI->WriteDword(0x43940C, 0x3EA);
         _PI->WriteDword(0x43C561, 0x3EA);
         // AI Spell Scrolls?
         _PI->WriteDword(0x52A97A, 0x3EA);
         _PI->WriteDword(0x52A9B6, SPELLS_NUM * sizeof(_Spell_));
         
         // Can cast?
         _PI->WriteDword(0x447551, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteDword(0x447C7D, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x447CC8, SPELLS_NUM * sizeof(_Spell_));
         
         // Cheats in battle
         _PI->WriteByte (0x471C57, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x48647A, 0x23);
         _PI->WriteJmp  (0x486485, 0x486498);
         
         _PI->WriteByte (0x4864B0, SPELLS_NUM);
         
         // Load Game?
         _PI->WriteByte (0x48A34B, SPELLS_NUM);
         
         // Scholar Secondary Skill
         _PI->WriteByte (0x4A2743, SPELLS_NUM);

         // New Game?
         _PI->WriteByte (0x4C244D, SPELLS_NUM);
         _PI->WriteByte (0x4C246F, SPELLS_NUM);
         _PI->WriteDword(0x4C24C9, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x4C250E, SPELLS_NUM);
         _PI->WriteDword(0x4C2557, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C260D, SPELLS_NUM * sizeof(_Spell_));

         _PI->WriteByte (0x4E67AC, SPELLS_NUM);
         
         // Cheat Menu?
         _PI->WriteByte (0x4F508B, SPELLS_NUM);
         _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_));
                           
         // Pyramids
         _PI->WriteByte (0x4C170D, SPELLS_NUM);
                 
         // Shrines
         _PI->WriteDword(0x4C92C5, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C9347, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C93C0, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteByte (0x4CEC4F, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x4D8F2E, 0x23);
         _PI->WriteJmp  (0x4D8F36, 0x4D8F49);
         
         _PI->WriteByte (0x4D8F53, SPELLS_NUM);
         _PI->WriteByte (0x4D8F8A, SPELLS_NUM);
         
         // Tome of Air Magic
         _PI->WriteDword(0x4D962D, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Fire Magic
         _PI->WriteDword(0x4D9681, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Water Magic
         _PI->WriteDword(0x4D96D6, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Earth Magic
         _PI->WriteDword(0x4D972E, SPELLS_NUM * sizeof(_Spell_));
         // Spellbinder's Hat
         _PI->WriteDword(0x4D9771, SPELLS_NUM * sizeof(_Spell_));
         
         // Scholars
         _PI->WriteByte (0x5012B7, SPELLS_NUM);
         
         _PI->WriteDword(0x527ACB, 0x3EA);
         _PI->WriteDword(0x527B08, SPELLS_NUM * sizeof(_Spell_));

         // RMG
         _PI->WriteDword(0x534C4B, SPELLS_NUM * sizeof(_Spell_));
         
         // RMG Spell Scrolls
         _PI->WriteDword(0x5353D5, SPELLS_NUM);
         _PI->WriteByte (0x53542B, SPELLS_NUM);
         
         // Spell Book
         _PI->WriteDword(0x59CD5E, 0x3EA);
         _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_));

         // Cast Spell
         _PI->WriteDword(0x5A1AD6, SPELLS_NUM * sizeof(_Spell_));

         // Mage Guild
         _PI->WriteByte (0x5BEA2C, SPELLS_NUM);
         _PI->WriteByte (0x5BEA70, SPELLS_NUM);
         _PI->WriteByte (0x5BEAAD, SPELLS_NUM);
         _PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEB48, SPELLS_NUM);
         _PI->WriteByte (0x5BEB71, SPELLS_NUM);
         _PI->WriteByte (0x5BEBB2, SPELLS_NUM);
         _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEC1B, SPELLS_NUM);
                 
         // Conflux Grail
         _PI->WriteDword(0x5BE512, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BE56E, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5D7464, SPELLS_NUM);
         
         // ---------------------------
         // New _Hero_.spell[140] field
         // ---------------------------
         _PI->WriteCodePatch(0x4D8B72, "%n", 8);
         _PI->WriteCodePatch(0x4D8F7F, "%n", 8);
         _PI->WriteCodePatch(0x4D95AF, "%n", 7);

         // ----------------------------------------
         // New _GameMgr_.disabled_spells[140] field
         // ----------------------------------------
         _PI->WriteByte(0x4C16ED, 4); // Pyramids
         _PI->WriteByte(0x4C254C, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x4C25F1, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x501297, 4); // Scholars
         _PI->WriteByte(0x5BEA55, 4); // Mage Guild
                         
         _PI->WriteDword(0x52AE1C, 0x3EA);

         // ------
         // Battle
         // ------
         _PI->WriteByte (0x4963E9, ANIMS_NUM);
         _PI->WriteByte (0x4965BD, ANIMS_NUM);
         _PI->WriteByte (0x502405, SPELLS_NUM);
         _PI->WriteByte (0x502451, SPELLS_NUM);
         _PI->WriteByte (0x5024CF, SPELLS_NUM);
         _PI->WriteByte (0x502515, SPELLS_NUM);
         _PI->WriteByte (0x502E62, SPELLS_NUM);
         _PI->WriteByte (0x502EB7, SPELLS_NUM);
         _PI->WriteByte (0x59EFD9, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x59EFE4, (int)&spellIndirectTableA);
         _PI->WriteByte (0x5A064E, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x5A0659, (int)&spellIndirectTableB);
         //_PI->WriteDword(0x4446FD, (int)&spellIndirectTableC);
                 
         // --------------------------------------------------
         // New _BattleStack_.active_spell_duration[162] field
         // --------------------------------------------------
         _PI->WriteDword(0x43787A, 162);
         _PI->WriteCodePatch(0x437880, "%n", 19);
         _PI->WriteDword(0x43D314, 162);
         _PI->WriteDword(0x43E3DF, SPELLS_NUM);
         _PI->WriteByte (0x443F63, SPELLS_NUM);
         _PI->WriteByte (0x446F03, SPELLS_NUM);
         _PI->WriteByte (0x5A1907, SPELLS_NUM);
         _PI->WriteByte (0x5A1995, SPELLS_NUM);
         _PI->WriteByte (0x5A84C8, SPELLS_NUM);
         _PI->WriteByte (0x5A852F, SPELLS_NUM);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteJmp  (0x444694, 0x4450C2);
         
         // Disable creature spells
         _PI->WriteLoHook(0x4C2567, disableCreatureSpells);

         // Shrine Spells
         _PI->WriteLoHook(0x4C2625, shrineSpellsInit);
         _PI->WriteHiHook(0x4C9260, SPLICE_, DIRECT_, THISCALL_, fillShrines);
         
         // Death Cloud
         _PI->WriteLoHook(0x5A0F4C, DeathCloud);

         // Artifacts (incl. Spell Scrolls);
         _PI->WriteHiHook(0x4D9840, SPLICE_, DIRECT_, THISCALL_, updateSpellsFromArtifacts);
      }
   }

   return TRUE;
}
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 25 авг 2021, 12:32

Нашёл новое заклинание в свитке. Оказывается, HD мод даунскейлит полноразмерные картинки свитков.

Изображение
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 26 авг 2021, 05:05

Добавил вызов Firebirds и Magic Elementals (вызов Магических элементалей поместил во все школы, Огненных птиц - в школу Огня):

Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include <bitset>
#include "..\..\HotA\homm3.h"

#define SPELLS_MAX 128
#define ANIMS_MAX 128
#define ADVSPELLS_NUM 10
#define SPECABIL_NUM 11
#define ARTIFACTS_NUM 144

#define SPELLS_NUM 89
#define SPL_FEAR_NEW 81
#define SPL_POISON_NEW 82
#define SPL_DISEASE_NEW 83
#define SPL_AGING_NEW 84
#define SPL_DEATH_CLOUD_NEW 85
#define SPL_DEATH_BLOW_NEW 86
#define SPL_FIREBIRD_NEW 87
#define SPL_MAGIC_ELEMENTAL_NEW 88

#define ANIMS_NUM 89
#define ANIM_FEAR_NEW 83
#define ANIM_POISON_NEW 84
#define ANIM_DISEASE_NEW 85
#define ANIM_AGING_NEW 86
#define ANIM_DEATH_CLOUD_NEW 87
#define ANIM_DEATH_BLOW_NEW 88

Patcher* _P;
PatcherInstance* _PI;

struct _ComboArtInfo_ {
   int index;
   std::bitset<160> parts;
};

struct _MagicAnim_ {
   char* defName;
   char* name;
   int type;
};

#define o_ComboArtInfo (*(_ComboArtInfo_**)0x660B6C)
#define o_MagicAnim ((_MagicAnim_*)0x641E18)

_Spell_ spell[SPELLS_MAX];
_MagicAnim_ anim[ANIMS_MAX];
//char iniPath[MAX_PATH];

char spellIndirectTableA[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  2,  3,  4,  4,  4,  4,  4,
    5,  5,  5,  5,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    6,  4,  4,  4,  4,  4,  4,  4,  4,  4,
    4,  4,  4,  4,  4,  4,  4,  4,  4,  5,
    4,  4,  4,  7,  8,  9, 10, 10, 10, 10,
   // Special Abilities (you cannot cast them anyway)
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
    4,  4,  4,  4,  5,  4, 10, 10
};

char spellIndirectTableB[] = {
   // Spells (starting from Quicksand #10)
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
   10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
   17, 17, 17, 17, 17, 18, 17, 19, 20, 20,
   21, 17, 17, 22, 17, 17, 17, 23, 17, 17,
   17, 17, 17, 17, 17, 17, 17,  7, 17, 24,
   17, 17, 17, 25, 26, 27, 28, 29, 30, 31,
   // Special Abilities
   32, 33, 34, 17, 17, 34, 37, 37, 35, 37,
   36,
   // New Spells (starting from Fear #81)
   17, 17, 17, 17, 11, 17, 38, 39
};

char spellIndirectTableC[] = {
   // Spells (starting from Shield #27)
    0,  1,  2,  3,  4,  5,  6,  7, 32,  8,
   32, 32, 32, 32,  9, 10, 11, 12, 13, 14,
   32, 15, 16, 17, 18, 19, 20, 21, 22, 23,
   32, 24, 25, 26, 27, 28, 32, 32, 32, 32,
   32, 32, 32,
   // Special Abilities
   32, 29, 32, 30, 32, 31, -1, -1, -1, -1,
   -1,
   // New Spells (starting from Fear #81)
   32, 32, 32, 32, 32, 32, 32, 32
};

bool shrineSpells[SPELLS_MAX];

int __stdcall afterInit(LoHook* h, HookContext* c)
{
   // Spell Table
   for (int i = 0; i < SPL_FEAR_NEW; ++i)
      spell[i] = o_Spell[i];

   // Fear
   spell[SPL_FEAR_NEW].type = -1;
   spell[SPL_FEAR_NEW].wav_name = "FearRoE.wav";
   spell[SPL_FEAR_NEW].animation_ix = ANIM_FEAR_NEW;
   spell[SPL_FEAR_NEW].flags = 0x20415;
   spell[SPL_FEAR_NEW].name = "Fear";
   spell[SPL_FEAR_NEW].short_name = "Fear";
   spell[SPL_FEAR_NEW].level = 4;
   spell[SPL_FEAR_NEW].school_flags = 8;
   spell[SPL_FEAR_NEW].mana_cost[0] = 16;
   spell[SPL_FEAR_NEW].mana_cost[1] = 8;
   spell[SPL_FEAR_NEW].mana_cost[2] = 8;
   spell[SPL_FEAR_NEW].mana_cost[3] = 8;
   spell[SPL_FEAR_NEW].eff_power = 0;
   spell[SPL_FEAR_NEW].effect[0] = 75;
   spell[SPL_FEAR_NEW].effect[1] = 75;
   spell[SPL_FEAR_NEW].effect[2] = 50;
   spell[SPL_FEAR_NEW].effect[3] = 25;
   spell[SPL_FEAR_NEW].chance2get_var[0] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[1] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[2] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[3] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[4] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[5] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[6] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[7] = 10;
   spell[SPL_FEAR_NEW].chance2get_var[8] = 10;
   spell[SPL_FEAR_NEW].ai_value[0] = 50;
   spell[SPL_FEAR_NEW].ai_value[1] = 50;
   spell[SPL_FEAR_NEW].ai_value[2] = 50;
   spell[SPL_FEAR_NEW].ai_value[3] = 50;
   spell[SPL_FEAR_NEW].description[0] =
      "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n";
   spell[SPL_FEAR_NEW].description[1] =
      "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n";
   spell[SPL_FEAR_NEW].description[2] =
      "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n";
   spell[SPL_FEAR_NEW].description[3] =
      "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";

   // Poison
   spell[SPL_POISON_NEW].type = -1;
   spell[SPL_POISON_NEW].wav_name = "Poison.wav";
   spell[SPL_POISON_NEW].animation_ix = ANIM_POISON_NEW;
   spell[SPL_POISON_NEW].flags = 0x1015;
   spell[SPL_POISON_NEW].name = "Poison";
   spell[SPL_POISON_NEW].short_name = "Poison";
   spell[SPL_POISON_NEW].level = 4;
   spell[SPL_POISON_NEW].school_flags = 8;
   spell[SPL_POISON_NEW].mana_cost[0] = 20;
   spell[SPL_POISON_NEW].mana_cost[1] = 16;
   spell[SPL_POISON_NEW].mana_cost[2] = 16;
   spell[SPL_POISON_NEW].mana_cost[3] = 16;
   spell[SPL_POISON_NEW].eff_power = 0;
   spell[SPL_POISON_NEW].effect[0] = 0;
   spell[SPL_POISON_NEW].effect[1] = 0;
   spell[SPL_POISON_NEW].effect[2] = 0;
   spell[SPL_POISON_NEW].effect[3] = 0;
   spell[SPL_POISON_NEW].chance2get_var[0] = 10;
   spell[SPL_POISON_NEW].chance2get_var[1] = 10;
   spell[SPL_POISON_NEW].chance2get_var[2] = 10;
   spell[SPL_POISON_NEW].chance2get_var[3] = 10;
   spell[SPL_POISON_NEW].chance2get_var[4] = 10;
   spell[SPL_POISON_NEW].chance2get_var[5] = 10;
   spell[SPL_POISON_NEW].chance2get_var[6] = 10;
   spell[SPL_POISON_NEW].chance2get_var[7] = 10;
   spell[SPL_POISON_NEW].chance2get_var[8] = 10;
   spell[SPL_POISON_NEW].ai_value[0] = 50;
   spell[SPL_POISON_NEW].ai_value[1] = 50;
   spell[SPL_POISON_NEW].ai_value[2] = 50;
   spell[SPL_POISON_NEW].ai_value[3] = 50;
   spell[SPL_POISON_NEW].description[0] =
      "{Poison}\n\nPoison Description.\n";
   spell[SPL_POISON_NEW].description[1] =
      "{Basic Poison}\n\nBasic Poison Description.\n";
   spell[SPL_POISON_NEW].description[2] =
      "{Advanced Poison}\n\nAdvanced Poison Description.\n";
   spell[SPL_POISON_NEW].description[3] =
      "{Expert Poison}\n\nExpert Poison Description.\n";

   // Disease
   spell[SPL_DISEASE_NEW].type = -1;
   spell[SPL_DISEASE_NEW].wav_name = "Disease.wav";
   spell[SPL_DISEASE_NEW].animation_ix = ANIM_DISEASE_NEW;
   spell[SPL_DISEASE_NEW].flags = 0x1015;
   spell[SPL_DISEASE_NEW].name = "Disease";
   spell[SPL_DISEASE_NEW].short_name = "Disease";
   spell[SPL_DISEASE_NEW].level = 4;
   spell[SPL_DISEASE_NEW].school_flags = 8;
   spell[SPL_DISEASE_NEW].mana_cost[0] = 16;
   spell[SPL_DISEASE_NEW].mana_cost[1] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[2] = 12;
   spell[SPL_DISEASE_NEW].mana_cost[3] = 12;
   spell[SPL_DISEASE_NEW].eff_power = 0;
   spell[SPL_DISEASE_NEW].effect[0] = 0;
   spell[SPL_DISEASE_NEW].effect[1] = 0;
   spell[SPL_DISEASE_NEW].effect[2] = 0;
   spell[SPL_DISEASE_NEW].effect[3] = 0;
   spell[SPL_DISEASE_NEW].chance2get_var[0] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[1] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[2] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[3] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[4] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[5] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[6] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[7] = 10;
   spell[SPL_DISEASE_NEW].chance2get_var[8] = 10;
   spell[SPL_DISEASE_NEW].ai_value[0] = 50;
   spell[SPL_DISEASE_NEW].ai_value[1] = 50;
   spell[SPL_DISEASE_NEW].ai_value[2] = 50;
   spell[SPL_DISEASE_NEW].ai_value[3] = 50;
   spell[SPL_DISEASE_NEW].description[0] =
      "{Disease}\n\nDisease Description.\n";
   spell[SPL_DISEASE_NEW].description[1] =
      "{Basic Disease}\n\nBasic Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[2] =
      "{Advanced Disease}\n\nAdvanced Disease Description.\n";
   spell[SPL_DISEASE_NEW].description[3] =
      "{Expert Disease}\n\nExpert Disease Description.\n";

   // Aging
   spell[SPL_AGING_NEW].type = -1;
   spell[SPL_AGING_NEW].wav_name = "Age.wav";
   spell[SPL_AGING_NEW].animation_ix = ANIM_AGING_NEW;
   spell[SPL_AGING_NEW].flags = 0x1015;
   spell[SPL_AGING_NEW].name = "Aging";
   spell[SPL_AGING_NEW].short_name = "Aging";
   spell[SPL_AGING_NEW].level = 5;
   spell[SPL_AGING_NEW].school_flags = 2;
   spell[SPL_AGING_NEW].mana_cost[0] = 25;
   spell[SPL_AGING_NEW].mana_cost[1] = 20;
   spell[SPL_AGING_NEW].mana_cost[2] = 20;
   spell[SPL_AGING_NEW].mana_cost[3] = 20;
   spell[SPL_AGING_NEW].eff_power = 0;
   spell[SPL_AGING_NEW].effect[0] = 0;
   spell[SPL_AGING_NEW].effect[1] = 0;
   spell[SPL_AGING_NEW].effect[2] = 0;
   spell[SPL_AGING_NEW].effect[3] = 0;
   spell[SPL_AGING_NEW].chance2get_var[0] = 10;
   spell[SPL_AGING_NEW].chance2get_var[1] = 10;
   spell[SPL_AGING_NEW].chance2get_var[2] = 10;
   spell[SPL_AGING_NEW].chance2get_var[3] = 10;
   spell[SPL_AGING_NEW].chance2get_var[4] = 10;
   spell[SPL_AGING_NEW].chance2get_var[5] = 10;
   spell[SPL_AGING_NEW].chance2get_var[6] = 10;
   spell[SPL_AGING_NEW].chance2get_var[7] = 10;
   spell[SPL_AGING_NEW].chance2get_var[8] = 10;
   spell[SPL_AGING_NEW].ai_value[0] = 50;
   spell[SPL_AGING_NEW].ai_value[1] = 50;
   spell[SPL_AGING_NEW].ai_value[2] = 50;
   spell[SPL_AGING_NEW].ai_value[3] = 50;
   spell[SPL_AGING_NEW].description[0] =
      "{Aging}\n\nAging Description.\n";
   spell[SPL_AGING_NEW].description[1] =
      "{Basic Aging}\n\nBasic Aging Description.\n";
   spell[SPL_AGING_NEW].description[2] =
      "{Advanced Aging}\n\nAdvanced Aging Description.\n";
   spell[SPL_AGING_NEW].description[3] =
      "{Expert Aging}\n\nExpert Aging Description.\n";

   // Death Cloud
   spell[SPL_DEATH_CLOUD_NEW].type = 0;
   spell[SPL_DEATH_CLOUD_NEW].wav_name = "Deathcld.wav";
   spell[SPL_DEATH_CLOUD_NEW].animation_ix = ANIM_DEATH_CLOUD_NEW;
   spell[SPL_DEATH_CLOUD_NEW].flags = 0x8281;
   spell[SPL_DEATH_CLOUD_NEW].name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].short_name = "Death Cloud";
   spell[SPL_DEATH_CLOUD_NEW].level = 5;
   spell[SPL_DEATH_CLOUD_NEW].school_flags = 8;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_CLOUD_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_CLOUD_NEW].eff_power = 40;
   spell[SPL_DEATH_CLOUD_NEW].effect[0] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[1] = 30;
   spell[SPL_DEATH_CLOUD_NEW].effect[2] = 60;
   spell[SPL_DEATH_CLOUD_NEW].effect[3] = 120;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_CLOUD_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_CLOUD_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_CLOUD_NEW].description[0] =
      "{Death Cloud}\n\nDeath Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[1] =
      "{Basic Death Cloud}\n\nBasic Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[2] =
      "{Advanced Death Cloud}\n\nAdvanced Death Cloud Description.\n";
   spell[SPL_DEATH_CLOUD_NEW].description[3] =
      "{Expert Death Cloud}\n\nExpert Death Cloud Description.\n";

   // Death Blow
   spell[SPL_DEATH_BLOW_NEW].type = 1;
   spell[SPL_DEATH_BLOW_NEW].wav_name = "Deathblo.wav";
   spell[SPL_DEATH_BLOW_NEW].animation_ix = ANIM_DEATH_BLOW_NEW;
   spell[SPL_DEATH_BLOW_NEW].flags = 0x1015;
   spell[SPL_DEATH_BLOW_NEW].name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].short_name = "Death Blow";
   spell[SPL_DEATH_BLOW_NEW].level = 5;
   spell[SPL_DEATH_BLOW_NEW].school_flags = 2;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[0] = 25;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[1] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[2] = 20;
   spell[SPL_DEATH_BLOW_NEW].mana_cost[3] = 20;
   spell[SPL_DEATH_BLOW_NEW].eff_power = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[0] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[1] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[2] = 0;
   spell[SPL_DEATH_BLOW_NEW].effect[3] = 0;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[0] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[1] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[2] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[3] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[4] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[5] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[6] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[7] = 10;
   spell[SPL_DEATH_BLOW_NEW].chance2get_var[8] = 10;
   spell[SPL_DEATH_BLOW_NEW].ai_value[0] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[1] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[2] = 50;
   spell[SPL_DEATH_BLOW_NEW].ai_value[3] = 50;
   spell[SPL_DEATH_BLOW_NEW].description[0] =
      "{Death Blow}\n\nDeath Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[1] =
      "{Basic Death Blow}\n\nBasic Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[2] =
      "{Advanced Death Blow}\n\nAdvanced Death Blow Description.\n";
   spell[SPL_DEATH_BLOW_NEW].description[3] =
      "{Expert Death Blow}\n\nExpert Death Blow Description.\n";

   // Firebird
   spell[SPL_FIREBIRD_NEW].type = 0;
   spell[SPL_FIREBIRD_NEW].wav_name = "SumnElm.wav";
   spell[SPL_FIREBIRD_NEW].animation_ix = ID_NONE;
   spell[SPL_FIREBIRD_NEW].flags = 0x80001;
   spell[SPL_FIREBIRD_NEW].name = "Firebird";
   spell[SPL_FIREBIRD_NEW].short_name = "Firebird";
   spell[SPL_FIREBIRD_NEW].level = 5;
   spell[SPL_FIREBIRD_NEW].school_flags = 2;
   spell[SPL_FIREBIRD_NEW].mana_cost[0] = 25;
   spell[SPL_FIREBIRD_NEW].mana_cost[1] = 20;
   spell[SPL_FIREBIRD_NEW].mana_cost[2] = 20;
   spell[SPL_FIREBIRD_NEW].mana_cost[3] = 20;
   spell[SPL_FIREBIRD_NEW].eff_power = 0;
   spell[SPL_FIREBIRD_NEW].effect[0] = 50;
   spell[SPL_FIREBIRD_NEW].effect[1] = 50;
   spell[SPL_FIREBIRD_NEW].effect[2] = 75;
   spell[SPL_FIREBIRD_NEW].effect[3] = 100;
   spell[SPL_FIREBIRD_NEW].chance2get_var[0] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[1] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[2] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[3] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[4] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[5] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[6] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[7] = 10;
   spell[SPL_FIREBIRD_NEW].chance2get_var[8] = 10;
   spell[SPL_FIREBIRD_NEW].ai_value[0] = 50;
   spell[SPL_FIREBIRD_NEW].ai_value[1] = 50;
   spell[SPL_FIREBIRD_NEW].ai_value[2] = 100;
   spell[SPL_FIREBIRD_NEW].ai_value[3] = 150;
   spell[SPL_FIREBIRD_NEW].description[0] =
      "{Firebird}\n\nAllows you to summon firebirds.  Once cast, no other elemental types may be summoned.\n";
   spell[SPL_FIREBIRD_NEW].description[1] =
      "{Basic Firebird}\n\nAllows you to summon firebirds.  Once cast, no other elemental types may be summoned.\n";
   spell[SPL_FIREBIRD_NEW].description[2] =
      "{Advanced Firebird}\n\nAllows you to summon firebirds.  Once cast, no other elemental types may be summoned.\n\n" \
      "Summons approximately one-and-a-half times the number of units as Basic Summon Firebird.\n";
   spell[SPL_FIREBIRD_NEW].description[3] =
      "{Expert Firebird}\n\nAllows you to summon firebirds.  Once cast, no other elemental types may be summoned.\n\n" \
      "Summons approximately twice the number of units as Basic Summon Firebird.\n";

   // Magic Elemental
   spell[SPL_MAGIC_ELEMENTAL_NEW].type = 0;
   spell[SPL_MAGIC_ELEMENTAL_NEW].wav_name = "SumnElm.wav";
   spell[SPL_MAGIC_ELEMENTAL_NEW].animation_ix = ID_NONE;
   spell[SPL_MAGIC_ELEMENTAL_NEW].flags = 0x80001;
   spell[SPL_MAGIC_ELEMENTAL_NEW].name = "Magic Elemental";
   spell[SPL_MAGIC_ELEMENTAL_NEW].short_name = "Magic Elemental";
   spell[SPL_MAGIC_ELEMENTAL_NEW].level = 5;
   spell[SPL_MAGIC_ELEMENTAL_NEW].school_flags = 0xF;
   spell[SPL_MAGIC_ELEMENTAL_NEW].mana_cost[0] = 25;
   spell[SPL_MAGIC_ELEMENTAL_NEW].mana_cost[1] = 20;
   spell[SPL_MAGIC_ELEMENTAL_NEW].mana_cost[2] = 20;
   spell[SPL_MAGIC_ELEMENTAL_NEW].mana_cost[3] = 20;
   spell[SPL_MAGIC_ELEMENTAL_NEW].eff_power = 0;
   spell[SPL_MAGIC_ELEMENTAL_NEW].effect[0] = 100;
   spell[SPL_MAGIC_ELEMENTAL_NEW].effect[1] = 100;
   spell[SPL_MAGIC_ELEMENTAL_NEW].effect[2] = 150;
   spell[SPL_MAGIC_ELEMENTAL_NEW].effect[3] = 200;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[0] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[1] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[2] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[3] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[4] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[5] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[6] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[7] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].chance2get_var[8] = 10;
   spell[SPL_MAGIC_ELEMENTAL_NEW].ai_value[0] = 50;
   spell[SPL_MAGIC_ELEMENTAL_NEW].ai_value[1] = 50;
   spell[SPL_MAGIC_ELEMENTAL_NEW].ai_value[2] = 100;
   spell[SPL_MAGIC_ELEMENTAL_NEW].ai_value[3] = 150;
   spell[SPL_MAGIC_ELEMENTAL_NEW].description[0] =
      "{Magic Elemental}\n\nAllows you to summon magic elementals.  Once cast, no other elemental types may be summoned.\n";
   spell[SPL_MAGIC_ELEMENTAL_NEW].description[1] =
      "{Basic Magic Elemental}\n\nAllows you to summon magic elementals.  Once cast, no other elemental types may be summoned.\n";
   spell[SPL_MAGIC_ELEMENTAL_NEW].description[2] =
      "{Advanced Magic Elemental}\n\nAllows you to summon magic elementals.  Once cast, no other elemental types may be summoned.\n\n" \
      "Summons approximately one-and-a-half times the number of units as Basic Summon Magic Elemental.\n";
   spell[SPL_MAGIC_ELEMENTAL_NEW].description[3] =
      "{Expert Magic Elemental}\n\nAllows you to summon magic elementals.  Once cast, no other elemental types may be summoned.\n\n" \
      "Summons approximately twice the number of units as Basic Summon Magic Elemental.\n";

   _PI->WriteDword(0x687FA8, (int)&spell);

   // Magic Animation Table
   for (int i = 0; i < ANIM_FEAR_NEW; ++i)
      anim[i] = o_MagicAnim[i];

   // Fear
   anim[ANIM_FEAR_NEW].defName = "C07spE0.def";
   anim[ANIM_FEAR_NEW].name = "Fear";
   anim[ANIM_FEAR_NEW].type = 0x101;

   // Poison
   anim[ANIM_POISON_NEW].defName = "sp11_.def";
   anim[ANIM_POISON_NEW].name = "Poison";
   anim[ANIM_POISON_NEW].type = 1;

   // Disease
   anim[ANIM_DISEASE_NEW].defName = "sp05_.def";
   anim[ANIM_DISEASE_NEW].name = "Disease";
   anim[ANIM_DISEASE_NEW].type = 1;

   // Aging
   anim[ANIM_AGING_NEW].defName = "sp01_.def";
   anim[ANIM_AGING_NEW].name = "Aging";
   anim[ANIM_AGING_NEW].type = 1;

   // Death Cloud
   anim[ANIM_DEATH_CLOUD_NEW].defName = "sp04_.def";
   anim[ANIM_DEATH_CLOUD_NEW].name = "DeathCloud";
   anim[ANIM_DEATH_CLOUD_NEW].type = 1;

   // Death Blow
   anim[ANIM_DEATH_BLOW_NEW].defName = "sp03_.def";
   anim[ANIM_DEATH_BLOW_NEW].name = "DeathBlow";
   anim[ANIM_DEATH_BLOW_NEW].type = 1;

   int AnimAddrDefName[] = {0x43F77E, 0x43FB6A, 0x4963FB, 0x4965CF, 0x5A5036, 0x5A6B14, 0x5A7A74, 0x5A962C};
   int AnimAddrName[] = {0x4689C4, 0x49651A, 0x4966CD, 0x5A6D2D, 0x5A7B06};
   
   for (int i = 0; i < sizeof(AnimAddrDefName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrDefName[i], (int)&anim->defName);

   for (int i = 0; i < sizeof(AnimAddrName) / sizeof(int); ++i)
      _PI->WriteDword(AnimAddrName[i], (int)&anim->name);

   _PI->WriteDword(0x43E503, (int)&anim->type);
   
   return EXEC_DEFAULT;
}

int __stdcall disableCreatureSpells(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;

   return EXEC_DEFAULT;
}

int __stdcall shrineSpellsInit(LoHook* h, HookContext* c)
{
   for (int i = SPL_STONE; i <= SPL_ACID_BREATH; ++i)
      o_GameMgr->disabled_shrines[i] = true;   
   
   memcpy(&shrineSpells, &o_GameMgr->disabled_shrines, sizeof(shrineSpells) / sizeof(bool));   

   c->return_address = 0x4C2641;
   return NO_EXEC_DEFAULT;
}

int __fastcall fillShrines(_GameMgr_* game, int unused_edx, int shrineFlags)
{
   int availSpellsNum = 0;

   for (int i = 0; i < SPELLS_NUM; ++i)
   {
      int lvl = o_Spell[i].level - 1;
      if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         ++availSpellsNum;
   }

   int spell = 0;
   int chosenSpell = 0;

   if (availSpellsNum)
   {
      int rndSpell = Randint(0, availSpellsNum - 1);
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !shrineSpells[i])
         {
            if (spell == rndSpell) break;
            ++spell;
         }
         ++chosenSpell;
      }
     
      shrineSpells[chosenSpell] = true;
   }
   else
   {
      spell = 0;
     
      for (int i = 0; i < SPELLS_NUM; ++i)
      {
         int lvl = o_Spell[i].level - 1;
         if (lvl < 5 && 1 << lvl & shrineFlags && o_Spell[i].school_flags && !game->disabled_shrines[i])
         {
            shrineSpells[i] = false;
            ++spell;
         }
      }
     
      chosenSpell = spell ? fillShrines(game, unused_edx, shrineFlags) : ID_NONE;
   }

   return chosenSpell; 
}

int __stdcall DeathCloud(LoHook* h, HookContext* c)
{
   if (c->edx == SPL_DEATH_CLOUD_NEW)
   {
      CALL_5(void, __thiscall, 0x5A4C80, o_BattleMgr, *(int*)(c->ebp + 0xC), SPL_DEATH_CLOUD_NEW, c->esi, *(int*)(c->ebp + 0x1C));
   
      c->return_address = 0x5A2368;
      return NO_EXEC_DEFAULT;
   }

   return EXEC_DEFAULT;
}

int __stdcall SummonCreatures(LoHook* h, HookContext* c)
{
   if (c->ecx == 38 || c->ecx == 39)
   {
      int spell;
      int creature;

      switch (c->ecx)
      {
      case 38:
         spell = SPL_FIREBIRD_NEW;
         creature = CID_FIREBIRD;
         break;
      case 39:
         spell = SPL_MAGIC_ELEMENTAL_NEW;
         creature = CID_MAGIC_ELEMENTAL;
         break;
      }

      CALL_5(void, __thiscall, 0x5A7390, o_BattleMgr, spell, creature, *(int*)(c->ebp + 0x1C), c->esi);
   
      c->return_address = 0x5A2368;
      return NO_EXEC_DEFAULT;
   }

   return EXEC_DEFAULT;
}

int __stdcall setSummonedCreaturesNumber(LoHook* h, HookContext* c)
{
   int creature = *(int*)(c->ebp + 0xC);
   int sp = *(int*)(c->ebp + 0x10);
   int schoolLevel = *(int*)(c->ebp + 0x14);

   if (creature == CID_FIREBIRD)
      c->esi = o_Spell[SPL_FIREBIRD_NEW].effect[schoolLevel] * sp / 100;
   else if (creature == CID_MAGIC_ELEMENTAL)
      c->esi = o_Spell[SPL_MAGIC_ELEMENTAL_NEW].effect[schoolLevel] * sp / 100;
   else
      return EXEC_DEFAULT;

   if (c->esi < 1) c->esi = 1;
   
   c->return_address = 0x5A7526;
   return NO_EXEC_DEFAULT;
}

int __stdcall checkSummonedCreaturesType(LoHook* h, HookContext* c)
{
   int spell = c->ebx;

   switch (spell)
   {
   case SPL_FIRE_ELEMENTAL:
      c->eax = CID_FIRE_ELEMENTAL;
      break;
   case SPL_EARTH_ELEMENTAL:
      c->eax = CID_EARTH_ELEMENTAL;
      break;
   case SPL_WATER_ELEMENTAL:
      c->eax = CID_WATER_ELEMENTAL;
      break;
   case SPL_AIR_ELEMENTAL:
      c->eax = CID_AIR_ELEMENTAL;
      break;
   case SPL_FIREBIRD_NEW:
      c->eax = CID_FIREBIRD;
      break;
   case SPL_MAGIC_ELEMENTAL_NEW:
      c->eax = CID_MAGIC_ELEMENTAL;
      break;
   default:
      c->eax = ID_NONE;
   }
   
   c->return_address = 0x59F8B7;
   return NO_EXEC_DEFAULT;
}

void __fastcall updateSpellsFromArtifacts(_Hero_* hero)
{
   for (int iSpell = 0; iSpell < SPELLS_MAX; ++iSpell)
      if (hero->spell[iSpell] > 1) hero->spell[iSpell] = 0;

   for (int iSlot = 0; iSlot < 19; ++iSlot)
   {
      if (hero->doll_art[iSlot].id != ID_NONE)
      {
         if (hero->doll_art[iSlot].id == AID_SPELL_SCROLL)
         {
            if (hero->doll_art[iSlot].mod < SPELLS_NUM && !hero->spell[hero->doll_art[iSlot].mod])
               hero->spell[hero->doll_art[iSlot].mod] = 2;
         }
         else if (o_ArtInfo[hero->doll_art[iSlot].id].new_spell)
         {
            std::bitset<SPELLS_MAX> spells;
            CALL_2(int, __fastcall, 0x4D95C0, &spells, hero->doll_art[iSlot].id);

            for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
            {
               if (spells[iSpell] && !hero->spell[iSpell])
                  hero->spell[iSpell] = 2;
            }

            int comboArtIndex = o_ArtInfo[hero->doll_art[iSlot].id].supercomposite;
            if (comboArtIndex != -1)
            {
               for (int iArt = 0; iArt < ARTIFACTS_NUM; ++iArt)
               {
                  if (o_ComboArtInfo[comboArtIndex].parts[iArt] && o_ArtInfo[iArt].new_spell)
                  {
                     std::bitset<SPELLS_MAX> spells;
                     CALL_2(int, __fastcall, 0x4D95C0, &spells, iArt);

                     for (std::size_t iSpell = 0; iSpell < spells.size(); ++iSpell)
                     {
                        if (spells[iSpell] && !hero->spell[iSpell])
                           hero->spell[iSpell] = 2;
                     }
                  }
               }
            }
         }
      }
   }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   static bool plugin_On = false;
   if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
   {
      if ( !plugin_On )
      {
         plugin_On = true;
         _P = GetPatcher();
         _PI = _P->CreateInstance("HD.Plugin.H3.NewSpells");

         //GetCurrentDirectoryA(sizeof(iniPath), iniPath);
         //strcat(iniPath, "\\NewSpells.ini");

         // Moving and Expanding Spell Table
         _PI->WriteLoHook(0x4EE1C1, afterInit);
               
         // nwcthereisnospoon
         _PI->WriteByte (0x402902, SPELLS_NUM);

         // "(Already learned)" Text
         _PI->WriteDword(0x40D97C, 0x3EA);
         
         // AI
         _PI->WriteDword(0x41FBDF, 0x3EA);
         _PI->WriteByte (0x41FC91, SPELLS_NUM);
         _PI->WriteDword(0x425C72, 0x3EA);
         _PI->WriteDword(0x425E98, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x427039, 0x3EA);
         _PI->WriteDword(0x427044, 0x3EA);
         _PI->WriteByte (0x427085, SPELLS_NUM);
         _PI->WriteDword(0x4329C1, 0x3EA);
         _PI->WriteDword(0x432A43, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x432CDE, 0x3EA);
         _PI->WriteDword(0x432D1E, SPELLS_NUM * sizeof(_Spell_));
         // ------------
         // Adventure AI
         // ------------
         _PI->WriteDword(0x430AE5, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x4E57CC, 0x3EA + SPL_SUMMON_BOAT);
         _PI->WriteDword(0x56B346, 0x3EA + SPL_TOWN_PORTAL);
         _PI->WriteDword(0x56B7EA, 0x3EA + SPL_DIMENSION_DOOR);
         _PI->WriteDword(0x56B93F, 0x3EA + SPL_FLY);
         _PI->WriteDword(0x56B99A, 0x3EA + SPL_WATER_WALK);
         // Battle AI
         _PI->WriteDword(0x43C6F2, SPELLS_NUM * sizeof(_Spell_));
         // Master Genie AI Spell Weighting
         _PI->WriteDword(0x43C21B, SPELLS_NUM * sizeof(_Spell_));
         // AI Quick Battle
         _PI->WriteDword(0x433026, 0x3EA);
         _PI->WriteDword(0x433719, 0x3EA);
         _PI->WriteDword(0x43940C, 0x3EA);
         _PI->WriteDword(0x43C561, 0x3EA);
         // AI Spell Scrolls?
         _PI->WriteDword(0x52A97A, 0x3EA);
         _PI->WriteDword(0x52A9B6, SPELLS_NUM * sizeof(_Spell_));
         
         // Can cast?
         _PI->WriteDword(0x447551, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteDword(0x447C7D, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x447CC8, SPELLS_NUM * sizeof(_Spell_));
         
         // Cheats in battle
         _PI->WriteByte (0x471C57, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x48647A, 0x23);
         _PI->WriteJmp  (0x486485, 0x486498);
         
         _PI->WriteByte (0x4864B0, SPELLS_NUM);
         
         // Load Game?
         _PI->WriteByte (0x48A34B, SPELLS_NUM);
         
         // Scholar Secondary Skill
         _PI->WriteByte (0x4A2743, SPELLS_NUM);

         // New Game?
         _PI->WriteByte (0x4C244D, SPELLS_NUM);
         _PI->WriteByte (0x4C246F, SPELLS_NUM);
         _PI->WriteDword(0x4C24C9, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x4C250E, SPELLS_NUM);
         _PI->WriteDword(0x4C2557, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C260D, SPELLS_NUM * sizeof(_Spell_));

         _PI->WriteByte (0x4E67AC, SPELLS_NUM);
         
         // Cheat Menu?
         _PI->WriteByte (0x4F508B, SPELLS_NUM);
         _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_));
                           
         // Pyramids
         _PI->WriteByte (0x4C170D, SPELLS_NUM);
                 
         // Shrines
         _PI->WriteDword(0x4C92C5, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C9347, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4C93C0, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteByte (0x4CEC4F, SPELLS_NUM);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x4D8F2E, 0x23);
         _PI->WriteJmp  (0x4D8F36, 0x4D8F49);
         
         _PI->WriteByte (0x4D8F53, SPELLS_NUM);
         _PI->WriteByte (0x4D8F8A, SPELLS_NUM);
         
         // Tome of Air Magic
         _PI->WriteDword(0x4D962D, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Fire Magic
         _PI->WriteDword(0x4D9681, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Water Magic
         _PI->WriteDword(0x4D96D6, SPELLS_NUM * sizeof(_Spell_));
         // Tome of Earth Magic
         _PI->WriteDword(0x4D972E, SPELLS_NUM * sizeof(_Spell_));
         // Spellbinder's Hat
         _PI->WriteDword(0x4D9771, SPELLS_NUM * sizeof(_Spell_));
         
         // Scholars
         _PI->WriteByte (0x5012B7, SPELLS_NUM);
         
         _PI->WriteDword(0x527ACB, 0x3EA);
         _PI->WriteDword(0x527B08, SPELLS_NUM * sizeof(_Spell_));

         // RMG
         _PI->WriteDword(0x534C4B, SPELLS_NUM * sizeof(_Spell_));
         
         // RMG Spell Scrolls
         _PI->WriteDword(0x5353D5, SPELLS_NUM);
         _PI->WriteByte (0x53542B, SPELLS_NUM);
         
         // Spell Book
         _PI->WriteDword(0x59CD5E, 0x3EA);
         _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_));

         // Cast Spell
         _PI->WriteDword(0x5A1AD6, SPELLS_NUM * sizeof(_Spell_));

         // Mage Guild
         _PI->WriteByte (0x5BEA2C, SPELLS_NUM);
         _PI->WriteByte (0x5BEA70, SPELLS_NUM);
         _PI->WriteByte (0x5BEAAD, SPELLS_NUM);
         _PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEB48, SPELLS_NUM);
         _PI->WriteByte (0x5BEB71, SPELLS_NUM);
         _PI->WriteByte (0x5BEBB2, SPELLS_NUM);
         _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x5BEC1B, SPELLS_NUM);
                 
         // Conflux Grail
         _PI->WriteDword(0x5BE512, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5BE56E, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x5D7464, SPELLS_NUM);
         
         // ---------------------------
         // New _Hero_.spell[140] field
         // ---------------------------
         _PI->WriteCodePatch(0x4D8B72, "%n", 8);
         _PI->WriteCodePatch(0x4D8F7F, "%n", 8);
         _PI->WriteCodePatch(0x4D95AF, "%n", 7);

         // ----------------------------------------
         // New _GameMgr_.disabled_spells[140] field
         // ----------------------------------------
         _PI->WriteByte(0x4C16ED, 4); // Pyramids
         _PI->WriteByte(0x4C254C, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x4C25F1, 4); // Titan's Lightning Bolt
         _PI->WriteByte(0x501297, 4); // Scholars
         _PI->WriteByte(0x5BEA55, 4); // Mage Guild
                         
         _PI->WriteDword(0x52AE1C, 0x3EA);

         // ------
         // Battle
         // ------
         _PI->WriteByte (0x4963E9, ANIMS_NUM);
         _PI->WriteByte (0x4965BD, ANIMS_NUM);
         _PI->WriteByte (0x502405, SPELLS_NUM);
         _PI->WriteByte (0x502451, SPELLS_NUM);
         _PI->WriteByte (0x5024CF, SPELLS_NUM);
         _PI->WriteByte (0x502515, SPELLS_NUM);
         _PI->WriteByte (0x502E62, SPELLS_NUM);
         _PI->WriteByte (0x502EB7, SPELLS_NUM);
         _PI->WriteByte (0x59EFD9, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x59EFE4, (int)&spellIndirectTableA);
         _PI->WriteByte (0x5A064E, SPELLS_NUM - 1 - ADVSPELLS_NUM);
         _PI->WriteDword(0x5A0659, (int)&spellIndirectTableB);
         //_PI->WriteDword(0x4446FD, (int)&spellIndirectTableC);
                 
         // --------------------------------------------------
         // New _BattleStack_.active_spell_duration[162] field
         // --------------------------------------------------
         _PI->WriteDword(0x43787A, 162);
         _PI->WriteCodePatch(0x437880, "%n", 19);
         _PI->WriteDword(0x43D314, 162);
         _PI->WriteDword(0x43E3DF, SPELLS_NUM);
         _PI->WriteByte (0x443F63, SPELLS_NUM);
         _PI->WriteByte (0x446F03, SPELLS_NUM);
         _PI->WriteByte (0x5A1907, SPELLS_NUM);
         _PI->WriteByte (0x5A1995, SPELLS_NUM);
         _PI->WriteByte (0x5A84C8, SPELLS_NUM);
         _PI->WriteByte (0x5A852F, SPELLS_NUM);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteCodePatch(0x4446D2, "%n", 7);
         _PI->WriteJmp  (0x444694, 0x4450C2);
         
         // Disable creature spells
         _PI->WriteLoHook(0x4C2567, disableCreatureSpells);

         // Shrine Spells
         _PI->WriteLoHook(0x4C2625, shrineSpellsInit);
         _PI->WriteHiHook(0x4C9260, SPLICE_, DIRECT_, THISCALL_, fillShrines);
         
         // Death Cloud
         _PI->WriteLoHook(0x5A0F4C, DeathCloud);

         // Firebird, Magic Elemental
         _PI->WriteLoHook(0x59F889, checkSummonedCreaturesType);
         _PI->WriteLoHook(0x5A065D, SummonCreatures);
         _PI->WriteLoHook(0x5A7516, setSummonedCreaturesNumber);
         
         // Artifacts (incl. Spell Scrolls);
         _PI->WriteHiHook(0x4D9840, SPLICE_, DIRECT_, THISCALL_, updateSpellsFromArtifacts);
      }
   }

   return TRUE;
}

NewSpellsAlpha.zip
(363.6 КБ) Скачиваний: 154
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 26 авг 2021, 09:40

Цитата:
Я предлагаю, как писал ранее, в подобных случаях оставлять одну картинку и просто обновлять длительность раундов этого закла всегда выбирая большее. Например, на отряде один из таких заклов (Disease, Poison или Aging) и атакующий отряд накладывает такой же (свою абилку). В таком случае мы обновляем только длительность этого закла при необходимости. То есть кол-во раундов действия этого закла устанавливаем в max(СМ - x, 3), где x от 0 до СМ. И наооборот, когда на отряде абилка и на этот отряд кастуется повторяющий эту абилку закл, то тогда кол-во раундов устанавливаем следущее: max(3 - x, СМ), где x от 0 до 3. А картинка не дублируется и всегда одна. Сложно ли будет такое сделать?

***

Проверил, именно так, как я описал выше, и обстоят дела с Проклятием, Слепотой, Жаждой крови и другими заклами повторяющими абилки в оригинале.

Так они полностью повторяют эффекты спецабилок. У нас же Disease будет намного круче абилки Зомби. По-хорошему, во избежание путаницы, нужны оригинальные картинки. Как минимум - оригинальная картинка эффекта в информационном окне отряда.

Ещё остаётся вопрос баланса вызова элементалей. Я бы поднял стоимость до 30 (25 при развитии школы).
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 26 авг 2021, 12:54

AlexSpl писал(а):

Нашёл новое заклинание в свитке. Оказывается, HD мод даунскейлит полноразмерные картинки свитков.

Точно. Теперь понятно, почему в ресурсах нет картинок для свитков. В оригинале для всех свитков используется одна картинка и для просмотра закла нужно ПКМ по свитку. А мод получается даунскейлит картинки из гильдии. Такой вопрос, а где же тогда используються урезанная версия картинки из гильдии без боковушек из SpellBon?

AlexSpl писал(а):

Добавил вызов Firebirds и Magic Elementals

Я предлагал:
Элементали психики + Огненные птицы
Элементали психики + Фениксы
Элементали магии + Фениксы

А вы выбрали 4-й вариант. Я его даже не написал, так как посчитал его не совсем подходящим и каким-то нелогичным. В оригинале призываються всегда неулучшенные версии элементалей. В таком случае самым подходящим вариантом будет "Psychic Elementals" + Firebirds". Но поскольку Вы изначально предлагали вызов именно Феников, как в KB, то можно было сделать "Psychic Elementals" + Phenixs". Либо же, если добавляем улучшенные версии, то добавляем в обоих случах, то есть "Magic Elementals + Phenixs". Я так понял делая свой выбор Вы руководствовались исключительно более привлекательными картинками, верно?

AlexSpl писал(а):

Так они полностью повторяют эффекты спецабилок. У нас же Disease будет намного круче абилки Зомби. По-хорошему, во избежание путаницы, нужны оригинальные картинки. Как минимум - оригинальная картинка эффекта в информационном окне отряда.

Согласен. Но тут даже и не знаю, с одной стороны сделать его заклом 2 или 3 уровня без эффекта замедления было бы логичней. Но вот с другой, очень нравится идея с АнтиМолитвой. Картинку эффекта в инфо окне отряда я сделал.

AlexSpl писал(а):

Ещё остаётся вопрос баланса вызова элементалей. Я бы поднял стоимость до 30 (25 при развитии школы).

Да, согласен, думаю, можно сделать. Посколько они в итоге будут чуточку сильнее, кол-ва Земляных элементалей, которых мы можем призвать при той же СМ. Правда если Magic Elementals заменить на Psychic Elementals, то для них вот можно оставить и 25 (20 при развитии школы), а вот для Firebirds в любом случае нужно поднимать до 30.

Другая картинка эффекта в инфо окне отряда для Disease:
Вложения
NewDisease.rar
(5.68 КБ) Скачиваний: 124
Последний раз редактировалось Rolex 26 авг 2021, 13:03, всего редактировалось 2 раз(а).
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 26 авг 2021, 13:01

Цитата:
А вы выбрали 4-й варинт. Я его даже не написал, так как посчитал его не совсем подходящим и каким-то нелогичным. В оригинале призываються всегда неулучшенные версии элементалей. В таком случае самым подходящим вариантом будет "Psychic Elementals" + Firebirds". Но поскольку Вы изначально предлагали вызов именно Феников, как в KB, то можно было сделать "Psychic Elementals" + Phenixs". Либо же, если добавляем улучшенные версии, то добавляем в обоих случах, то есть "Magic Elementals + Phenixs". Я так понял делая свой выбор Вы руководствовались исключительно более привлекательными картинками, верно?

Я подумал, что призыв Фениксов будет слишком жирно из-за их абилки. А Магические победили как раз из-за иммунитета к магии, т.е. их вызов очень ценен в битвах против сильных магов. Но можно добавить вообще все четыре случая :smile1:

Цитата:
Такой вопрос, а где же тогда используються урезанная версия картинки из гильдии без боковушек из SpellBon?

Я почти уверен, что это заклинания на выбор перед сценарием кампании (нам не нужно).
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 26 авг 2021, 13:06

Цитата:
Но можно добавить вообще все четыре случая :smile1:

Нет, все 4 точно ненужно. Тогда для тех, что добавили, как Вы и рекомендовали, просто поднимаем стоимость до 30 (25 при развитии школы).
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 27 авг 2021, 06:10

Кстати, касательно Pison (Яд), в оригинале он не снимается Диспелом, а только Лечением. Более того, даже спустя 3 раунда, когда его действие заканчивается, здоровье не восстанавливается к прежнему уровню, а остается пониженным. Даже если отравленный Ядом отряд погибает, то даже после его воскрешения у него будет пониженное здоровье. По-момему, это баг. Так быть не должно. С Aging подобного нет, он снимается и Лечением, и Диспелом и здоровье восстанавливается, как после снятия, так и после окончания его действия (после 3 раундов). Вот и думаю, что в этом плане нужно их уравнивать, иначе у Poison будет серьезное примущество, и это при том, что он 4-го уровня в отличии от Aging, который 5-го. Надо бы, что бы после окончания дейсвтия закла здоровье после Poison восстанавливалось, плюс, чтобы он также снимался Диспелом.

Также думаю на счет Death Blow. Сейчас при наложеении на наш отряд проигрывается анимация, а перед атакой вражексого отряда на отряде врага, как у Рыцарей Смерти, ее нет. Вот и думаю, что неплохо было бы ее добавить. Правда тогда получится так, что одна и таже анимация будет проигрываться как на своем, так и на вражеском отряде. :smile5:

Сохранил на всякий Disease сразу в bmp (8-bit) без пересохранения. А то изначально сохранил картинку в спешке в jpg. При пересохранении высококачественного jpg в bmp, хоть размер и остается тот же, но хеш-сумма, конечно, меняется. На счет потерь в качестве не знаю, но алгоритмы обработки там при первом сохранении в jpg и bmp разные.
Вложения
Disease.rar
(2.1 КБ) Скачиваний: 132
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

cron