Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 26 сен 2017, 19:08

Пишу хук по адресу 4E4ACB

Почему-то в следующую переменную попадают различные результаты при разных запусках (герой один и тот же) -
Код: Выделить всё
int learningSkill = *(int*)(c->ecx + 0xDE);


И так пробовал, бесполезно -
Код: Выделить всё
int learningSkill = *(int*)((c->ecx) + 222);
Вернуться к началу

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 » 26 сен 2017, 19:47

Потому что тип поля - char (1 байт). Т.е. в остальных трёх байтах может быть мусор. Нужно так:

Код: Выделить всё
char learningSkill = *(char*)(c->ecx + 0xDE);

или

Код: Выделить всё
_Hero_* hero = (_Hero_*)c->ecx;
char learningSkill = hero->second_skill[HSS_LEARNING];
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 27 сен 2017, 15:28

Написал плагин для адекватной работы навыка Обучение - теперь герой с данным навыком с увеличением количества опыта увеличивает свой уровневый отрыв от героя без данного навыка.
Сравнительное движение героев по уровням:

Герой с навыком: 1->3->8->16->21->25->37->40->46
Герой без навыка: 1->3->7->11->14->17->27->30->34

Суть нововведения в том, что количество дополнительного опыта рассчитывается исходя из текущего уровня героя
(это количество линейно зависит от текущего уровня, степень же навыка является дополнительным множителем).

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

    Patcher* _P;
    PatcherInstance* _PI;

    static _bool_ plugin_On = 0;

 
   int __stdcall changeLearningPower(LoHook* h, HookContext* c)
   {
      char learningSkill = *(char*)(c->ecx + 0xDE);
      _word_ heroLevel = *(int*)(c->ecx + 0x55);

      float multiplier = learningSkill * heroLevel / (float)15.0;
      *(float*)(c->ebp - 4) = (float)multiplier;

      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("HD.Plugin.LearningSkill");
           
          _PI->WriteLoHook(0x4E4ACD, changeLearningPower);
          }
       }
       
       return TRUE;
    }

Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 27 сен 2017, 15:38

Кстати, куда правильнее хук поставить - на 4E4ACD или 4E4ACB ?
Вернуться к началу

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 » 27 сен 2017, 16:19

Цитата:
Код: Выделить всё
_word_ heroLevel = *(int*)(c->ecx + 0x55);

Тут тоже потенциально мусор можно прочитать, если младшие два байта следующего поля (visited[0]) окажутся ненулевыми. Чтобы не путаться, лучше использовать типы из структуры:

Код: Выделить всё
_word_ heroLevel = *(_word_*)(c->ecx + 0x55);


Тип _word_ (слово, 2 байта) определён как unsigned __int16 (или unsigned short, если нравятся стандартные типы). В данном примере unsigned вообще можно опустить, т.к. уровень героя на практике не может превысить 0x7FFF (32767):

Код: Выделить всё
short heroLevel = *(short*)(c->ecx + 0x55);


Цитата:
Кстати, куда правильнее хук поставить - на 4E4ACD или 4E4ACB ?

В данном случае особой разницы нет. Но если поставить на 4E4ACDh, код патча просто лишний раз (кода у героя нет Learning) выполняться не будет, что только +.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 27 сен 2017, 17:28

На виртуальной машине у меня даже в Windows 10 не хотят плагины HD мода работать.
Есть какой-то секрет ?
Вернуться к началу

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 » 27 сен 2017, 17:49

Не знаю. Я на VMware Workstation тестил. Сразу всё заработало. На Windows 7 не пошло.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 28 сен 2017, 07:26

