Объявления

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

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

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

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

Сообщение AlexSpl » 02 ноя 2022, 19:09

Автор: AlexSpl

Название: FairCancelSpells

Описание: Заклинания Dispel и Cure снимают только последнее наложенное заклинание/эффект. В случае, если последнее заклинание/эффект невозможно снять (например, последний эффект - Poison для Dispel или какой-нибудь баф для Cure), снимается ближайшее заклинание/эффект, которое можно снять.

 Код
Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0

#pragma warning(disable : 4005)
#pragma warning(disable : 4010)

#include "stdafx.h"
#include <vector>
#include "..\..\HotA\homm3.h"

Patcher* _P;
PatcherInstance* _PI;

#pragma pack(push, 4)
class stdDequeIterator {
public:
   int* first;
   int* last;
   int* node;
   int** map;
};

class stdDeque {
public:
   char allocator;
   stdDequeIterator itFirst;
   stdDequeIterator itLast;
   int** map;
   int mapSize;
   int size;
};

struct SLimitData
{
   int MinX;
   int MinY;
   int MaxX;
   int MaxY;
};

struct TObstacleInfo
{
   unsigned long backgroundMask;
   unsigned char height;
   unsigned char width;
   unsigned char numSquares;
   unsigned char underlay;
   char sOffsets[8];
   const char* FileName;
};

// Actual types are commented, as we don't need them in this plugin
struct TObstacle
{
   // CSprite* sprite;
   int* sprite;
   TObstacleInfo* info;
   unsigned char grid_index;
   char owner;
   bool is_visible;
   int damage;
   int duration;
   // TSpellEffectID dispel_effect;
   int dispel_effect;
};

class hexcell {
public:
   short refX;
   short refY;
   short hexULX;
   short hexULY;
   short hexBRX;
   short hexBRY;
   short fullHexBRY;
   unsigned int attributes;
   int obstacleIndex;
   char armyGrp;
   char armyIndex;
   char partOfDouble;
   int iBodiesInHex;
   char deadArmyGrp[14];
   char deadArmyIndex[14];
   char deadPartOfDouble[14];
   bool bValidMove;
   unsigned char front_move;
   unsigned char mouse_shaded;
   char background_offset;
   SLimitData obstacleLimitData;
   SLimitData cloudLimitData;
};
#pragma pack(pop)

class army : public _BattleStack_ {
public:
   inline void CancelIndividualSpell(int SpellID) {
      CALL_2(void, __thiscall, 0x444230, this, SpellID);
   }
};

void debugStrWin(const char* format, ...)
{
   va_list args;
   va_start(args, format);

   vsprintf(o_TextBuffer, format, args);
   ShowMessage(o_TextBuffer);
   
   va_end(args);
}

#define SPL_DISPEL 35
#define SPL_STONE_GAZE 70
#define SPL_DISEASE 73
#define SPL_AGE 75
#define SPL_DISPEL_HELPFUL_SPELLS 78

int __stdcall fixCure(LoHook* h, HookContext* c)
{
   army* Army = (army*)c->esi;
   Army->lost_hp = c->eax;

   if (Army->active_spells_count)
   {
      stdDeque* spellDeque = (stdDeque*)(c->esi + 0x420);
     
      for (int i = spellDeque->size; i > 0; --i)
      {
         // You can do so because the size of spellDeque's chunk is 4096 bytes,
         // and this is more than enough for all possible spells
         int spell = spellDeque->itFirst.node[i - 1];
         
         if (spell == SPL_CURSE || spell == SPL_WEAKNESS || spell == SPL_SORROW || spell == SPL_MISFORTUNE ||
            spell == SPL_SLOW || spell == SPL_BERSERK || spell == SPL_HYPNOTIZE || spell == SPL_FORGETFULNESS ||
            spell == SPL_BLIND || spell == SPL_STONE_GAZE || spell == SPL_POISON || spell == SPL_DISEASE ||
            spell == SPL_PARALYZE || spell == SPL_AGE)
         {
            Army->CancelIndividualSpell(spell);
            break;
         }
      }
   }
   
   c->return_address = 0x4462FD;
   return NO_EXEC_DEFAULT;
}

