Объявления

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

Пользовательские плагины для HD мода

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

Пользовательские плагины для HD мода

Сообщение AlexSpl » 02 окт 2017, 19:00

В эту тему предлагаю складывать пользовательские плагины для HD мода. Все обсуждения ведём в соседней теме "Как создать плагин для HD мода".

Формат сообщения:

Автор(ы): ...

Название: ...

Описание: ...

 Код
Код: Выделить всё
// Исходный код плагина

Код прячем под спойлер. К сообщению прикрепляем архив zip с dll и, если требуется, необходимыми для работы плагина файлами.
Вернуться к началу

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

Re: Пользовательские плагины для HD мода

Сообщение AlexSpl » 02 окт 2017, 19:10

Авторы: AlexSpl, Ben80

Название: newEagleEye

Описание: Герои, обладающие вторичным навыком "Орлиный глаз" (Eagle Eye), учат заклинания из книги вражеского героя, как только получают ход в битве. Вероятность выучить заклинание равна (30/35/40 + бонусы за артефакты и специализацию)% для базового, продвинутого и экспертного навыка соответственно.

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

Patcher* _P;
PatcherInstance* _PI;

static _bool_ plugin_On = 0;

struct PicStruc {
    int type;       // тип картинки (9 - заклинание)
    int id;         // ID картинки
};

// кастомный _List_
struct List {
    _ptr_ Creation;
    PicStruc* Data;
    PicStruc* EndData;
    _ptr_ EndMem;
};

int captionAddr;
bool dlgFirst[] = {true, true};

// Заголовок в каждом диалоге
int __stdcall saveCaption(LoHook* h, HookContext* c)
{
    captionAddr = c->ecx;
    return EXEC_DEFAULT;
}

int __stdcall captionFix(LoHook* h, HookContext* c)
{
    *(int*)(c->ebp - 0x14) = captionAddr;
    return EXEC_DEFAULT;
}

int showSpellDlg(_Hero_* hero, int spells[], int nPics)
{
    if ( !nPics ) return 0;

    List picList;

    // Динамический массив картинок
    // Первый и последний элемент резервируем для полей Creation и EndData/EndMem соответственно
    PicStruc* pic = new PicStruc[nPics + 2];

    for (int i = 0; i < nPics; ++i) {
        pic[i + 1].type = 9;
        pic[i + 1].id = spells[i];
    }

    picList.Creation = (_ptr_)pic + 4;
    picList.Data = pic + 1; // Адрес первого элемента в списке
    picList.EndData = picList.Data + nPics; // Адрес следующего за последним элементом в списке байта
    picList.EndMem = (_ptr_)picList.EndData;

    sprintf(o_TextBuffer, "Благодаря навыку {Орлиный глаз}, {%s} выучил%s следующ%s заклинан%s:",
        hero->name, hero->sex ? "а" : "", nPics > 1 ? "ие" : "ее", nPics > 1 ? "ия" : "ие");
    CALL_5(unsigned int, __fastcall, 0x4F7D20, o_TextBuffer, &picList, -1, -1, 0);

    delete [] pic;

    return 0;
}

int getEagleEyeSpells(_Hero_* hero, _Hero_* heroDonor, int spells[])
{
    int n = 0;
    unsigned int eagleEyeProb = (unsigned int)(CALL_1(float, __thiscall, 0x4E4690, hero) * 100.0);

    for (_Spell_* iSpell = o_Spell + SPL_QUICKSAND; iSpell <= o_Spell + SPL_AIR_ELEMENTAL; ++iSpell)
    {
        int i = iSpell - o_Spell;
        if ( heroDonor->spell_level[i] && !hero->spell[i] )
        {
            if ( iSpell->level <= hero->second_skill[HSS_EAGLE_EYE] + 1 )
            {
                unsigned int dice;
                rand_s(&dice);
                dice = (unsigned int)((double)dice / ((double)UINT_MAX + 1) * 100.0) + 1;
                if ( dice <= eagleEyeProb )
                {
                    spells[n++] = i;
                    hero->spell[i] = 1;
                    hero->spell_level[i] = 1;
                }
            }
        }
    }

    return n;
}