Другой вариант плагина представлен ниже.
Тогда в подсказке по навыку можно будет написать почти то же самое что и в оригинале -
что навык дает дополнительные 5/10/20% опыта за каждый уровень, достигнутый героем.

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

        Patcher* _P;
        PatcherInstance* _PI;

        static _bool_ plugin_On = 0;

     
       int __stdcall changeLearningPower(LoHook* h, HookContext* c)
       {
          char learningSkill = *(char*)(c->ecx + 0xDE);
          _word_ heroLevel = *(int*)(c->ecx + 0x55);

          if(learningSkill == 1)
          *(float*)(c->ebp - 4) = (float)(heroLevel * 0.05)
          if(learningSkill == 2)
          *(float*)(c->ebp - 4) = (float)(heroLevel * 0.10)
          if(learningSkill == 3)
          *(float*)(c->ebp - 4) = (float)(heroLevel * 0.20)

          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("HD.Plugin.LearningSkill");
               
              _PI->WriteLoHook(0x4E4ACD, changeLearningPower);
              }
           }
           
           return TRUE;
        }

Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 28 сен 2017, 07:28

Подскажите, пожалуйста, как сделать так, чтобы водоворот манны давал случайное количество манны (максимум - удвоенное) ? При этом чтобы в городе Темницы можно было бы восстанавливать манну, в случае недельного исчерпания водоворота, как и в других замках.
Вернуться к началу

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 » 28 сен 2017, 08:55

Например, так:

Код: Выделить всё
int __stdcall manaVortex(LoHook* h, HookContext* c)
{
    unsigned int dice;
    rand_s(&dice);
   
    // maxMana (c->eax) - максимальный запас маны: (int)(10 * knowledge * modifier)
    // curMana (c->ebx) - текущий запас маны: maxMana + rand(1, maxMana)
    c->ebx = c->eax + (unsigned int)((double)dice / ((double)UINT_MAX + 1) * c->eax) + 1;

    return EXEC_DEFAULT;
}

// Новое сообщение
int __stdcall manaVortexDlg(LoHook* h, HookContext* c)
{
    _Hero_* hero = (_Hero_*)c->edi;
    char Text[200];
    sprintf(Text, "{%s}, близ вихря маны Ваше тело наполняется новой силой. " \
        "Количество маны увеличилось на {%d} ед. и теперь составляет {%d} ед.",
        hero->name, c->ebx - hero->spell_points, c->ebx);
    b_MsgBox(Text, MBX_OK);
   
    c->return_address = 0x5BDD92;
    return NO_EXEC_DEFAULT;
}

...

_PI->WriteLoHook(0x5BDD4E, manaVortex);
_PI->WriteLoHook(0x5BDD66, manaVortexDlg);


Цитата:
При этом чтобы в городе Темницы можно было бы восстанавливать манну, в случае недельного исчерпания водоворота, как и в других замках.

Не понял.

* * *
Ещё можно одним хуком (чуть сложнее, зато понятнее):

 
Код: Выделить всё
int __stdcall manaVortex(LoHook* h, HookContext* c)
{
    _Town_* town = (_Town_*)c->esi;
    _Hero_* hero = (_Hero_*)c->edi;

    unsigned int dice;
    rand_s(&dice);
   
    // maxMana - максимальный запас маны: (int)(10 * knowledge * modifier)
    // curMana - текущий запас маны: maxMana + rand(1, maxMana)
    int maxMana = c->eax;
    int curMana = maxMana + 1 + (unsigned int)((double)dice / ((double)UINT_MAX + 1) * maxMana);

    if (curMana > hero->spell_points)
    {
        if ( CALL_2(_byte_, __thiscall, 0x4CE630, o_GameMgr, town->owner_id) ) {
            char Text[200];
            sprintf(Text, "{%s}, близ вихря маны Ваше тело наполняется новой силой. " \
                "Количество маны увеличилось на {%d} ед. и теперь составляет {%d}/{%d} ед.",
                hero->name, curMana - hero->spell_points, curMana, maxMana);
            b_MsgBox(Text, MBX_OK);
        }

        hero->spell_points = curMana;
        // Сбрасываем флаг "Вихря Маны"
        *(_byte_*)((int)town + 51) = 0;
    }

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

...

_PI->WriteLoHook(0x5BDD4E, manaVortex);
Вернуться к началу

Пред.След.

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

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

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

cron