Heroes of Might and Magic Community
visiting hero! Register | Today's Posts | Games | Search! | FAQ/Rules | AvatarList | MemberList | Profile


Age of Heroes Headlines:  
5 Oct 2016: Heroes VII development comes to an end.. - read more
6 Aug 2016: Troubled Heroes VII Expansion Release - read more
26 Apr 2016: Heroes VII XPack - Trial by Fire - Coming out in June! - read more
17 Apr 2016: Global Alternative Creatures MOD for H7 after 1.8 Patch! - read more
7 Mar 2016: Romero launches a Piano Sonata Album Kickstarter! - read more
19 Feb 2016: Heroes 5.5 RC6, Heroes VII patch 1.7 are out! - read more
13 Jan 2016: Horn of the Abyss 1.4 Available for Download! - read more
17 Dec 2015: Heroes 5.5 update, 1.6 out for H7 - read more
23 Nov 2015: H7 1.4 & 1.5 patches Released - read more
31 Oct 2015: First H7 patches are out, End of DoC development - read more
5 Oct 2016: Heroes VII development comes to an end.. - read more
[X] Remove Ads
LOGIN:     Username:     Password:         [ Register ]
HOMM1: info forum | HOMM2: info forum | HOMM3: info mods forum | HOMM4: info CTG forum | HOMM5: info mods forum | MMH6: wiki forum | MMH7: wiki forum
Heroes Community > Heroes 3.5 - WoG and Beyond > Thread: About HDMod dll plugin (started by sandruse in November 2025)
About HDMod dll plugin
sandruse
sandruse

Tavern Dweller
posted November 03, 2025 03:51 PM
Edited by sandruse at 16:10, 03 Nov 2025.

About HDMod dll plugin FOR HELP

Hello there! I try to create a small HDMod dll plugin. However, the game will crash when the logic run into the if area. Any Friend could help me? Thanks!

#include <stdint.h>
#include "patcher_x86.hpp"

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

