Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 19 авг 2021, 07:22

А у Вас уже получалось находить свитки с Fear?
Вернуться к началу

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

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

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

AlexSpl писал(а):

А у Вас уже получалось находить свитки с Fear?

Пока нет. Нужно шаблон подходящий найти, где будет генерится много свитков с заклами 4-го и 5-го уровня.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

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

Оказывается, ни один сборный артефакт в оригинальных Героях 3 не состоит из артефактов-частей, которые дают заклинания. Однако код, который обрабатывает такую ситуацию присутствует. Например, если бы в игре был сборный артефакт из всех четырёх томов стихий, то он бы продолжал давать заклинания каждого тома стихии в собранном виде.

Полностью переписал функцию, дающую и отбирающую заклинания при экипировке/снятии артефактов (наверное, в этой теме это единственный пример хайхука, который переписывает целиком всю функцию):

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

#define SPELLS_MAX 128
#define ARTIFACTS_NUM 144
#define SPELLS_NUM 71
#define SPL_FEAR 70

Patcher* _P;
PatcherInstance* _PI;

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

#define o_ComboArtInfo (*(_ComboArtInfo_**)0x660B6C)

_Spell_ spell[SPELLS_MAX];
//char iniPath[MAX_PATH];

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

   spell[SPL_FEAR].type = -1;
   spell[SPL_FEAR].wav_name = "Fear.wav";
   spell[SPL_FEAR].animation_ix = 15;
   spell[SPL_FEAR].flags = 0x20415;
   spell[SPL_FEAR].name = "Fear";
   spell[SPL_FEAR].short_name = "Fear";
   spell[SPL_FEAR].level = 4;
   spell[SPL_FEAR].school_flags = 8;
   spell[SPL_FEAR].mana_cost[0] = 16;
   spell[SPL_FEAR].mana_cost[1] = 8;
   spell[SPL_FEAR].mana_cost[2] = 8;
   spell[SPL_FEAR].mana_cost[3] = 8;
   spell[SPL_FEAR].eff_power = 0;
   spell[SPL_FEAR].effect[0] = 75;
   spell[SPL_FEAR].effect[1] = 75;
   spell[SPL_FEAR].effect[2] = 50;
   spell[SPL_FEAR].effect[3] = 25;
   spell[SPL_FEAR].chance2get_var[0] = 10;
   spell[SPL_FEAR].chance2get_var[1] = 10;
   spell[SPL_FEAR].chance2get_var[2] = 10;
   spell[SPL_FEAR].chance2get_var[3] = 10;
   spell[SPL_FEAR].chance2get_var[4] = 10;
   spell[SPL_FEAR].chance2get_var[5] = 10;
   spell[SPL_FEAR].chance2get_var[6] = 10;
   spell[SPL_FEAR].chance2get_var[7] = 10;
   spell[SPL_FEAR].chance2get_var[8] = 10;
   spell[SPL_FEAR].ai_value[0] = 50;
   spell[SPL_FEAR].ai_value[1] = 50;
   spell[SPL_FEAR].ai_value[2] = 50;
   spell[SPL_FEAR].ai_value[3] = 50;
   spell[SPL_FEAR].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].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].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].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";

   for (int i = SPL_FEAR + 1; i < SPL_FEAR + 11; ++i)
      spell[i] = o_Spell[i];

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

   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);
         
         _PI->WriteByte (0x41FC91, SPELLS_NUM);
         _PI->WriteDword(0x425E98, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x427085, SPELLS_NUM);
         _PI->WriteDword(0x432A43, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x432D1E, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x43C21B, SPELLS_NUM * sizeof(_Spell_)); // Master Genie AI
         _PI->WriteDword(0x43C6F2, SPELLS_NUM * sizeof(_Spell_)); // Battle AI
         _PI->WriteDword(0x447551, SPELLS_NUM * sizeof(_Spell_)); // Casters
         _PI->WriteDword(0x447C7D, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x447CC8, SPELLS_NUM * sizeof(_Spell_));
         
         // Cheats in battle
         _PI->WriteByte (0x471C57, SPELLS_NUM);
         
         _PI->WriteByte (0x4864B0, SPELLS_NUM);
         _PI->WriteByte (0x48A34B, SPELLS_NUM);
         _PI->WriteByte (0x4C244D, SPELLS_NUM);
         _PI->WriteByte (0x4C246F, SPELLS_NUM);
         _PI->WriteDword(0x4C24C9, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteByte (0x4E67AC, SPELLS_NUM);
         _PI->WriteByte (0x4F508B, SPELLS_NUM);
         _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_));
                  
         // TODO: _GameMgr_.disabled_spells[SPELLS_NUM]

         // Pyramid
         _PI->WriteByte (0x4C170D, SPELLS_NUM);
         
         _PI->WriteByte (0x4C250E, SPELLS_NUM);
         _PI->WriteDword(0x4C2557, SPELLS_NUM * sizeof(_Spell_));
         
         _PI->WriteDword(0x4C260D, SPELLS_NUM * sizeof(_Spell_));
         _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);
         _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(0x527B08, SPELLS_NUM * sizeof(_Spell_));
         _PI->WriteDword(0x52A9B6, SPELLS_NUM * sizeof(_Spell_)); // AI
         _PI->WriteDword(0x534C4B, SPELLS_NUM * sizeof(_Spell_)); // RMG
         _PI->WriteDword(0x5353D5, SPELLS_NUM);
         _PI->WriteByte (0x53542B, SPELLS_NUM);
         _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_)); // Spell Book
         _PI->WriteDword(0x5A1AD6, SPELLS_NUM * sizeof(_Spell_)); // Cast 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);

         _PI->WriteDword(0x40D97C, 0x3EA);
         _PI->WriteDword(0x41FBDF, 0x3EA);
         _PI->WriteDword(0x425C72, 0x3EA);
         _PI->WriteDword(0x427039, 0x3EA);
         _PI->WriteDword(0x427044, 0x3EA);
         _PI->WriteDword(0x4329C1, 0x3EA);
         _PI->WriteDword(0x432CDE, 0x3EA);
         _PI->WriteDword(0x433026, 0x3EA);
         _PI->WriteDword(0x4336C0, 0x3EA);
         _PI->WriteDword(0x439330, 0x3EA);
         _PI->WriteDword(0x43C561, 0x3EA);
         
         // Clear _Hero_.spell[140] (optional)
         _PI->WriteDword(0x48647A, 0x23);
         _PI->WriteJmp(0x486485, 0x486498);
         
         _PI->WriteDword(0x4E57CC, 0x3EA);
         _PI->WriteDword(0x527ACB, 0x3EA);
         _PI->WriteDword(0x52A97A, 0x3EA);
         _PI->WriteDword(0x52AE1C, 0x3EA);
         // Spell Book
         _PI->WriteDword(0x59CD5E, 0x3EA);

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

   return TRUE;
}

