Объявления

Друзья, если не получается зарегистрироваться, напишите на почту 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 » 14 окт 2020, 17:04

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

Это только для стрелков. Для милишников нужен такой же патч в другом месте.
Вернуться к началу

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 » 14 окт 2020, 17:16

Плагин с исправлениями для нейтралов:

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

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

int __stdcall BadLuckAnim(LoHook* h, HookContext* c)
{
    int Luck = c->eax;
       
    if ( Luck < 0 )
    {
        if ( Luck < -3 ) Luck = -3;
        // RandomInt(1, 12);
        if ( CALL_2(int, __fastcall, 0x50C7C0, 1, 12) <= -Luck )
        {
            _BattleStack_* stack = (_BattleStack_*)c->esi;
            // Setting Luck flag to Bad Luck state (-1)
            stack->field_70 = -1;
            // Is battle visible?
            if ( !CALL_1(bool, __thiscall, 0x46A080, o_BattleMgr) )
            {
                // Play sound
                CALL_3(void, __fastcall, 0x59A890, (const char*)"badluck.82m", -1, 3);
                // Show message
                sprintf(o_TextBuffer, o_GENRLTXT_TXT->GetString(45),
                    CALL_2(const char*, __fastcall, 0x43FE20, stack->creature_id, stack->count_current));
                CALL_4(void, __thiscall, 0x4729D0, o_BattleMgr->dlg, o_TextBuffer, 1, 0);
                // Play animation
                CALL_5(void, __thiscall, 0x4963C0, o_BattleMgr, 48, stack, 100, 0);
            }
        }
        c->eax = 0;
    }

    return EXEC_DEFAULT;
}

int __stdcall HalveBasicDamage(HiHook* hook, _BattleStack_* stack, int a1)
{
    int BasicDamage = CALL_2(int, __thiscall, hook->GetDefaultFunc(), stack, a1);
    if ( stack->field_70 == -1 )
    {
        BasicDamage /= 2;
        if ( BasicDamage < 1 ) BasicDamage = 1;
    }

    return BasicDamage;
}

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.BadLuck");
            _PI->WriteHexPatch(0x43F642, "90 90 90 90 90 90");
            _PI->WriteHexPatch(0x441524, "90 90 90 90 90 90");
            _PI->WriteLoHook(0x43F64E, BadLuckAnim);
            _PI->WriteLoHook(0x441530, BadLuckAnim);
            _PI->WriteHiHook(0x442E80, SPLICE_, EXTENDED_, THISCALL_, HalveBasicDamage);
        }
    }

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

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

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

Сообщение Rolex » 14 окт 2020, 17:46

Добавил в плагин, который меняет диапазон Морали на +24/-12 положительную Удачу в +24. Теперь нужно как-то этот плагин допилить, чтобы при его подключении он патчил тот кусок (изменяя нижнюю границу Удачи с -3 на -12), который добавляет плагин BadLuck.

Изображение
Изображение

Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "patcher_x86.hpp"

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

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.MoraleLuckCap");
// Good Morale Cap
         _PI->WriteHexPatch(0x464580 + 6, "18 00 00 00");
         _PI->WriteHexPatch(0x464580 + 12, "E8");
         _PI->WriteHexPatch(0x464590 + 3, "E8 FF FF FF");
         _PI->WriteHexPatch(0x4645A0, "18");
// Bad Morale Cap
         _PI->WriteHexPatch(0x464740 + 11, "0C 00 00 00");
         _PI->WriteHexPatch(0x464750 + 4, "F4 FF FF FF");
         _PI->WriteHexPatch(0x464770 + 12, "F4");
         _PI->WriteHexPatch(0x464780 + 12, "0C");
      
// Good Luck Cap
       _PI->WriteHexPatch(0x43F650 + 8, "18");
       _PI->WriteHexPatch(0x43F650 + 15, "18");
       _PI->WriteHexPatch(0x43F660, "00 00 00");
      
       _PI->WriteHexPatch(0x441530 + 10, "18");
       _PI->WriteHexPatch(0x441540 + 1, "18 00 00 00");
      
