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: Heroes 3 Hacking Reference Guide (started by BTB in February 2020)
Heroes 3 Hacking Reference Guide This thread is 45 pages long: 1 2 3 4 5 ... 10 20 30 ... 41 42 43 44 45 · «PREV / NEXT»
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 02:33 PM

I think it's better to cap amount of joining monsters. Say, with Basic Diplomacy you can join 25% of monsters, but no more than their 1 basic growth. With Advanced Diplomacy, 50%/2 growths. With Expert Diplomacy, 75%/3 growths. Though 3 Archangels from one neutral group still look too many.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 03:22 PM

AlexSpl said:
I think it's better to cap amount of joining monsters. Say, with Basic Diplomacy you can join 25% of monsters, but no more than their 1 basic growth. With Advanced Diplomacy, 50%/2 growths. With Expert Diplomacy, 75%/3 growths. Though 3 Archangels from one neutral group still look too many.

So thats an idea, and I think there was a similar mechanics in homm2? The thing is, this feels like a buff to diplomacy, while I am trying to nerf it.

Another question, say i want the formula to be v16 + 0, lea ecx,[edx+ecx] becomes 8d 0c 0a, what do I put in the 4th byte? 00? 90?

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 04:23 PM

Yes, NOP (90h) is what you need as a padding. You can also use it to 'erase' whole instructions.

Just for fun

It's what Intel recommends to use when we need more than 1 NOP -

Table 4-12. Recommended Multi-Byte Sequence of NOP Instruction
Length Assembly Byte Sequence
2 bytes 66 NOP 66 90H
3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] 66 0F 1F 84 00 00 00 00 00H


 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 07:40 PM

Speaking of erasing whole instructions. Do you know the location of the code responsible for Wisdom (and School of magic skills?) being offered every 3/6 levels to might/magic heroes? Can it be isolated or is it a series of bits of code scattered around the larger function for level up skill offers? I would like to get rid of this rule completely so that Wisdom and School of magic skills are only offered "randomly" according to the probabilities specified for each hero class.

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 08:04 PM
Edited by AlexSpl at 20:09, 05 Mar 2026.

Yes, it's there -