Заодно посмотрел сборные артефакты. Оказывается, довольно легко добавлять новые сборники или менять их составные части.

* * *
Начал думать, как лучше решить проблему _GameMgr_.disabled_spells[SPELLS_NUM] (по сравнению с расширением _Hero_.spell[SPELLS_NUM] это семечки), и совершенно случайно наткнулся на Пирамиду (кстати, можете потестить, я обновил код выше) :smile18:

Изображение

Теперь точно 50% готово :smile11:
Вернуться к началу

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

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

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

AlexSpl писал(а):

и совершенно случайно наткнулся на Пирамиду (кстати, можете потестить, я обновил код выше)

Подтверждаю, теперь алгоритм работает и наш закл 5-го уровня попадает в Пирамиду. Тестил на русскоязычной версии.

AlexSpl писал(а):

Заодно посмотрел сборные артефакты. Оказывается, довольно легко добавлять новые сборники или менять их составные части.

Значит можно будет после NewSpells сделать и сборники: Железный кулак огра, Кулон отражения, Мантию дипломата и Золотого гуся. В перерывах от KB II. :smile1:
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 19 авг 2021, 11:10

Цитата:
Значит можно будет после NewSpells сделать и сборники: Железный кулак огра, Кулон отражения, Мантию дипломата и Золотого гуся.

А смысл? Зачем переносить HotA в SoD? Почему бы сразу не играть в HotA? :smile1:
Вернуться к началу

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

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

Сообщение Rolex » 19 авг 2021, 11:16

Все дело в том, что эти сборники должны были быть в SoD, так как планировались изначально разработчиками. А в HotA присутствует немало того, что изначально и не планировалось разработчиками оригинала, и не всем игрокам по душе. Будет некая альтернатива HotA, прокачанный SoD с набором полезных плагинов.
Последний раз редактировалось Rolex 19 авг 2021, 11:24, всего редактировалось 2 раз(а).
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 19 авг 2021, 11:19

Цитата:
Все дело в том, что эти сборники должны были быть в SoD

Откуда информация про Золотого гуся? Остальным трём даже ID назначены: 141, 142, 143.
Вернуться к началу

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

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

Сообщение Rolex » 19 авг 2021, 11:21

AlexSpl писал(а):

Откуда информация про Золотого гуся?

Гусь под вопросом. Но его тоже можно сделать. Вроде, что-то подобное было Героях 2.
Последний раз редактировалось Rolex 19 авг 2021, 11:32, всего редактировалось 2 раз(а).
Вернуться к началу

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

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

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

Мне вот интересно, а добавить совершенно новый вторичный навык или совершенно новый артефакт (не сборник!) сложно ли будет при наличии уже готовых картинок для этого дела? Сложнее нового закла или легче?
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 19 авг 2021, 11:30

Кстати, заметил недоделку HD. При посещении Святыни (Shrine), которая даёт заклинания 1-го уровня, не отображается картинка для заклинания Bless (для других - отображается). Сначала подумал, что плагин чудит. Отключил. Убрал из Common def'ы. Всё равно вот так:

Изображение

Можете проверить у себя?

Так, я понял. Без картинки - это когда герой уже знает заклинание :smile4:
Вернуться к началу

Пред.След.

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

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

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