int __stdcall eagleEyeMain(LoHook* h, HookContext* c)
{
    _Hero_* hero[] = {o_BattleMgr->hero[ATTACKER], o_BattleMgr->hero[DEFENDER]};

    if ( hero[ATTACKER] && hero[DEFENDER] )
    {
        int spells[70];

        for (int i = ATTACKER; i <= DEFENDER; ++i)
        {
            if ( dlgFirst[i] && o_BattleMgr->current_side == i && hero[i]->second_skill[HSS_EAGLE_EYE] &&
                hero[i]->doll_art[AS_SPELL_BOOK].id == AID_SPELL_BOOK )
            {
                dlgFirst[i] = false;

                // Учим заклинания всегда.
                int n = getEagleEyeSpells(hero[i], hero[1 - i], spells);

                // Но диалог показываем только для игрока-человека:
                // в хотсите - диалог для обоих героев, в сетевой игре - только для своего героя.
                if ( o_GameMgr->GetPlayer(hero[i]->owner_id)->IsHuman() ) {
                    int id = o_GameMgr->GetMeID();
                    if ( !o_NetworkGame || hero[i]->owner_id == id ) {
                        o_ActivePlayerID = hero[i]->owner_id;
                        showSpellDlg(hero[i], spells, n);
                        o_ActivePlayerID = id;
                    }
                }
            }
        }
    }

    return EXEC_DEFAULT;
}

int __stdcall eagleEyeSetGlobalFlags(LoHook* h, HookContext* c)
{
    dlgFirst[ATTACKER] = true;
    dlgFirst[DEFENDER] = true;

    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.NewEagleEye");

            // Меняем коэффициенты
            float eagleEyeCoefs[] = {0.00f, 0.30f, 0.35f, 0.40f};

            _PI->WriteDword(0x63EA2C, (int&)eagleEyeCoefs[1]);
            _PI->WriteDword(0x63EA30, (int&)eagleEyeCoefs[2]);
            _PI->WriteDword(0x63EA34, (int&)eagleEyeCoefs[3]);

            // Убираем оригинальный эффект
            _PI->WriteHexPatch(0x469C23, "EB");
            _PI->WriteHexPatch(0x476996, "E9 DD 01 00 00");

            // Фиксим заголовок диалога
            _PI->WriteLoHook(0x4F7D49, saveCaption);
            _PI->WriteLoHook(0x4F7D54, captionFix);

            _PI->WriteLoHook(0x462C7D, eagleEyeSetGlobalFlags);
            _PI->WriteLoHook(0x477C00, eagleEyeMain);
        }
    }

    return TRUE;
}

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

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

Re: Пользовательские плагины для HD мода

Сообщение AlexSpl » 02 окт 2017, 19:39

Авторы: AlexSpl, FfuzzyLogik

Название: FfuzzyLogik

Описание: Изменяет длительность заклинаний по следующей формуле:

Длительность = 1 + (2 * Сила_Магии + Знание) / n, где

n = 3 для QUICKSAND, PROTECTION FROM AIR, PROTECTION FROM FIRE, PROTECTION FROM WATER, PROTECTION FROM EARTH, BLESS, BLOODLUST, STONE SKIN, MIRTH, FORTUNE, MISFORTUNE, HASTE, SLAYER;

n = 4 для FIRE SHIELD, ANTI-MAGIC, PRAYER, COUNTERSTRIKE;

n = 6 для SHIELD, AIR SHIELD, MAGIC MIRROR, CURSE, PRECISION, WEAKNESS, SORROW, SLOW, FORGETFULNESS, FIRE ELEMENTAL, EARTH ELEMENTAL, WATER ELEMENTAL, AIR ELEMENTAL;

n = 8 для FIREWALL, FRENZY;

n = 10 для FORCEFIELD, HYPNOTIZE, BLIND.

Кроме того, меняет бонус к длительности заклинаний для артефактов Collar of Conjuring, Ring of Conjuring, Cape of Conjuring, Ring of the Magi на 1/1/2/6 раундов соответственно.

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

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

#define RELEASE
#define H_QUICKSAND 0x5A0787
#define H_FORCEFIELD 0x5A0AE2
#define H_FIREWALL 0x5A0C1D

const int hookAddr[] = {H_QUICKSAND, H_FORCEFIELD, H_FIREWALL};
int elemSplDuration[2][21];

#ifdef DEBUG
int showDebugInfo(_ptr_ hAddr, _Hero_* hero, int idSpell, int duration, int n, int artBonus)
{
    sprintf(o_TextBuffer, "{LoHook @ %08X}\n\n%s casts %s\nDuration = %d\nSpell Power = %d\nKnowledge = %d\nFormula: 1 + (2S + K) / %d\nBonus for Artifacts = %d",
        hAddr, hero->name, (o_Spell + idSpell)->name, duration, hero->power, hero->knowledge, n, artBonus);
    CALL_12(void, __fastcall, 0x4F6C00, o_TextBuffer, 1, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0);   
   
    return 0;   
}
#endif