TSecondarySkill __fastcall get_skill_award(
       hero *current_hero,
       TSkillMastery min_level,
       int max_level,
       TSecondarySkill excluded)
{
   hero *v4; // edi
   THeroClass hero_class; // eax
   int v6; // eax
   int v7; // esi
   int Level; // ecx
   __int32 v9; // eax
   TSecondarySkill v10; // eax
   TSecondarySkill result; // eax
   int v12; // edx
   const TSecondarySkill *v13; // esi
   TSecondarySkill v14; // eax
   char v15; // bl
   int v16; // ebx
   TSecondarySkill *v17; // esi
   char v18; // dl
   int v19; // esi
   int v20; // eax
   char v21; // bl
   int v22; // ecx
   int v23; // esi
   char v24; // dl
   int v25; // ecx
   THeroClassTraits *v26; // [esp+Ch] [ebp-10h]
   _BYTE *ss_disabled; // [esp+14h] [ebp-8h]
   TSkillMastery v29; // [esp+18h] [ebp-4h]

   v4 = current_hero;
   v29 = min_level;
   hero_class = current_hero->hero_class;
   v26 = (THeroClassTraits *)(akHeroClassTraits[0].m_townType + (hero_class << 6));
   ss_disabled = gpGame->ss_disabled;
   if ( gbInCampaign && gpGame->sCampaign.iCurrentCampaign == SOD_BIRTH_OF_A_BARBARIAN && current_hero->id == HERO_SOLMYR )
       ss_disabled = Campaign14SolmyrBannedSkills;
   if ( current_hero->numSSs >= 8 )
   {
       v29 = eMasteryBasic;
       min_level = eMasteryBasic;
   }
   if ( min_level >= max_level )
       return -1;
   if ( hero_class == eClassCleric
     || hero_class == eClassDruid
     || hero_class == eClassWizard
     || hero_class == eClassHeretic
     || hero_class == eClassNecromancer
     || hero_class == eClassWarlock
     || hero_class == eClassBattleMage
     || hero_class == eClassWitch )
   {
       v6 = 3;
       v7 = 3;
   }
   else
   {
       v6 = 6;
       v7 = 4;
   }
   Level = current_hero->Level;
   if ( v6 + v4->lastWisdom > Level || (v9 = v4->SSLevel[SKILL_WISDOM], v9 >= max_level) || v9 < min_level )
   {
       v10 = excluded;
   }
   else
   {
       v10 = excluded;
       if ( excluded != SKILL_WISDOM && !ss_disabled[7] )
           return 7;
   }
   if ( v7 + v4->last_magic_school_level > Level
     || v10 == SKILL_FIRE_MAGIC
     || v10 == SKILL_AIR_MAGIC
     || v10 == SKILL_WATER_MAGIC
     || v10 == SKILL_EARTH_MAGIC )
   {
       goto LABEL_50;
   }
   v12 = 0;
   v13 = schools;
   while ( 1 )
   {
       v14 = *v13;
       v15 = v4->SSLevel[*v13];
       if ( v15 < max_level && v15 >= v29 && !ss_disabled[v14] )
       {
           if ( v15 <= 0 )
               v12 += v26->m_gainSecondarySkillChance[v14];
           else
               ++v12;
       }
       if ( (int)++v13 >= (int)"HeroSpec.txt" )
           break;
       v4 = current_hero;
   }
   if ( v12 <= 0 )
   {
LABEL_49:
       v4 = current_hero;
LABEL_50:
       v19 = 0;
       v20 = 0;
       while ( 1 )
       {
           v21 = v4->SSLevel[v20];
           if ( v21 >= max_level || v21 < v29 || v20 == excluded )
               goto LABEL_59;
           if ( ss_disabled[v20] )
               break;
           v22 = v26->m_gainSecondarySkillChance[v20];
           if ( !v26->m_gainSecondarySkillChance[v20] )
               goto LABEL_56;
LABEL_58:
           v19 += v22;
LABEL_59:
           if ( ++v20 >= 28 )
           {
               if ( v19 )
               {
                   v23 = Random(1, v19);
                   result = SKILL_PATHFINDING;
                   while ( 1 )
                   {
                       v24 = v4->SSLevel[result];
                       if ( v24 < max_level && v24 >= v29 && result != excluded )
                           break;
LABEL_73:
                       if ( ++result >= MAX_SECONDARY_SKILLS )
                           return -1;
                   }
                   if ( !ss_disabled[result] )
                   {
                       v25 = v26->m_gainSecondarySkillChance[result];
                       if ( !v26->m_gainSecondarySkillChance[result] )
                       {
LABEL_70:
                           if ( v24 > 0 )
                               v25 = 1;
                       }
                       v23 -= v25;
                       if ( v23 <= 0 )
                           return result;
                       goto LABEL_73;
                   }
                   v25 = 0;
                   goto LABEL_70;
               }
               return -1;
           }
       }
       v22 = 0;
LABEL_56:
       if ( v21 > 0 )
           v22 = 1;
       goto LABEL_58;
   }
   v16 = Random(1, v12);
   v17 = (TSecondarySkill *)schools;
   while ( 1 )
   {
       result = *v17;
       v18 = current_hero->SSLevel[*v17];
       if ( v18 < max_level && v18 >= v29 && !ss_disabled[result] )
       {
           if ( v18 <= 0 )
               v16 -= v26->m_gainSecondarySkillChance[result];
           else
               --v16;
           if ( v16 <= 0 )
               return result;
       }
       if ( (int)++v17 >= (int)"HeroSpec.txt" )
           goto LABEL_49;
   }
}


Checks for classes start at 4DAFE4h. Btw, you can notice there are no checks for Conflux heroes (bug), so its both classes are treated as Might.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 08:24 PM

{
       v6 = 3;
       v7 = 3;
   }
   else
   {
       v6 = 6;
       v7 = 4;
   }


I could probably neutralise it by giving these variables some ridiculously high values? Whats the highest I can put here? 255?

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 08:29 PM

Probably, it's better to get rid of this logic completely. Just NOP the following code (or write a jmp past it till here - 4DB096h) -

if ( v6 + v4->lastWisdom > Level || (v9 = v4->SSLevel[SKILL_WISDOM], v9 >= max_level) || v9 < min_level )
  {
      v10 = excluded;
  }
  else
  {
      v10 = excluded;
      if ( excluded != SKILL_WISDOM && !ss_disabled[7] )
          return 7;
  }
  if ( v7 + v4->last_magic_school_level > Level
    || v10 == SKILL_FIRE_MAGIC
    || v10 == SKILL_AIR_MAGIC
    || v10 == SKILL_WATER_MAGIC
    || v10 == SKILL_EARTH_MAGIC )
  {
      goto LABEL_50;
  }

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 08:36 PM

Is it better? Genuine question.

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 08:45 PM
Edited by AlexSpl at 21:00, 05 Mar 2026.

Noping will give you a free space, if you want it. Jumping is an elegant solution. Usually it's two bytes EB xx (where xx if how far or back you jump), or five bytes (E9 xx xx xx xx), if the length of the code you want to jump over is more than 128 bytes forth or -127 bytes back. Usually, you have to check, if any registers are defined in the code you want to erase, but I don't see any.

So, try to jmp from 4DAFDBh to 4DB096h. Edited a bit.

I see that distance is bigger than 128 bytes forward just by subtracting: 4DB096h - 4DAFDBh + 2 (2 is EB xx itself) > 128, so use E9 xx xx xx xx: 4DB096 - 4DAFDB + 5 (5 is E9 xx xx xx xx). Test and use jmps freely

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 09:07 PM
Edited by BigPig2 at 21:07, 05 Mar 2026.