// Bad Luck Cap

      }
   }

   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 » 14 окт 2020, 17:50

Просто уберите ограничение if ( Luck < -3 ) Luck = -3;

* * *
Насчёт излишнего дробления кода плагинами. Это не совсем удачный подход хотя бы потому, что придётся следить за порядком их загрузки. Более гибкое решение для взаимосвязанных изменений - один плагин с зависимым кодом и ini-файл, в котором можно включать или выключать определённый функционал этого плагина. Для удобства пользователя можно написать утилиту для отключения ненужных компонентов. В лончере HD-мода используется похожая идея, но она не очень подходит для случая плагинов с взаимосвязанным кодом.
Вернуться к началу

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

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

Сообщение Rolex » 14 окт 2020, 18:06

AlexSpl писал(а):

Просто уберите ограничение if ( Luck < -3 ) Luck = -3;

Не, я BadLuck не хочу трогать. Можно ли как-то из этого сделать это? То есть, если нужны другие диапазоны Морали/Удачи, то подключаешь нужный плагин с нужным диапазоном, если ненужны - отключаешь и юзаешь дефолтные +3/-3.
Вернуться к началу

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 » 14 окт 2020, 18:11

Через ini-файл можно, как я написал выше. Либо придётся менять порядок загрузки плагинов в лончере, чтобы можно было сделать проверку, загружен ли плагин, от которого зависит другой плагин.

Проще говоря, в Вашем случае Вы не сможете убрать строчку if ( Luck < -3 ) Luck = -3; плагином, который изменяет кап Неудачи, если первый не загружен. Или наоборот - плагин на Неудачу не сможет проверить, нужно ли ему удалять эту строчку, если он не знает, загружен ли второй. Вы, конечно, можете менять порядок загрузки плагинов в лончере, но это не очень удачное решение, которое приведёт к путанице.
Вернуться к началу

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

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

Сообщение Rolex » 14 окт 2020, 18:42

В принципе можно проще, без доп ini. По умолчанию подключен плагин BadLuck с if ( Luck < -3 ) Luck = -3, а когда нужны другие границы Морали/Удачи (например, есть два плагина +6/-6 и +24/-12), то к каждому (в папке 2 dll-ки) будет идти доп dll-ка BadLuck с if ( Luck < -6 ) Luck = -6 и BadLuck с if ( Luck < -12 ) Luck = -12, соответственно. Да, это очень кривое решение, так как весь код BadLuck за исключением одной строчки повторяется трижды, но самое простое.
Вернуться к началу

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 » 14 окт 2020, 19:20

Цитата:
Код: Выделить всё
_PI->WriteHexPatch(0x43F650 + 15, "18");
_PI->WriteHexPatch(0x43F660, "00 00 00");

Так писать необязательно :smile2: В hex-редакторах код разбит на строки по 16 байт для удобства. Т.е. код выше эквивалентен

Код: Выделить всё
_PI->WriteHexPatch(0x43F650 + 15, "18 00 00 00");

Ещё можно не патчить то, что не изменяется. Например, хвост из нулей можно опустить. Но я рекомендую делать это, пока не станет легче патчить через WriteByte/WriteWord/WriteDword.
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

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

Сообщение igrik » 15 окт 2020, 07:23

Я увидел у вас танцы с бубном вокруг всей некромантии.
Всё можно сделать куда проще:
Код: Выделить всё
// ослабление всей некромантии разом
float __stdcall GetNecromancyPower(HiHook* hook, _Hero_* hero, char isEndBATTLE)
{
   float power;
   power = CALL_2(float, __thiscall, hook->GetDefaultFunc(), hero, isEndBATTLE);

   // режем всю некромантию в 2 раза
   if (power)
      power *= 0.5;

   return power;
}

// хук на некромантию
_PI->WriteHiHook(0x4E3F40, SPLICE_, EXTENDED_, THISCALL_, GetNecromancyPower);


Rolex , просмотрите плагин/мод adfontes. В нём половина вашей работы уже сделана.
https://sites.google.com/site/heroes3ad ... u/download