int getArtBonus(_Hero_* hero)
{
    int artBonus = 0;

    if ( hero->DoesWearArtifact(AID_RING_OF_THE_MAGI) ) artBonus = 6; else {
        if ( hero->DoesWearArtifact(AID_COLLAR_OF_CONJURING) ) ++artBonus;
        if ( hero->DoesWearArtifact(AID_RING_OF_CONJURING) ) ++artBonus;
        if ( hero->DoesWearArtifact(AID_CAPE_OF_CONJURING) ) artBonus += 2;
    }

    return artBonus;
}

int getActionId()
{
    return *(int*)o_BattleMgr->Offset(0x3C);
}

int __stdcall splCommon(LoHook* h, HookContext* c)
{
    int n = 0;
    _Hero_* hero = (_Hero_*)o_BattleMgr->hero[o_BattleMgr->current_side];

    if ( getActionId() == 1 )
    {
        switch ( c->ebx )
        {
            case SPL_SHIELD:
            case SPL_AIR_SHIELD:
            case SPL_MAGIC_MIRROR:
            case SPL_CURSE:
            case SPL_PRECISION:
            case SPL_WEAKNESS:
            case SPL_SORROW:
            case SPL_SLOW:
            case SPL_FORGETFULNESS:
                n = 6;
                break;

            case SPL_FIRE_SHIELD:
            case SPL_ANTI_MAGIC:
            case SPL_PRAYER:
            case SPL_COUNTERSTRIKE:
                n = 4;
                break;

            case SPL_PROTECTION_FROM_AIR:
            case SPL_PROTECTION_FROM_FIRE:
            case SPL_PROTECTION_FROM_WATER:
            case SPL_PROTECTION_FROM_EARTH:
            case SPL_BLESS:
            case SPL_BLOODLUST:
            case SPL_STONE_SKIN:
            case SPL_MIRTH:
            case SPL_FORTUNE:
            case SPL_MISFORTUNE:
            case SPL_HASTE:
            case SPL_SLAYER:
                n = 3;
                break;

            case SPL_FRENZY:
                n = 8;
                break;

            case SPL_HYPNOTIZE:
            case SPL_BLIND:
                n = 10;
        }
    }

    if ( n ) {
        int artBonus = getArtBonus(hero);
        c->eax = 1 + (2 * hero->power + hero->knowledge) / n + artBonus;

        #ifdef DEBUG
        showDebugInfo(h->GetAddress(), hero, c->ebx, c->eax, n, artBonus);
        #endif
    }

    return EXEC_DEFAULT;
}

int __stdcall splObsctacle(LoHook* h, HookContext* c)
{
    if ( getActionId() == 1 )
    {
        int n = 1;
        switch ( h->GetAddress() )
        {
            case H_QUICKSAND:
                n = 3;
                break;
           
            case H_FORCEFIELD:
                n = 10;
                break;

            case H_FIREWALL:
                n = 8;
        }
       
        _Hero_* hero = (_Hero_*)o_BattleMgr->hero[o_BattleMgr->current_side];
        int artBonus = getArtBonus(hero);
        int duration = 1 + (2 * hero->power + hero->knowledge) / n + artBonus;

        *(int*)(c->ebp - 0x4C) = duration;
       
        #ifdef DEBUG       
        showDebugInfo(h->GetAddress(), hero, *(int*)(c->ebp + 8), duration, n, artBonus);
        #endif
    }
   
    return EXEC_DEFAULT;
}

int __stdcall removeElemental(LoHook* h, HookContext* c)
{
    // int currentRound = *(int*)o_BattleMgr->Offset(0x132A0) - 30000;
    _BattleStack_* currentStack = *(_BattleStack_**)(c->ebp - 4);
   
    if ( elemSplDuration[currentStack->side][currentStack->index_on_side] )
    {
        if ( !--elemSplDuration[currentStack->side][currentStack->index_on_side] ) currentStack->Die(TRUE);
    }

    return EXEC_DEFAULT;
}