int __stdcall spellCastWorkChance(LoHook* h, HookContext* c)
{
   army* Army = *(army**)(c->ebp + 0x10);
   int spell = *(int*)(c->ebp + 8);

   if (spell == SPL_DISPEL && Army && Army->active_spells_count)
   {
      stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);

      for (int i = spellDeque->size; i > 0; --i)
      {
         int spell = spellDeque->itFirst.node[i - 1];

         if (spell != SPL_POISON)
            return EXEC_DEFAULT;
      }

      std::vector<TObstacle>* Obstacles = o_BattleMgr->PField<std::vector<TObstacle>>(0x13D58);

      for (std::vector<TObstacle>::iterator it = Obstacles->begin(); it != Obstacles->end(); ++it)
         if (o_BattleMgr->PField<hexcell>(0x1C4)[it->grid_index].attributes & 0x3C)
            return EXEC_DEFAULT;

      c->return_address = 0x5A849A;
      return NO_EXEC_DEFAULT;
   }
     
   return EXEC_DEFAULT;   
}

int __stdcall fixDispel(LoHook* h, HookContext* c)
{
   army* Army = (army*)c->edi;

   if (Army->active_spells_count)
   {
      stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);

      for (int i = spellDeque->size; i > 0; --i)
      {
         int spell = spellDeque->itFirst.node[i - 1];

         if (spell != SPL_POISON)
         {
            Army->CancelIndividualSpell(spell);
            break;
         }
      }
   }
         
   c->return_address = 0x5A190A;
   return NO_EXEC_DEFAULT;
}

int __stdcall fixMassDispel(LoHook* h, HookContext* c)
{
   army* Army = (army*)c->esi;

   if (Army->active_spells_count)
   {
      stdDeque* spellDeque = (stdDeque*)(c->esi + 0x420);

      for (int i = spellDeque->size; i > 0; --i)
      {
         int spell = spellDeque->itFirst.node[i - 1];

         if (spell != SPL_POISON)
         {
            Army->CancelIndividualSpell(spell);
            break;
         }
      }
   }
       
   c->return_address = 0x5A1998;
   return NO_EXEC_DEFAULT;
}

int __stdcall fixDispelHelpful(LoHook* h, HookContext* c)
{
   army* Army = (army*)c->edi;

   if (Army->active_spells_count)
   {
      stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);

      for (int i = spellDeque->size; i > 0; --i)
      {
         int spell = spellDeque->itFirst.node[i - 1];

         if (o_Spell[spell].type > 0)
         {
            Army->CancelIndividualSpell(spell);
            break;
         }
      }
   }
       
   c->return_address = 0x5A1AE2;
   return NO_EXEC_DEFAULT;
}

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((char*)"HD.Plugin.H3.FairCancelSpells");

         _PI->WriteLoHook(0x44627C, fixCure);
         _PI->WriteLoHook(0x5A18F7, fixDispel);
         _PI->WriteLoHook(0x5A1985, fixMassDispel);
         _PI->WriteLoHook(0x5A1A8E, fixDispelHelpful);
         _PI->WriteLoHook(0x5A8477, spellCastWorkChance);
         // TODO: fixCancelValue
      }
   }
   
   return TRUE;
}

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

offlinevovacyxov  
имя: Влaдимир
 
Сообщения: 9
Зарегистрирован: 08 ноя 2022, 12:30
Пол: Мужчина
Поблагодарили: 3 раз.

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

Сообщение vovacyxov » 08 ноя 2022, 12:44

Добрый день уважаемые, не могу нигде найти плагин для удаления взятого вторичного навыка. Заранее спасибо! Сам к сожалению плагины делать неумею. Буду благодарен если поможете.
Огромное Спасибо AlexSpl

скачать плагин удаление вторичных навыков можно по ссылке

viewtopic.php?f=56&t=518&start=3810
Вернуться к началу

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

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

Сообщение AlexSpl » 11 ноя 2022, 16:16

Авторы: AlexSpl, vovacyxov

Название: ForgetSecSkill

Описание: Вторичные навыки можно удалять прямо из окна героя. Левый клик на навыке и нажатие на кнопку Cancel приведёт к отмене этого навыка/ступени навыка.

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

#pragma warning(disable : 4005)
#pragma warning(disable : 4010)

#include "stdafx.h"
#include "..\..\headers\HoMM3API.h"

Patcher* _P;
PatcherInstance* _PI;