I understand. I dont think Im yet at the point of needing space for anything and I feel like just switching up the values allows me to reverse the change easily should it turn out to cause some issues down the line.

Btw, I believe I see
{
       v6 = 3;
       v7 = v6;
   }
   else
   {
       v6 = 6;
       v7 = 4;
   }

Could that be correct? Also, in the hex code, v6 and v7 get mentioned first but I guess thats just a property of its syntax?

So:

06 at DB00D is the 6
04 at DB012 is the 4, and
03 at DB019 is the 3

So i can just set all these three to 25 and effectively mute this whole procedure?

And the 8B F0 at DB01D-E is the v7 = v6 ? How come when I reverse-assemble "mov    esi,eax" I get 89 c6 instead though?

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 09:15 PM

Correct, you see

mov     eax, 6
mov     esi, 4

for Might heroes and

mov     eax, 3
mov     esi, eax

for Magic heroes (with compiler optimization)

You can make 6, 4, and 3 very big numbers, and it will work, but we call it 'a crutch', as it doesn't look beautiful or effective. The game still will be running those instructions which you could just skip, never to trigger the intended logic. So, try to make those numbers big, and when it will work, try to just jmp over them.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 09:27 PM
Edited by BigPig2 at 21:28, 05 Mar 2026.

So u mean its good habits basically? I will keep that in mind.

I set the three values to 25 because by then the hero should have a full set of skills.

I am wondering about another thing:

if ( v7 + v4->last_magic_school_level > Level
    || v10 == SKILL_FIRE_MAGIC
    || v10 == SKILL_AIR_MAGIC
    || v10 == SKILL_WATER_MAGIC
    || v10 == SKILL_EARTH_MAGIC )


Does this part mean one of the schools is chosen at random or will it check for probabilities according to hero class at some later point? I am still struggling to read some parts of this code, not familiar with the syntax.

Also, what is that bit about pathfinding?

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 09:38 PM
Edited by AlexSpl at 21:41, 05 Mar 2026.

Quote:
I am wondering about another thing

This condition rockets you to LABEL_50, thus skipping the part of the code where skills are given according to their weights. That's why it called an exception. Magic schools just skip voting process

Quote:
Also, what is that bit about pathfinding?

Don't pay attention yet, Pathfinding just has ID of zero, so every iterator starts from it, from the first available skill.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 10:07 PM

Yet another reason to ditch this procedure then.

Ok but that is it then, my problems 2. and 5. are solved, I will play with the constants, I have a feeling v16+0 / v16+2 might be what I end up going for. Thank you so much for your help!

Btw, speaking of skill weights. I have seen multiple mentions of "make sure the probabilities add up to 112" (I think is the number?) and similarly "spell probabilities have to add up to 100", what happens if the dont exactly? I have already altered both in many spots but I have not played enough games with the changes applied to notice any ill or side effects.

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 10:11 PM

Quote:
Btw, speaking of skill weights. I have seen multiple mentions of "make sure the probabilities add up to 112" (I think is the number?) and similarly "spell probabilities have to add up to 100", what happens if the dont exactly? I have already altered both in many spots but I have not played enough games with the changes applied to notice any ill or side effects.

Forget 112. They sum up. Feel free to set up any you want.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 10:20 PM

And the spells (mage guild occurence probabilities)?

 View Profile
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted March 05, 2026 10:33 PM

Just experiment. They will sum up. The single thing that is important is the weight of a spell divided by the sum.

 View Profile
BTB
BTB


Famous Hero
Moist & Creamy
posted March 05, 2026 10:46 PM

BigPig2 said:
Btw, speaking of skill weights. I have seen multiple mentions of "make sure the probabilities add up to 112" (I think is the number?) and similarly "spell probabilities have to add up to 100", what happens if the dont exactly? I have already altered both in many spots but I have not played enough games with the changes applied to notice any ill or side effects.


This is something that can be redacted. It's a statement I made before I dug deep enough into the code to disprove it.

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 10:54 PM

Alright, that was my suspicion too but I just saw it in multiple sources and its just kind of hard to test it empirically.

Last question for the day then. How can I find the values of maximum number of heroes allowed to AI players per difficulty level? The 3/12, 4/15, 5/18 and 6/21. I feel like these values were probably justified with the memory constraints back when the game came out, and I understand things might get weird with like 60 heroes on the map but I would really like to play with these numbers and see if I find a better spot..

 View Profile
BigPig2
BigPig2

Tavern Dweller
posted March 05, 2026 10:57 PM

BTB said:
It's a statement I made

You and a whole lot of posters in other threads, and I believe on other sites as well, it feels like its "common knowledge".

 View Profile
Jump To: Next Thread » This thread is 45 pages long: 1 2 3 4 5 ... 10 20 30 ... 41 42 43 44 45 · «PREV / NEXT»
Post New Poll   Post New Topic   Post New Reply

Page compiled in 0.1313 seconds