int __stdcall splElemental(LoHook* h, HookContext* c)
{
    _BattleStack_* currentStack = (_BattleStack_*)c->eax;

    if ( currentStack && getActionId() == 1 )
    {
        int n = 6;
        _Hero_* hero = (_Hero_*)o_BattleMgr->hero[o_BattleMgr->current_side];
        int artBonus = getArtBonus(hero);
        int duration = 1 + (2 * hero->power + hero->knowledge) / n + artBonus;
        elemSplDuration[currentStack->side][currentStack->index_on_side] = duration;
       
        #ifdef DEBUG
        showDebugInfo(h->GetAddress(), hero, *(int*)(c->ebp + 8), duration, n, artBonus);
        #endif
    }

    return EXEC_DEFAULT;
}

int __stdcall clearElemSpellDuration(LoHook* h, HookContext* c)
{
    memset(&elemSplDuration, 0, sizeof(elemSplDuration));

    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.FfuzzyLogikPlugin");
           
            for (int i = 0; i < 3; ++i) _PI->WriteLoHook(hookAddr[i], splObsctacle);
            _PI->WriteLoHook(0x44467E, splCommon);
            _PI->WriteLoHook(0x5A7605, splElemental);
            _PI->WriteLoHook(0x475A3D, removeElemental);
            _PI->WriteLoHook(0x462C7D, clearElemSpellDuration);
        }
    }

    return TRUE;
}

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

offlineBen80
Мастер
Мастер
 
Сообщения: 386
Зарегистрирован: 18 июн 2017, 06:49
Поблагодарили: 50 раз.

Re: Пользовательские плагины для HD мода

Сообщение Ben80 » 02 окт 2017, 21:18

Автор: Ben80

Название: NewLearningSkill

Описание: Теперь герой с данным навыком с увеличением количества опыта увеличивает свой уровневый отрыв от героя без данного навыка.
Суть нововведения в том, что количество дополнительного опыта рассчитывается исходя из текущего уровня героя (за каждый набранный уровень добавляется 5/10/15%)

 Код
Код: Выделить всё
    #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 = *(_word_*)(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.15);
      

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



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

offlineBen80
Мастер
Мастер
 
Сообщения: 386
Зарегистрирован: 18 июн 2017, 06:49
Поблагодарили: 50 раз.

Re: Пользовательские плагины для HD мода

Сообщение Ben80 » 03 окт 2017, 19:03

Авторы: AlexSpl, Ben80

Название: NewTownPortal

Описание: Теперь на любом уровне магии Земли можно выбирать город. Существенно увеличились расходы MP - для основного уровня 1200 MP, для продвинутого 1000 MP, для эксперта 800 MP.
AI в курсе введенных изменений, применяет Городской портал для перемещения в нужный город, даже не имея навыка Магия Земли.
Патч HD-мода, выводящий сообщение о подтверждении намерений, для базового уровня магии Земли, обойден и не будет задействован.

Добавил AI value - 40/50/60, сделал описания.
NewTownPortal_Rus.zip
(3.79 КБ) Скачиваний: 0


 Код
Код: Выделить всё

#include "..\..\include\homm3.h"

// объекты patcher_x86.
Patcher* _P;
PatcherInstance* _PI;

int __stdcall setSpells(LoHook* h, HookContext* c)
{
   o_Spell[9].ai_value[0] = 50;
   o_Spell[9].ai_value[1] = 50;
   o_Spell[9].ai_value[2] = 60;
   o_Spell[9].ai_value[3] = 70;

   return EXEC_DEFAULT;
}

int __stdcall tpCostForHuman(LoHook* h, HookContext* c)
{
   *(int*)(c->ebp - 0x40) = 1200;
   *(int*)(c->ebp - 0x3C) = 1200;
   *(int*)(c->ebp - 0x38) = 1000;
   *(int*)(c->ebp - 0x34) = 800;
   
   return EXEC_DEFAULT;
}


int __stdcall skipTownPortalConfirm(LoHook* h, HookContext* c)
{
   if ( c->eax == -1 ) {
      c->ecx = *(unsigned char*)(c->edi + 5); // Выполняем затёртую jmp-патчем команду
      c->return_address = 0x41D990; // Обходим jmp-патч
      return NO_EXEC_DEFAULT;
   }
   
   c->return_address = 0x41D939;
   return NO_EXEC_DEFAULT;
}



int __stdcall mpointsEarth_1(LoHook* h, HookContext* c) {
   int level = c->eax;
   int mpoints[] = {1200, 1200, 1000, 800};
   c->eax = mpoints[level];
   
   c->return_address = 0x56B5AA;
   return NO_EXEC_DEFAULT;
}