void __stdcall forgetSecSkill(HiHook* h, char const* cText, int iMBType, int x, int y,
                              int iResType1, int iResExtra1, int iResType2, int iResExtra2,
                              int iSpecial, int iTimeout, int iResType3, int iResExtra3)
{
   if (iResExtra1 && iMBType == 1)
      iMBType = 2;

   CALL_12(void, __fastcall, h->GetDefaultFunc(), cText, iMBType, x, y,
      iResType1, iResExtra1, iResType2, iResExtra2, iSpecial, iTimeout, iResType3, iResExtra3);

   if (iResExtra1 && pWindowManager->dialogReturn == 0x7806)
   {
      pWindowManager->dialogReturn = 0;

      hero* gpHero = *(hero**)0x698B70;

      if (gpHero)
      {
         int skill = (iResExtra1 - 3) / 3;
         TSkillMastery mastery = (TSkillMastery)((iResExtra1 - 3) % 3 + 1);
         
         --gpHero->SSLevel[skill];

         if (mastery == eMasteryBasic)
         {
            --gpHero->numSSs;
           
            for (int i = 0; i < 28; ++i)
               if (gpHero->SSOrder[i] > gpHero->SSOrder[skill])
                  --gpHero->SSOrder[i];

            gpHero->SSOrder[skill] = 0;
         }

         heroWindow* heroWnd = *(heroWindow**)0x698AC8;

         CALL_1(void, __thiscall, 0x4E1CC0, heroWnd);
         CALL_4(void, __thiscall, *(int*)(*(int*)heroWnd + 0x14), heroWnd, true, -65535, 65535);
      }
   }
}

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((char*)"HD.Plugin.H3.ForgetSecSkill");

         _PI->WriteHiHook(0x4DE843, CALL_, EXTENDED_, FASTCALL_, forgetSecSkill);
      }
   }
   
   return TRUE;
}

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

offlinejackslater777  
имя: Иван
 
Сообщения: 1
Зарегистрирован: 22 дек 2022, 12:26
Пол: Мужчина
Поблагодарили: 0 раз.

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

Сообщение jackslater777 » 23 дек 2022, 10:28

Добрый день. Ни у кого не осталось сурс-кода на плагин RandomObjectsTuning от Ben80? Буду крайне признателен за помощь.
Вернуться к началу

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

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

Сообщение AlexSpl » 13 июн 2023, 15:24

Автор: AlexSpl

Название: LimitMaxHeroes

Описание: Ограничивает максимальное количество героев у игроков на карте приключений. Количество героев задаётся в конфигурационном файле LimitMaxHeroes.ini, там же можно прописать сообщение для объекта "Тюрьма".

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

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

Patcher* _P;
PatcherInstance* _PI;

char iniPath[MAX_PATH];
char strBuffer[201] = "";

#define o_ADVEVENT (*(_TXTEX_**)0x696A68)

struct _TXTEX_ : public _TXT_ {
  inline void SetString(int index, char* str) { *(char**)(*(int*)((int)this + 32) + index * 4) = str; }
};

int __stdcall afterInit(LoHook* h, HookContext* c)
{
   GetPrivateProfileStringA("Messages", "Prison", o_ADVEVENT->GetString(103), strBuffer, 201, iniPath);
   o_ADVEVENT->SetString(103, strBuffer);
 
   return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   static _bool_ plugin_On = 0;
   if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
   {
       if ( !plugin_On )
       {
          plugin_On = 1;
          _P = GetPatcher();
          _PI = _P->CreateInstance("HD.Plugin.H3.LimitMaxHeroes");
         
          GetCurrentDirectoryA(sizeof(iniPath), iniPath);
          strcat(iniPath, "\\LimitMaxHeroes.ini");
         
          char maxHeroes = GetPrivateProfileIntA("Limits", "MaxHeroes", 8, iniPath);
          _PI->WriteByte(0x431391, maxHeroes);
          _PI->WriteByte(0x4A3BE1, maxHeroes);
          _PI->WriteByte(0x52A891, maxHeroes);
          _PI->WriteByte(0x5D566F, maxHeroes);
          _PI->WriteByte(0x5D7E02, maxHeroes);
          _PI->WriteByte(0x5D7E0B, maxHeroes);
          _PI->WriteByte(0x5D860A, maxHeroes);
          _PI->WriteLoHook(0x4EE1C1, afterInit);
       }
   }

  return TRUE;
}

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

Пред.

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

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

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