int __stdcall SS(LoHook* h, HookContext* c)
{
   int SSName = *(int*)(c->ebp + 0x08);  // SS ID
   unsigned char SSLevel = *(unsigned char*)(c->esi + c->ecx + 0x0C9);  // Curent SS Level
   if (SSName == 11 && SSLevel == 1)// SKILL_EAGLE_EYE
   {
       // ADD Primary Skill
       *(uint8_t*)(c->ecx + 0x476) = 15;
   }
   __asm // The asm LoHook ocupy
   {
     add     al, byte ptr [ebp+0Ch]
     mov     [edx], al
   }
   return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
 switch ( ul_reason_for_call )
 {
    case DLL_PROCESS_ATTACH:
       
       if ( !plugin_On )
       {
          plugin_On = 1;
          _P = GetPatcher();
          _PI = _P->CreateInstance("HD.Plugin.Rules_1.7");
          _PI->WriteLoHook(0x4E255D, SS);
       }

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

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 04, 2025 03:02 AM

This code seems to be correct with the exception of this:

__asm // The asm LoHook ocupy
{
    add     al, byte ptr [ebp+0Ch]
    mov     [edx], al
}


You don't need it as you already wrote EXEC_DEFAULT, which means the patcher will execute those instructions after it's done with your hook's code. I don't know exactly, but supposedly registers in __asm sections are treated as they are (I mean, for example, that c->edx may actually be stored in another register within a hook and even in the memory, while edx in the __asm section is the actual edx register which may store anything at the moment).

 View Profile
sandruse
sandruse

Tavern Dweller
posted November 04, 2025 11:46 AM

AlexSpl said:
This code seems to be correct with the exception of this:

__asm // The asm LoHook ocupy
{
    add     al, byte ptr [ebp+0Ch]
    mov     [edx], al
}


You don't need it as you already wrote EXEC_DEFAULT, which means the patcher will execute those instructions after it's done with your hook's code. I don't know exactly, but supposedly registers in __asm sections are treated as they are (I mean, for example, that c->edx may actually be stored in another register within a hook and even in the memory, while edx in the __asm section is the actual edx register which may store anything at the moment).


Thank you for your answer, AlesSpl! The place you mentioned is also what I suspect, but due to my limited computer programming skills, I don't know how to handle it either. However, I re-edited the previous code, rewrote the logic of the original function, and then embedded my own logic. It seems that there are no problems after testing.

This is a simple Mod to slightly balance the EagleEye:

Hero will get +1 Power when get EagleEye on second and third level. And the hero who have the special EagleEye will get and extra +1 on the third level.

 View Profile
sandruse
sandruse

Tavern Dweller
posted November 04, 2025 11:48 AM

#include "patcher_x86.hpp"

// HDMod dll hack: The Eagle Eye update will give extra Magic Power

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

int __stdcall MyGiveSS(LoHook* h, HookContext* c) {
   // get 'hero' Pointer&#65288;ecx&#65289;
   void* hero = (void*)c->ecx;

   // get the 2 formal parameters of the hooked function
   int iWhichSS = *(int*)(c->ebp + 8);
   int iNumLevelsToGive = *(int*)(c->ebp + 0x0C);

   // get the val and pointer of hero's second skill level
   unsigned char* skillLevel = (unsigned char*)hero + 0xC9 + iWhichSS;
   int currentLevel = *skillLevel;

   if (currentLevel > 0) {
       *skillLevel += iNumLevelsToGive;
   } else {
       int* skillCount = (int*)((char*)hero + 0x101);
       if (*skillCount < 8) {
           *skillLevel = iNumLevelsToGive;
           *(unsigned char*)((char*)hero + 0xE5 + iWhichSS) = (unsigned char)(*skillCount + 1);
           (*skillCount)++;
       }
   }

   if (*skillLevel > 3) {
       *skillLevel = 3;
   }

   int result = *skillLevel - currentLevel;
       
   // the hack content
   // if hero get level 2 eagle eye, power +1
   if (currentLevel <= 1 && *skillLevel >= 2 && iWhichSS == 11) {
     *(unsigned char*)((char*)hero + 0x476 + 2) += 1; // Hero's 3rd Primary Power: Magic Power
   }
   // if hero get level 3 eagle eye, power +1
   if (result >= 1 && *skillLevel == 3 && iWhichSS == 11) {
     // if hero's special is eagle eye then get an extra +1
     switch (*(int*)((char*)hero + 0x1A)) { // HeroID
       case 13: // Sanya
       case 28: // Malcom
       case 42: // Serena
       case 75: // Nimbus
       case 92: // Geon
       case 110: // Oris
       case 127: // Tiva
         *(unsigned char*)((char*)hero + 0x476 + 2) += 1;
     }
     *(unsigned char*)((char*)hero + 0x476 + 2) += 1;
   }
   
   c->eax = result;  // set the retrun val
   
   c->return_address = 0x4E259B; // set the return position
   
   return EXEC_DEFAULT;
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
 switch ( ul_reason_for_call )
 {
    case DLL_PROCESS_ATTACH:
       
       if ( !plugin_On )
       {
          plugin_On = 1;
          _P = GetPatcher();
          _PI = _P->CreateInstance("HD.Plugin.Test_2025-11-4");
          _PI->WriteLoHook(0x004E2548, MyGiveSS);
       }

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

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 04, 2025 07:05 PM

Great The next step would be to get rid of numerical offsets. For this you may use some APIs (the best one I can recommend at the moment is NH3API). With API you will no longer need to remember offsets or search for them in a database. You will be able to use field and methods of a class in your code in a readable form, like -

hero->SSLevel[HSS_EAGLE_EYE]

for this -

*(unsigned char*)(c->esi + c->ecx + 0x0C9);  // Curent SS Level


 View Profile
sandruse
sandruse

Tavern Dweller
posted November 05, 2025 11:37 AM

I've found that lib on github. And it helped me to get the correct hex offset. Since it only works on VC2017 or higher, I can't use it with my VC2010
Later may I have more spare time to make good use with it.
Thank you AlesSpl again! Your codes on handbookhmm inspire me a lot too.

 View Profile
Jump To: « Prev Thread . . . Next Thread »
Post New Poll   Post New Topic   Post New Reply

Page compiled in 0.0520 seconds