int __stdcall mpointsEarth_2(LoHook* h, HookContext* c) {
   int level = c->eax;
   int mpoints[] = {1200, 1200, 1000, 800};
   c->eax = mpoints[level];
   c->ecx = *(int*)(c->esi + 0x4D);
   
   c->return_address = 0x430532;
   return NO_EXEC_DEFAULT;
}

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

            _P = GetPatcher();
            _PI = _P->CreateInstance("HD.Plugin.TownPortal");
           
            _PI->WriteLoHook(0x41D538, tpCostForHuman); // меняем расходы MP c 300/300/200 на 1200/1000/800
            _PI->WriteHexPatch(0x41D6D1, "90 90 90 90 90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли в главной функции заклинания
            _PI->WriteLoHook(0x56B59B, mpointsEarth_1); // расходы MP во вспомогат. функции 1
            _PI->WriteHexPatch(0x56B3B4, "90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли во вспомогат. функции 1
            _PI->WriteLoHook(0x430520, mpointsEarth_2); // расходы MP во вспомогат. функции 2
            _PI->WriteLoHook(0x41D934, skipTownPortalConfirm); // обходим jmp патч HD мода (версии 3.809 и выше)
            // Для Новой игры
            _PI->WriteLoHook(0x4BFB30, setSpells);
            // Для Загрузить игру
            _PI->WriteLoHook(0x4BEFF0, setSpells);
        }
        break;

        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}



NewTownPortal.zip
(3.56 КБ) Скачиваний: 8
Последний раз редактировалось Ben80 13 окт 2017, 16:46, всего редактировалось 4 раз(а).
Вернуться к началу

offlineBen80
Мастер
Мастер
 
Сообщения: 386
Зарегистрирован: 18 июн 2017, 06:49
Поблагодарили: 50 раз.

Re: Пользовательские плагины для HD мода

Сообщение Ben80 » 03 окт 2017, 19:12

Авторы: Ben80

Название: NewQuicksandMines

Описание: Теперь количество Зыбучих песков и Мин (в результате заклинания во время боя) - не 4/6/8, а 6/8/10,
в зависимости от уровня соответствующей Магии.

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

Patcher* _P;
PatcherInstance* _PI;


int __stdcall quicksandSpell(LoHook* h, HookContext* c)
{
   
   int peski[] = {6, 6, 8, 10};
   c->edi = peski[c->esi];
   
   return EXEC_DEFAULT;
}

int __stdcall minesSpell(LoHook* h, HookContext* c)
{
   
   int miny[] = {6, 6, 8, 10};
   c->edx = miny[c->esi];
   
   return EXEC_DEFAULT;
}


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

_P = GetPatcher();
_PI = _P->CreateInstance("HD.Plugin.QuicksandMines");

_PI->WriteLoHook(0x5A066B, quicksandSpell);
_PI->WriteLoHook(0x5A0852, minesSpell);

}
break;

case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}



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

offlineBen80
Мастер
Мастер
 
Сообщения: 386
Зарегистрирован: 18 июн 2017, 06:49
Поблагодарили: 50 раз.

Re: Пользовательские плагины для HD мода

Сообщение Ben80 » 03 окт 2017, 19:17

Авторы: AlexSpl, Ben80

Название: NewManaVortex

Описание: Теперь Водоворот маны восполняет запас маны и добавляет случайное количество (от нуля до полного запаса маны), кроме того, Водоворот маны теперь можно построить только после Гильдии магов 2 уровня.

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

Patcher* _P;
PatcherInstance* _PI;

static _bool_ plugin_On = 0;

