Объявления

Форум о Героях Меча и Магии и King's Bounty. Если Вы любите эти игры, мы будем рады видеть Вас в наших рядах. :smile2:

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 13 авг 2019, 16:25

Цитата:
e.g. Spell loop @ 0x54AE39

Needs code examle how to disable any spell.
Cann't understand this:
Код: Выделить всё
    LOBYTE(i) = 0;
    do
    {
      if ( (1 << (v100 & 0x1F)) & *(&v138 + (v100 >> 5)) )
        *((_BYTE *)&v145 + (v100 >> 3)) |= 1 << (v100 & 7);
      ++v100;
    }
    while ( v100 < 0x46 );
Вернуться к началу

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

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

Сообщение AlexSpl » 13 авг 2019, 18:19

Здесь идёт работа с битовым массивом. Всего в игре 70 заклинаний, и если каждому заклинанию отвести один бит (0 - разрешено на случайной карте, 1 - запрещено), то для хранения такой маски заклинаний потребуется ceil(70 / 32) = ceil(2.1875) = 3 двойных слова. Код выше последовательно читает биты этой маски, и если бит заклинания в маске RMG установлен (test [ebp+ecx*4+var_34], eax), то он также устанавливается и в соответствующей маске карты.

Т.е. Вам нужно поставить лоухук до этого цикла (например, в начале блока 54AE23h) и прописать свою маску:

Код: Выделить всё
*(int*)(с->ebp - 0x34) = Mask0;
*(int*)(с->ebp - 0x34 + 4) = Mask1;
*(int*)(с->ebp - 0x34 + 8) = Mask2;


Мask0, Mask1 и Mask2 - три части маски заклинаний. Биты заклинаний с номерами от 0 до 31 хранятся в первой маске, от 32 до 63 - во второй, а в третьей - все остальные.
Вернуться к началу

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

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

Сообщение AlexSpl » 13 авг 2019, 20:45

Вот код, запрещающий заклинания:

Код: Выделить всё
#include "pch.h"
#include "..\HotA\homm3.h"

Patcher* _P;
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

int* DisabledSpells;

void disableSpells(int count, ...)
{
    va_list spells;

    va_start(spells, count);
    for (int i = 0; i < count; ++i)
    {
        int spellID = va_arg(spells, int);
        *(int*)(DisabledSpells + (spellID >> 5)) |= 1 << (spellID & 31);
    }
    va_end(spells);
   
    return;
}