Мод распространяется вместе с исходниками!
https://drive.google.com/file/d/1xCUUgs ... IT55S/view
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

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

Сообщение igrik » 15 окт 2020, 09:42

Плохо так делать, открыаешь дизасамблер - а там не код, а лапша.
Думайте пожалуйста о других модерах, которые потом пытаются это всё прочитать и понять почему их плагин не работает или вылетает если ваш плагин подключился.
Код: Выделить всё
_PI->WriteHexPatch(0x43F642, "90 90 90 90 90 90");
_PI->WriteLoHook(0x43F64E, BadLuckAnim);


Почему не поставить лоухук в место установки патча?
С коментариями понятно зачем и почему код ставится в одно и то же место.
Код: Выделить всё
// Включаем удачу без героя в ближнем бою.
_PI->WriteHexPatch(0x43F642, "90 90 90 90 90 90");
// А потом в это же место добавляем неудачу в ближнем бою.
// В итоге: не превращаем код в лапшу
_PI->WriteLoHook(0x43F642, BadLuckAnim);


Потом просто параметр удачи берём не из eax, а из структуры монстра.
И волки сыты, и половина овец цела...
 Я бы сделал код таким
Код: Выделить всё
#define BADLUCK_MIN -3
#define BADLUCK_CHANCE 12

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

int __stdcall BattleStack_BadLuckAnim(LoHook* h, HookContext* c)
{
    _BattleStack_* stack = (_BattleStack_*)c->esi;

    if (stack)
    {
        int luck = stack->luck;

        if ( luck < 0 )
        {
            if ( luck < BADLUCK_MIN )
                luck = BADLUCK_MIN;

            if ( Randint(1, BADLUCK_CHANCE) <= abs(luck) )
            {           
                stack->isLucky = -1;

                if ( !o_BattleMgr->ShouldNotRenderBattle() )
                {
                    Sound_Play_Wav((const char*)"badluck.82m");

                    sprintf(o_TextBuffer, o_GENRLTXT_TXT->GetString(46),
                        GetCreatureName(stack->creature_id, stack->count_current));
                    o_BattleMgr->AddStatusMessage(o_TextBuffer);

                    stack->PlayMagicAnimation(48, 0);

                }
            }
        }
    }

    return EXEC_DEFAULT;
}

int __stdcall Battle_Stack_CalcDamage(HiHook* hook, _BattleStack_* stack, int isTeoreticBattle)
{
    int BasicDamage = CALL_2(int, __thiscall, hook->GetDefaultFunc(), stack, isTeoreticBattle);
    if ( stack->isLucky == -1 )
    {
        BasicDamage /= 2;

        if ( BasicDamage < 1 )
            BasicDamage = 1;
    }

    return BasicDamage;
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

void HooksInit()
{
    // режем урон, если сработала неудача
    _PI->WriteHiHook(0x442E80, SPLICE_, EXTENDED_, THISCALL_, Battle_Stack_CalcDamage);

    // Включаем удачу без героя в ближнем бою.
    _PI->WriteCodePatch(0x44151D, "%n", 13); // 13 nop
    // А потом в это же место добавляем неудачу в ближнем бою.
    // В итоге: не превращаем код в лапшу
    _PI->WriteLoHook(0x44151D, BattleStack_BadLuckAnim);

    // Включаем удачу без героя в при стрельбе.
    _PI->WriteCodePatch(0x43F635, "%n", 13); // 13 nop
    // А потом в это же место добавляем неудачу при стрельбе.
    // В итоге: не превращаем код в лапшу
    _PI->WriteLoHook(0x43F635, BattleStack_BadLuckAnim);
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

BOOL APIENTRY DllMain ( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
{
    static _bool_ initialized = 0;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        if (!initialized)
        {
            initialized = 1;

            _P = GetPatcher();
            _PI = _P->CreateInstance("BadLuck");

            HooksInit();
           
        }
        break;

    case DLL_PROCESS_DETACH:
        if (initialized)
            initialized = 0;
        break;

    case DLL_THREAD_ATTACH:
        break;

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

Пред.След.

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

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

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