int BuildDepends_Dungeon[] =
{
7, -1,
8, 7, -1,
9, 8, -1,
22, -1,
23, -1,
5, -1,
16, -1,
14, -1,
15, 14, -1,
17, 14, -1,
0, -1,
1, 0, -1,
2, 1, -1,
21, 1, -1,
3, 2, -1,
4, 3, -1,
11, 5, -1,
12, 11, 16, 14, 0, -1,
13, 12, 9, -1,
30, 7, -1,
18, 30, -1,
37, 30, -1,
19, 37, -1,
32, 30, -1,
39, 32, -1,
31, 30, -1,
38, 31, -1,
33, 32, 31, -1,
40, 33, -1,
34, 33, -1,
41, 34, -1,
35, 33, -1,
42, 35, -1,
36, 34, 35, 1, -1,
2, -1,
26, -1,
-100
};


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} ед.",
    sprintf(Text, "{%s}, близ вихря маны ваше тело наполняется новой силой, " \
        "количество маны увеличилось.",

        hero->name, c->ebx - hero->spell_points, c->ebx);
    b_MsgBox(Text, MBX_OK);
   
    c->return_address = 0x5BDD92;
    return NO_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.NewManaVortex");
               
            _PI->WriteLoHook(0x5BDD4E, manaVortex);
            _PI->WriteLoHook(0x5BDD66, manaVortexDlg);

            *(int*)0x4EBA5C = (int)BuildDepends_Dungeon;

        }
    }
           
    return TRUE;
}



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

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

Re: Пользовательские плагины для HD мода

Сообщение AlexSpl » 04 окт 2017, 15:23

Автор: AlexSpl

Название: NewSecSkillDesc

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

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

Patcher* _P;
PatcherInstance* _PI;

static _bool_ plugin_On = 0;

char* NewSecSkillDesc[][4] =
{
    // 0: Pathfinding
    {
        "Pathfinding",
        "{Basic Pathfinding}\n\nYour description here",
        "{Advanced Pathfinding}\n\nYour description here",
        "{Expert Pathfinding}\n\nYour description here"
    },
   
    // 1: Archery
    {
        "Archery",
        "{Basic Archery}\n\nYour description here",
        "{Advanced Archery}\n\nYour description here",
        "{Expert Archery}\n\nYour description here"
    },

    // 2: Logistics
    {
        "Logistics",
        "{Basic Logistics}\n\nYour description here",
        "{Advanced Logistics}\n\nYour description here",
        "{Expert Logistics}\n\nYour description here"
    },
   
    // 3: Scouting
    {
        "Scouting",
        "{Basic Scouting}\n\nYour description here",
        "{Advanced Scouting}\n\nYour description here",
        "{Expert Scouting}\n\nYour description here"
    },
   
    // 4: Diplomacy
    {
        "Diplomacy",
        "{Basic Diplomacy}\n\nYour description here",
        "{Advanced Diplomacy}\n\nYour description here",
        "{Expert Diplomacy}\n\nYour description here"
    },
   
    // 5: Navigation
    {
        "Navigation",
        "{Basic Navigation}\n\nYour description here",
        "{Advanced Navigation}\n\nYour description here",
        "{Expert Navigation}\n\nYour description here"
    },
   
    // 6: Leadership
    {
        "Leadership",
        "{Basic Leadership}\n\nYour description here",
        "{Advanced Leadership}\n\nYour description here",
        "{Expert Leadership}\n\nYour description here"
    },
   
    // 7: Wisdom
    {
        "Wisdom",
        "{Basic Wisdom}\n\nYour description here",
        "{Advanced Wisdom}\n\nYour description here",
        "{Expert Wisdom}\n\nYour description here"
    },
   
    // 8: Mysticism
    {
        "Mysticism",
        "{Basic Mysticism}\n\nYour description here",
        "{Advanced Mysticism}\n\nYour description here",
        "{Expert Mysticism}\n\nYour description here"
    },
   
    // 9: Luck
    {
        "Luck",
        "{Basic Luck}\n\nYour description here",
        "{Advanced Luck}\n\nYour description here",
        "{Expert Luck}\n\nYour description here"
    },
   
    // 10: Ballistics
    {
        "Ballistics",
        "{Basic Ballistics}\n\nYour description here",
        "{Advanced Ballistics}\n\nYour description here",
        "{Expert Ballistics}\n\nYour description here"
    },
   
    // 11: Eagle Eye
    {
        "Eagle Eye",
        "{Basic Eagle Eye}\n\nYour description here",
        "{Advanced Eagle Eye}\n\nYour description here",
        "{Expert Eagle Eye}\n\nYour description here"
    },
   
    // 12: Necromancy
    {
        "Necromancy",
        "{Basic Necromancy}\n\nYour description here",
        "{Advanced Necromancy}\n\nYour description here",
        "{Expert Necromancy}\n\nYour description here"
    },
   
    // 13: Estates
    {
        "Estates",
        "{Basic Estates}\n\nYour description here",
        "{Advanced Estates}\n\nYour description here",
        "{Expert Estates}\n\nYour description here"
    },
   
    // 14: Fire Magic
    {
        "Fire Magic",
        "{Basic Fire Magic}\n\nYour description here",
        "{Advanced Fire Magic}\n\nYour description here",
        "{Expert Fire Magic}\n\nYour description here"
    },
   
    // 15: Air Magic
    {
        "Air Magic",
        "{Basic Air Magic}\n\nYour description here",
        "{Advanced Air Magic}\n\nYour description here",
        "{Expert Air Magic}\n\nYour description here"
    },
   
    // 16: Water Magic
    {
        "Water Magic",
        "{Basic Water Magic}\n\nYour description here",
        "{Advanced Water Magic}\n\nYour description here",
        "{Expert Water Magic}\n\nYour description here"
    },
   
    // 17: Earth Magic
    {
        "Earth Magic",
        "{Basic Earth Magic}\n\nYour description here",
        "{Advanced Earth Magic}\n\nYour description here",
        "{Expert Earth Magic}\n\nYour description here"
    },
   
    // 18: Scholar
    {
        "Scholar",
        "{Basic Scholar}\n\nYour description here",
        "{Advanced Scholar}\n\nYour description here",
        "{Expert Scholar}\n\nYour description here"
    },
   
    // 19: Tactics
    {
        "Tactics",
        "{Basic Tactics}\n\nYour description here",
        "{Advanced Tactics}\n\nYour description here",
        "{Expert Tactics}\n\nYour description here"
    },
   
    // 20: Artillery
    {
        "Artillery",
        "{Basic Artillery}\n\nYour description here",
        "{Advanced Artillery}\n\nYour description here",
        "{Expert Artillery}\n\nYour description here"
    },
   
    // 21: Learning
    {
        "Learning",
        "{Basic Learning}\n\nYour description here",
        "{Advanced Learning}\n\nYour description here",
        "{Expert Learning}\n\nYour description here"
    },
   
    // 22: Offense
    {
        "Offense",
        "{Basic Offense}\n\nYour description here",
        "{Advanced Offense}\n\nYour description here",
        "{Expert Offense}\n\nYour description here"
    },
   
    // 23: Armorer
    {
        "Armorer",
        "{Basic Armorer}\n\nYour description here",
        "{Advanced Armorer}\n\nYour description here",
        "{Expert Armorer}\n\nYour description here"
    },
   
    // 24: Intelligence
    {
        "Intelligence",
        "{Basic Intelligence}\n\nYour description here",
        "{Advanced Intelligence}\n\nYour description here",
        "{Expert Intelligence}\n\nYour description here"
    },
   
    // 25: Sorcery
    {
        "Sorcery",
        "{Basic Sorcery}\n\nYour description here",
        "{Advanced Sorcery}\n\nYour description here",
        "{Expert Sorcery}\n\nYour description here"
    },

    // 26: Resistance
    {
        "Resistance",
        "{Basic Resistance}\n\nYour description here",
        "{Advanced Resistance}\n\nYour description here",
        "{Expert Resistance}\n\nYour description here"
    },

    // 27: First Aid
    {
        "First Aid",
        "{Basic First Aid}\n\nYour description here",
        "{Advanced First Aid}\n\nYour description here",
        "{Expert First Aid}\n\nYour description here"
    }
};