int __stdcall RMGDisableSpells(LoHook* h, HookContext* c)
{
    DisabledSpells = (int*)(c->ebp - 0x34);
    disableSpells(4, SPL_MAGIC_ARROW, SPL_SLOW, SPL_STONE_SKIN, SPL_SHIELD);
   
    return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    if (DLL_PROCESS_ATTACH == ul_reason_for_call)
    {
        if (!plugin_On)
        {
            plugin_On = 1;
            _P = GetPatcher();
            _PI = _P->CreateInstance((char*)"HD.Plugin.RMGDisableSpells");
            _PI->WriteLoHook(0x54AE23, RMGDisableSpells);
        }
    }

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

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 233 раз.

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

Сообщение RoseKavalier » 13 авг 2019, 21:19

Toggleflag(&int) changes the value of the flag you pass as argument.
I don't know how it's coded by HW rulez plugin and don't have time to look but chances are it's not a H3DlgCustomButton but instead a H3DlgDef or H3DlgDefButton. Still the logic to toggle its value should be similar, just remember to redraw it afterward, just look at Toggleflag() code if in doubt!

You can use Alex's code or use the H3Bitfield structure to ban spells.
Код: Выделить всё
H3Bitfield *banned_spells = (H3Bitfield *)(c->ebp - 0x34);
banned_spells ->SetState(H3Spell::SUMMON_BOAT, TRUE);
Вернуться к началу

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

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

Сообщение AlexSpl » 13 авг 2019, 22:34

Цитата:
Having one result - flag on is working, flag off didn't


Цитата:
Item2Stack->ToggleFlag(GamePlayChangesOn);

b->ToggleFlag(GamePlayChangesOn);


Может быть, причина в том, что Вы переключаете флаг дважды?

Код: Выделить всё
inline void H3DlgCustomButton::ToggleFlag(BOOL & flag)
{
   defFrame = !defFrame;
   defFrameOnClick = !defFrameOnClick;
   flag = !flag;
   Draw();
   Refresh();
}


В самом первом варианте у Вас и первая, и вторая команда изменяют его: если флаг был true, то первая команда переключит его в состояние false, и это значение станет аргументом для второй команды, которая тоже его переключит, и флаг опять станет true. Для случая false аналогично: false -> true -> false. Во втором, вроде, всё должно бы работать...

Что такое GetH3DlgItem(CheckBoxID) и GetH3DlgItem(101)? Чему равен CheckBoxID? Случайно не 101?
Вернуться к началу

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

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

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

Кстати, проверил плагин, запрещающий заклинания. В гильдии магов запрещённые заклинания не появляются, да, но их можно получить, например, из свитков. Видимо, при генерации свитков (и, предполагаю, прочих объектов, дающих заклинания) маска* запрещённых заклинаний не применяется, и нужно ставить дополнительные лоухуки на генерацию содержимого таких объектов. Заметьте ещё, что заклинания в гильдии магов меняются при рестарте карты, а заклинания в свитках - нет.

* Вообще, обычно термин "маска" предполагает логическое И, и если бы в игре был битовый массив разрешённых заклинаний, то проблем с названием не было бы, но в игре - битовый массив запрещённых заклинаний, поэтому употреблять термин "маска" не совсем корректно :smile1: Но всё равно удобно называть этот битовый массив маской (пусть or-маской).
Вернуться к началу

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

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

Сообщение AlexSpl » 14 авг 2019, 05:03

Плагин, запрещающий заклинания в гильдиях магов и свитках:

Код: Выделить всё
#include "pch.h"
#include "..\HotA\homm3.h"

Patcher* _P;
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

int* DisabledSpells;
int DisabledSpellsList[] = {SPL_MAGIC_ARROW, SPL_SLOW, SPL_STONE_SKIN, SPL_SHIELD};

void disableSpells()
{
    for (int i = 0; i < sizeof(DisabledSpellsList) / sizeof(int); ++i)
    {
        *(int*)(DisabledSpells + (DisabledSpellsList[i] >> 5)) |= 1 << (DisabledSpellsList[i] & 31);
    }
       
    return;
}

int __stdcall RMGDisableSpells(LoHook* h, HookContext* c)
{
    DisabledSpells = (int*)(c->ebp - 0x34);
    disableSpells();
   
    return EXEC_DEFAULT;
}

bool isSpellAllowed(int ID)
{
    bool isAllowed = true;
   
    for (int i = 0; i < sizeof(DisabledSpellsList) / sizeof(int); ++i)
    {
        if (ID == DisabledSpellsList[i])
        {
            isAllowed = false;
            break;
        }
    }

    return isAllowed;
}

// Считаем кол-во разрешённых заклинаний
int __stdcall RMGDisableSpellsInScrollsA(LoHook* h, HookContext* c)
{
    // Получаем ID текущего заклинания
    int ID = (c->eax - (int)&o_Spell->school_flags) / sizeof(_Spell_);

    if (!isSpellAllowed(ID))
    {
        c->return_address = 0x5353EE;
        return NO_EXEC_DEFAULT;
    }
       
    return EXEC_DEFAULT;
}

// Выбираем разрешённое заклинание
int __stdcall RMGDisableSpellsInScrollsB(LoHook* h, HookContext* c)
{
    // Получаем ID текущего заклинания
    int ID = (c->eax - (int)&o_Spell->school_flags) / sizeof(_Spell_);

    if (!isSpellAllowed(ID))
    {
        c->return_address = 0x535423;
        return NO_EXEC_DEFAULT;
    }
       
    return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    if (DLL_PROCESS_ATTACH == ul_reason_for_call)
    {
        if (!plugin_On)
        {
            plugin_On = 1;
            _P = GetPatcher();
            _PI = _P->CreateInstance((char*)"HD.Plugin.RMGDisableSpells");
            _PI->WriteLoHook(0x54AE23, RMGDisableSpells);
           
            // Запрещаем заклинания в свитках
            _PI->WriteLoHook(0x5353E8, RMGDisableSpellsInScrollsA);
            _PI->WriteLoHook(0x535417, RMGDisableSpellsInScrollsB);
        }
    }

    return TRUE;
}

Проверил с помощью Проспектора. Запрещённые заклинания в свитках не генерируются.

Без плагина:

Изображение

С плагином:

Изображение

Возможно, для Святилищ и остальных объектов, дающих заклинания на случайных картах, придётся добавить ещё пару-тройку хуков, хотя Проспектор показывает, что запрещённые заклинания там тоже не генерируются, но проверить лишний раз не помешает.
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 14 авг 2019, 05:48

Цитата:
Плагин, запрещающий заклинания в гильдиях магов и свитках:

Шикарно! Проверил все работает как надо!
В свитках и ГМ 100% не появляется.

Единственное, я наивно думал, что это должно было быть гораздо проще.
Как с артами, с ними вот так работает:
Код: Выделить всё
   P_Artifacts[H3Artifact::SEA_CAPTAINS_HAT].disabled = 1;
   P_Artifacts[H3Artifact::BOOTS_OF_LEVITATION].disabled = 1;
   P_Artifacts[H3Artifact::NECKLACE_OF_OCEAN_GUIDANCE].disabled = 1;


Еще бы навигацию запретить, посмотрю - если там такая же схема как с заклинаниями, то я смогу сделать.
Последний раз редактировалось as239 14 авг 2019, 05:54, всего редактировалось 1 раз.
Вернуться к началу

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

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

Сообщение AlexSpl » 14 авг 2019, 05:51

Цитата:
Единственное, я наивно думал, что это должно было быть гораздо проще.


Для свитков почему-то не учитывается маска запрещённых заклинаний. Если убрать последние два хука, то запрещённые заклинания будут генерироваться в свитках. Вот такой нюанс.
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 14 авг 2019, 06:00

Цитата:
Что такое GetH3DlgItem(CheckBoxID) и GetH3DlgItem(101)? Чему равен CheckBoxID? Случайно не 101?

GetH3DlgItem(CheckBoxID) - получает мой флаг "Gameplay changes"
GetH3DlgItem(101) - получает флаг "Always 2nd hero stack"
Id у них естественно разные.
Я хочу чтобы:
1. При установке "Gameplay changes" флаг "Always 2nd hero stack" также устанавливался
2. При сбрасывании "Gameplay changes" также сбрасывался флаг "Always 2nd hero stack".
Так вот чтобы я не делал, какие значения не передавал п.1 всегда работает, а п.2 никогда.
Вернуться к началу

Пред.След.

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

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

Сейчас этот форум просматривают: Yandex [bot] и гости: 1