int __stdcall changeSecSkillDesc(LoHook* h, HookContext* c)
{
    /* for (int iSkill = 0; iSkill < 28; ++iSkill)
    {
        for (int iLevel = 0; iLevel < 4; ++iLevel)
        {
            // Меняем название и описание вторичного навыка с порядковым номером iSkill
            *(int*)(*(int*)0x67DCF0 + iSkill * 16 + iLevel * 4) = (int)NewSecSkillDesc[iSkill][iLevel];
        }
    } */

    // Если нужна замена всех названий и описаний сразу, то проще так:
    *(int*)0x67DCF0 = (int)NewSecSkillDesc;

    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.NewSecondarySkillDescriptions");

            _PI->WriteLoHook(0x4E6D77, changeSecSkillDesc);
        }
    }

    return TRUE;
}

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

offlineSerp
 
Сообщения: 6
Зарегистрирован: 05 окт 2017, 11:21
Поблагодарили: 11 раз.

Re: Пользовательские плагины для HD мода

Сообщение Serp » 05 окт 2017, 11:35

Authors:
RoseKavalier, Serp

Titel:
WitchHutChoiceHotA

Description:
When entering a Witchhut you can click "yes" or "no", whether you want to learn the secondary skill.
Works also in Multiplayer. Every player should have this plugin installed/uninstalled, to not mess up the game.
Although the name contains "HotA", it also works without.

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

Patcher* _P; // required for every plugin
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

int __stdcall Witch_Hut_Choice(LoHook* h, HookContext* c)
{
       int choice = *(int*)(*(int*)0x6992D0 + 0x38) - 0x7805; // grab user's decision
       if (choice != 0) { // clicked "refuse"
               c->return_address = 0x4A7E8F; // skip over "give secondary skill procedure"
               return NO_EXEC_DEFAULT; // do not execute original code
       }
       return EXEC_DEFAULT; // execute original code because user did not refuse secondary skill
}


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.WitchHutChoiceHotA"); // required for every plugin
            _PI->WriteHexPatch(0x4A7E64, "02"); // add Cancel button to textbox
            _PI->WriteLoHook(0x4A7E85, Witch_Hut_Choice); // adds the Witch_Hut_Choice function to the code @ 0x4A7E85
        }
    }
    return TRUE;
}
Вложения
WitchHutChoiceHotA.zip
(4.36 КБ) Скачиваний: 97
Последний раз редактировалось Serp 05 окт 2017, 11:43, всего редактировалось 1 раз.
Вернуться к началу

offlineSerp
 
Сообщения: 6
Зарегистрирован: 05 окт 2017, 11:21
Поблагодарили: 11 раз.

Re: Пользовательские плагины для HD мода

Сообщение Serp » 05 окт 2017, 11:42

Authors:
RoseKavalier, Serp

Titel:
ScholarChoiceHotA

Description:
When entering a Scholar who wants to teach you a secondary skill, you can click "yes" or "no", whether you want to learn the secondary skill. If you hit no, you won't learn anything, the Scholar will still disappear.
Works also in Multiplayer. Every player should have this plugin installed/uninstalled, to not mess up the game.
I'm not sure if it works without HotA, not tested.

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

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

#define o_ADVEVENT_TXT (*(_TXT_**)0x696A68)
#define Show_SSKill_MSG_YES_NO(frame) \
CALL_12(void, __fastcall, 0x4F6C00,o_ADVEVENT_TXT->GetString(115), MBX_OKCANCEL, -1, -1, 0x14, frame, -1, 0, -1, 0, -1, 0);

int __stdcall wandering_scholar_sskill_choice(LoHook *h, HookContext *c)
{
    int skill_id = c->eax; // grab skill to learn
    _Hero_ *hero = (_Hero_*)c->ebx; // grab current hero structure
    int skill_level = hero->second_skill[skill_id]; // current skill level
    if (*(BYTE*)(c->ebp + 0x14) == 0 ) // || o_IsMultiPlayerGame // disable for AI
        return EXEC_DEFAULT;
   
    if (hero->second_skill_count == 8 || skill_level==3) // if hero can not learn skill
    {
        c->return_address = 0x4A4B3F; // change return address to learn primary skill
        return NO_EXEC_DEFAULT; // do not execute original code that was overwritten
    }
   
    Show_SSKill_MSG_YES_NO(skill_id * 3 + skill_level + 2 + 1); // is the ID of the frame to use from .DEF file.
    // The extra + 1 is because the skill is not yet increased!
    // equivalent to ... MOVSX ECX,BYTE PTR DS:[EBX+EDI+0C9] ... LEA EDX, [EDI*2 + EDI] ... LEA EAX, [EDX+ECX+2]
   
    if (o_WndMgr->result_dlg_item_id == DIID_OK) // did user click ok?
        hero->LearnSecondarySkill(skill_id,1); // then leanr the skill
   
    c->return_address = 0x4A4B86; // go to exit procedure
    return NO_EXEC_DEFAULT; // do not execute original code that was overwritten
}

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.ScholarChoice_HotA");
           
            _PI-> WriteLoHook (0x4A4AE4, wandering_scholar_sskill_choice);
        }
    }
    return TRUE;
}

 homm3.h
In homm3.h you have to add right under the line with "int AddBackpackArtifact..." this line (if it is not already there):
int LearnSecondarySkill(int skill_id, int skill_increase) { return CALL_3(int, __thiscall, 0x4E2540, this, skill_id, skill_increase);}
Вложения
ScholarChoiceHotA.zip
(4.84 КБ) Скачиваний: 24
Вернуться к началу

След.

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

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

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

cron