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
Thread: Heroes 3 Hacking Reference Guide This thread is 42 pages long: 1 10 20 ... 29 30 31 32 33 ... 40 42 · «PREV / NEXT»
Parascus
Parascus


Adventuring Hero
posted October 26, 2022 09:45 PM

AAAararrgggllllll, sometimes I should just lay down and wait for a time when my brain is ready to work ... Lord Haart has Estates Speciality!!!!! No wonder he gets more money than the basic estates!!!!. Sorry for the inconvinience.

Have a nice evening!

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 27, 2022 10:07 AM

Hello again,

I've sat down and tried some more things. Right now I have a function to change the SecondarySkillValues. It writes the int values to the corresponding address (like described in BTBs document).

Now there are the following items I want to change:
1) regarding code organization I want to have an included code but when I try to separate this methods in different files I always get errors because the H§API.cpp and the patcher_x86.hpp have partially equaly named objects. Am I really forced to implement everything in the dllmain file?
2) The method to set the secondary skill values works fine for integer values. But because there are also doubles (percentages) I'd like to know how this is done. Doe I have to do a conversion or are there any further functions? I didn't find any.
3) Changing the skill values is fine but I would also need to overwrite the corresponding skill texts. They are located in h3bitmap.lod file SSTRAITS.TXT. Is there any way I can change them also via the dll methods?

Kind regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 27, 2022 12:00 PM
Edited by AlexSpl at 12:09, 27 Oct 2022.

Quote:
1) regarding code organization I want to have an included code but when I try to separate this methods in different files I always get errors because the H§API.cpp and the patcher_x86.hpp have partially equaly named objects. Am I really forced to implement everything in the dllmain file?

Look at H3API Single header, particularly at _H3API_PATCHER_X86_ option.

Quote:
2) The method to set the secondary skill values works fine for integer values. But because there are also doubles (percentages) I'd like to know how this is done. Doe I have to do a conversion or are there any further functions? I didn't find any.

For writeable sections (like .data) you can do this:

*(float*)0xADDRESS = X.Xf;
*(double*)0xADDRESS = X.X;

But you cannot do this for read-only sections (like .rdata where most of constants is stored actually), so you have to stick with WriteDword()/WriteHexPatch() methods. But there is a trick for float type floating-point numbers (4 bytes):

float eagleEyeCoefs[] = {0.00f, 0.30f, 0.35f, 0.40f};

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


If you have to change double type floating-point numbers (8 bytes) you should write your own wrapper function (e.g. WriteDouble() which should be able to split doubles into two double words).

But, again, feel free to use things like *(float*)(c->ebp - 4) = 1.75f; and *(double*)(c->ebp + 8) = 12.8; in your hooks.

Quote:
3) Changing the skill values is fine but I would also need to overwrite the corresponding skill texts. They are located in h3bitmap.lod file SSTRAITS.TXT. Is there any way I can change them also via the dll methods?

You can do this. Actually, all TXTs are loaded to memory, so you can work with them from a plugin without a need of messing with actual text files in LODs. Here is an example. In H3API things are automatized even further.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 27, 2022 04:02 PM

Hi AlexSpl,

thanks for your response. I managed to handle floats now and also the patch_86 is done. But I'm stuck with the texts. It does not return an error compiling or executing but I still see the old texts. I looked into the Memory and found that the old and the new text is included. The new ones in the area of 7BCD92F9 and the old ones at 0496BB67. At the address of the code (0067DCF0) I think I see the image names of the heroes. My current code is like:

   changeSecondarySkillValue(_PI, h3::NH3Skills::eSecondary::ESTATES, h3::NH3Skills::eSecondaryAddress::ESTATES, 0, 300, 600, 1200,
       (char*)"{Basic Estates}nnWith Estates, a hero contributes 300 gold per day to your cause.",
       (char*)"{Advanced Estates}nnWith Estates, a hero contributes 600 gold per day to your cause.",
       (char*)"{Expert Estates}nnWith Estates, a hero contributes 1200 gold per day to your cause.");

void changeSecondarySkillValue(
   PatcherInstance* PI,
   h3::NH3Skills::eSecondary skillID,
   h3::NH3Skills::eSecondaryAddress skillAddress,
   int noLevel,
   int baseLevel,
   int advancedLevel,
   int expertLevel,
   char basicDescription[],
   char advancedDescription[],
   char expertDescription[])
{
   DWORD baseAddress = 0x00400000;

   if (skillAddress != 0)
   {
       PI->WriteDword(baseAddress + skillAddress + 4 * h3::NH3Skills::NSecSkillLevel::NONE, noLevel);
       PI->WriteDword(baseAddress + skillAddress + 4 * h3::NH3Skills::NSecSkillLevel::BASIC, baseLevel);
       PI->WriteDword(baseAddress + skillAddress + 4 * h3::NH3Skills::NSecSkillLevel::ADVANCED, advancedLevel);
       PI->WriteDword(baseAddress + skillAddress + 4 * h3::NH3Skills::NSecSkillLevel::EXPERT, expertLevel);

       *(int*)(*(int*)0x67DCF0 + skillID * 16 + 0 * 4) = (int)basicDescription;
       *(int*)(*(int*)0x67DCF0 + skillID * 16 + 1 * 4) = (int)advancedDescription;
       *(int*)(*(int*)0x67DCF0 + skillID * 16 + 2 * 4) = (int)expertDescription;
   }
}

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 27, 2022 04:09 PM
Edited by AlexSpl at 16:11, 27 Oct 2022.

Probably you missed a hook: _PI->WriteLoHook(0x4E6D77, changeSecSkillDesc);

Also make sure skillID is Estates ID.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 27, 2022 04:49 PM

Hi AlexSpl,

ok, here I need a hook because I do not overwrite the data but append my data to the memory and I have to hook the program to the new memory location. Now it shows my texts.

So when i want to "replace" the speciality description, bios and also some names I have to do it the same way? And I have to "debug" the code during execution to get a feeling for the correct address for the hook.  asume to search for a text string ("Nagash" or "+1 Mercury") and place a "break on access" on it. The address looking for the memory location than is the hook address?

Thank you and best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 27, 2022 06:06 PM

Yes, you are right. Btw, in the above code we overwrite pointers to strings, so they point to our own strings, instead of the original ones, now.

Quote:
And I have to "debug" the code during execution to get a feeling for the correct address for the hook.  asume to search for a text string ("Nagash" or "+1 Mercury") and place a "break on access" on it. The address looking for the memory location than is the hook address?

Basically, it's what pioneers of Heroes reverse engineering did. But now we have very thorough and precise game databases for IDA. Most things are usually done just by searching for function names/signatures.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 27, 2022 06:26 PM

Hi AlecSpl,

I might have overridden this but can you give me a link to the IDA database? I googled it but had no luck.

Best Regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 27, 2022 06:30 PM

There. But you need IDA 7.7 + Hex-Rays decompiler to open it.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 28, 2022 09:51 AM

Hello AlexSpl and BTB,

I'm now trying to do a mix of your approaches. I want to implement the frenzy mod within c++.

So I have first done a hook on address 0422C7 to call my own code. Than I tries to implement a test code. BTB has done the following:
   6B DB 02 imul ebx,ebx,02 ; Attack (EBX) * 2
   909090909090 nop ; -
   89 5D 0C mov [ebp+0C],ebx ; store EBX

As I understood this doubles the attack of the targeted unit. I implemented:
   int attack = c->ebx;
   *(double*)(c->ebp + 12) = attack * 100;
   c->return_address = 0x4422CE;
   return NO_EXEC_DEFAULT;
I take 100 to have a clear change in the stats and I jump back to 4422CE where the defense would be uneffected.

But the effect is not as desired and hoped:
1. I don't get a right click screen with the stats of the target unit.
2. The hover screen shows no changes.
3. I don't know how it should work because the effect (original procedure in BTB's mod) only is called hovering above the unit. Does it also take the change inot account when the unit attacks or is attacked?
I wonder where I cen get an example where the returned data is stuffed into a c++ structure. I only found an example of hota/homm3.h. But I don't have hota.
I also try to get the IDA running but the necessary program needs a registration and I'm still waiting for a response of the enterprise.

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 28, 2022 10:53 AM

Quote:
So I have first done a hook on address 0422C7 to call my own code.

You are trying to change the wrong function, namely long army::get_adjusted_defense(army *,bool). You should patch long army::get_adjusted_attack(army *,bool) instead.



Just some hints. Try to implement a hook yourself first.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 28, 2022 08:12 PM
Edited by Parascus at 20:46, 28 Oct 2022.

Hi AlexSpl,

yes, I think the start would be to implement a hook first that does not crash the system. Unfortunatelly I fail at this easiest first task :-(.

Cheat Engine shows me the following code:
Heroes3 HD.exe+42221 - 8B 86 78020000        - mov eax,[esi+00000278]
Heroes3 HD.exe+42227 - 5F                    - pop edi
Heroes3 HD.exe+42228 - 85 C0                 - test eax,eax
Heroes3 HD.exe+4222A - 74 35                 - je "Heroes3 HD.exe"+42261 { ->Heroes3 HD.exe+42261 }
Heroes3 HD.exe+4222C - 8B 55 08              - mov edx,[ebp+08]
Heroes3 HD.exe+4222F - 6A 00                 - push 00 { 0 }
Heroes3 HD.exe+42231 - 52                    - push edx
Heroes3 HD.exe+42232 - 8B CE                 - mov ecx,esi
Heroes3 HD.exe+42234 - E9 6FC91702           - jmp 025BEBA8
Heroes3 HD.exe+42239 - 89 45 0C              - mov [ebp+0C],eax
Heroes3 HD.exe+4223C - DB 45 0C              - fild dword ptr [ebp+0C]
Heroes3 HD.exe+4223F - D9 5D 0C              - fstp dword ptr [ebp+0C]
Heroes3 HD.exe+42242 - D9 45 0C              - fld dword ptr [ebp+0C]

I have a Hook in my dll defined with:
_PI->WriteLoHook(0x442234, executeSpellFrenzy);

This is calling:
int __stdcall executeSpellfrenzy(LoHook* h, HookContext* c) {
   c->return_address = 0x442239;
   return NO_EXEC_DEFAULT;
}

In my opinion 0x442234 is the address where you have your call long army::get_adjusted_defense(army *, bool). The next start of an opcode is 442239. So my spell execution does nothing but setting the return address to 0x442239 and declaring that it should not use the default but return to the return address.

The first lines of the crash report are below. An interesting fact is that the exceptions contain the 278 which are mentoined in the line of 442221.

I think there is a deep detail I have still no understanding for.

Best regards

Parascus

e-mail: baratorch@yandex.ru

[HOMM3 HD CRASH LOG]

Log
{
compability_dir = E:GamesgogcomHoMM 3 Complete modded_HD3_DataCompability#com_en
EXE_VERSION & SOD
No Files.ini for 'E:GamesgogcomHoMM 3 Complete modded_HD3_DataCompability#com_en'
No Files.ini for 'E:GamesgogcomHoMM 3 Complete modded_HD3_DataPacksHMMParascus'
got sulfur in nagabank. replace it to gems.

}

HOMM3 HD version: 5.4 R7
Time {   10/28/2022 20:41:58 }

GUN:  [AXG6HY0BHG3999WN996-7XB813]

Exception
{
  Module: Heroes3 HD.exe
  Adress:      [ 0x004422BD ]
  Code:        EXCEPTION_ACCESS_VIOLATION
  Flags:       0x00000000
  Information: read of address: 0x00000278
}

Context { EAX: 0x00000001, ECX: 0x00000000, EDX: 0x00000000, EBX: 0x0000000F, ESP: 0x00198094, EBP: 0x00198098, ESI: 0x00000000, EDI: 0x00000000 }

Call stack
{
  [ 0x004422B0 ] called from [ 0x0046D805 ]
  [ 0x0046D780 ] called from [ 0x004750DD ]
  ? called from before [ HD_SOD.dll+0x21B86 ]
  [ HD_SOD.dll+0x21B30 ] called from [ 0x025B686C ]
  [ HW_SOD.dll+0x36B0 ] called from [ 0x025BF260 ]
  ? called from before [ HD_SOD.dll+0x24441 ]
  [ HD_SOD.dll+0x243F0 ] called from [ 0x025B5DDC ]
  [ HD_SOD.dll+0x26670 ] called from [ 0x025B6038 ]
  [ HD_SOD.dll+0x53240 ] called from [ 0x025B7050 ]
  ? called from before [ 0x02DEFFD2 ]
}

Call stack V2
{
  004422BD (Heroes3 HD: 00400000): (?): (?)
  0046D80A (Heroes3 HD: 00400000): (?): (?)
  004750E2 (Heroes3 HD: 00400000): (?): (?)
  03361B86 (HD_SOD: 03340000): (?): (?)
  025B6871 (?): (?): (?)
  025BF265 (?): (?): (?)
  03364441 (HD_SOD: 03340000): (?): (?)
  025B5DE1 (?): (?): (?)
  025B603D (?): (?): (?)
  025B7055 (?): (?): (?)
  775110A8 (ntdll: 774E0000): (?): RtlRunOnceExecuteOnce
}

____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 28, 2022 10:00 PM

Well, it should have worked, but... you forgot about the stack. Note, that the next instructions:

push 0
push edx


push two arguments (edx and 0) on the stack, so that the following function (army::get_adjusted_defense()) could use them for its calculations. After a function is done using its arguments, it must clean the stack (this is how __thiscall, __fastcall, __stdcall functions work) or the stack must be cleaned by the caller just after the execution of the callee for __cdecl functions. If it's not done properly, the next functions will have wrong arguments (for example, the next function will receive 0 as a pointer) and this will result in a crash. So, keep this in mind when you choose a place to write your hook (jump).

Try the next address after the function call (0x442239) and return to 0x442259. In the hook body just write:

c->eax = 99;

c->return_address = 0x442259;
return NO_EXEC_DEFAULT;


Now, find out what is what (where is a pointer to your army? where is a pointer to the enemy army? etc.) and calculate your result (c->eax) as you wish.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 28, 2022 10:12 PM

Hi AlexSpl,

thanks for the stack hint. I will try this and also try top get used to it ... Java takes much of this work an dmakes you lazy...

I have tries to find a version of homm3.h to work with e.g. the hero structure _Hero_. But I didn't find it. And I think it would mix up with the H34API.hpp. Is this correct? Is there anything I can use in the H3API? I just found some pointers but no Hero structure.

Have a nice evening

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 28, 2022 10:18 PM

Quote:
I have tries to find a version of homm3.h to work with e.g. the hero structure _Hero_. But I didn't find it. And I think it would mix up with the H34API.hpp. Is this correct? Is there anything I can use in the H3API? I just found some pointers but no Hero structure.

You don't have to. H3API has all the classes you need. Just figure out how they called.

In the example above we have a pointer to an army in c->esi, so you can write:

army* myArmy = (army*)c->esi;

Now replace army with H3API's name for this class and you will be able to work with all the fields and methods this class provides.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 29, 2022 12:16 AM

Hi AlexSpl,

yeah, no crash, attack is 99 and it also accepts h3::H3Army! c->pop() twice did the job. Thank you.

Have a nice time

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 29, 2022 01:53 AM

Quote:
yeah, no crash, attack is 99 and it also accepts h3::H3Army! c->pop() twice did the job. Thank you.

While thus you indeed can clean the stack, I recommend to write hooks so that you wouldn't have to clean it manually. Just set your hook at the address of the next instruction after that function call

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 29, 2022 04:29 PM

Hi AlexSpl,

I thank you for your patience. Today I fought a long battle against logic but I lost ...

I think there are to many things I don't understand, maybe because the approach in pragramming is much more different than I expected. I even do not know what an "instruction" is in this case. I asumed that every Opcode is an instruction but I am not sure. Else when I write some code and try to debug it I have no chance to understand the result allthough I really tried. I also googled if there is any kind of console output where I could write something so I can see what's going on but there I had no luck either. Additionally I can only guess some of the meanings of the structures ... in lack of an ERM diagram. The following shows the code I would write in another language and because this is now  mixture of my approach and the harsh reality of c++/assembler, it has more a nature of pseudo coding:

The hook would be:
_PI->WriteLoHook(0x442239, executeSpellFrenzy);
But I do not know what it would mean to move it some bytes left or write. Is it important to do the hook after the jmp 025BEBA8?

Than my code would be like:
int __stdcall executeSpellFrenzy(LoHook* h, HookContext* c) {
   h3::H3Army* myArmy = (h3::H3Army*)c->esi;
   h3::H3CombatCreature* myCreature = (h3::H3CombatCreature*)myArmy->FindExistingByIndex(0);
   h3::H3CreatureInformation myCreatureInformation = (h3::H3CreatureInformation)myCreature->info;
   h3::H3Hero* myHero = (h3::H3Hero*)myCreature->GetOwner();
   h3::H3HeroSpecialty* mySpeciality = nullptr; // = myHero->GetSpeciality();

   int hasFrenzySpeciality = 0;
   if (mySpeciality != nullptr) {
       if (
           mySpeciality->bonusId == h3::NH3Heroes::eHeroSpecialty::SPELL &&
           mySpeciality->GetSpell() == h3::NH3Spells::eSpell::FRENZY
           
       {
           hasFrenzySpeciality = 1;
       }
   }
   
   int originalDefence = myCreatureInformation.defence;
   int originalDuration = 1;
   int fireMagicLevel = myHero->secSkill[h3::NH3Skills::eSecondary::FIRE_MAGIC];
   int resultingDefence = originalDuration;
   int resultingDuration;
   if (fireMagicLevel == 0) {
       resultingDefence = 0;
   }
   else if (fireMagicLevel == 1)
   {
       resultingDefence = originalDefence / 4;
       if (hasFrenzySpeciality) resultingDuration = originalDuration + 1;
   }
   else if (fireMagicLevel == 2)
   {
       resultingDefence = originalDefence / 2;
       if (hasFrenzySpeciality) resultingDuration = originalDuration + 3;
   }
   else
   {
       resultingDefence = originalDefence * 3 / 4;
       if (hasFrenzySpeciality) resultingDuration = originalDuration + 3;
   }

   int originalAttack = myCreatureInformation.attack;
   int resultingAttack = originalAttack * 2;
   

   c->return_address = 0x442259;
   c->eax = resultingAttack;
   // Assign resultingDefence;
   // Assign resultingDuration;

   return NO_EXEC_DEFAULT;
}

Some of this lines are quite normal in my opinion, others are wild guesses. In total this code leads to another crash. I don't know if the properties I try to use are correct and I have no possibility to find out which registers to set to have an effect on the data in the game. As mentioned before I have no access to the IDB database. Maybe there are some answers but the internet page to download it want a registration which I did but I got no email from them to activate my account.

Is this pseudo code so far away of the reality?

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted October 29, 2022 05:24 PM
Edited by AlexSpl at 18:19, 29 Oct 2022.

Quote:
h3::H3Hero* myHero = (h3::H3Hero*)myCreature->GetOwner();

Most of crashes happen because of incorrect pointers (usually, a program tries to access something, but a pointer to it is 0). So, if you fight against wandering creatures, for example, which haven't an owner, you'll end up having a 0-pointer in myHero. And in your code you're trying to access properties of myHero even when myHero is a 0-pointer. Usually you can write:

if (myHero)
{
  // do something if myHero isn't a 0-pointer
}
else
{
  // do nothing or try to handle such a case
}


Quote:
I also googled if there is any kind of console output where I could write something so I can see what's going on but there I had no luck either.


Add the following function to your code (or try to find something similar in H3API):


#define o_TextBuffer ((char*)0x697428)
#define ShowMessage(msg) MessageBoxA(NULL, (LPCSTR)(msg), (LPCSTR)"", MB_OK)

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

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


Now you can read internal information about your variables, classes and so on by calling debugStrWin(). For example,

debugStrWin("Attack: %dnDefense: %d", myHero->attack, myHero->defense);

Quote:
I asumed that every Opcode is an instruction but I am not sure.

An (assembler) instruction (or a command) is just like a microfunction with arguments usually. For example,

jmp loc_0044388E

is an instruction and only the jmp part of it is opcode.

In machine code a near jump - E9 XX XX XX XX, but only the "E9" part is opcode. Sometimes opcodes are even less than one byte in size (are just several bits of the first byte of instruction).

* * *
Also there are some differencies in naming between the original game classes and H3API's equivalents.

Quote:
h3::H3Army* myArmy = (h3::H3Army*)c->esi;
  h3::H3CombatCreature* myCreature = (h3::H3CombatCreature*)myArmy->FindExistingByIndex(0);

Note, that the army class in the original game code is a stack on the battlefield and not an army group of your hero. So, I think you should stick with h3::H3CombatCreature:

h3::H3CombatCreature* myArmy = (h3::H3CombatCreature*)c->esi

Yes, it's confusing, but when H3API had been being written there was no information about the original names.

* * *
A couple of advises. First, make sure your hook with empty body works. Second, comment (//) every line you have doubts about, and see if your code works without them. Third, use debugStrWin() function to make sure you're using right classes. For example, if myArmy->attack is 12345678 you've definitely chosen a wrong class.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted October 29, 2022 07:29 PM

Hello AlexSpl,

thanks again for all your hints. The debug message is really a good tool.

I tried different classes for the Army and as you mentioned it the CombatCreature was the correct one (not really surprising ).

I remodelled my functiona little bit:

int __stdcall executeSpellFrenzy(LoHook* h, HookContext* c) {

   h3::H3CombatCreature* targetCreature = (h3::H3CombatCreature*)c->esi;
   if (targetCreature != nullptr) {

       h3::H3Hero* currentHero = (h3::H3Hero*)targetCreature->GetOwner();
       if (currentHero != nullptr) {

           h3::H3CreatureInformation targetCreatureInformation = (h3::H3CreatureInformation)targetCreature->info;
           // h3::H3HeroSpecialty* speciality = currentHero.

           int originalAttack = targetCreatureInformation.attack;
           int resultingAttack = originalAttack * 2;
           c->eax = resultingAttack;

       } else {
           debugStrWin("No hero found.");
       }
   } else {
       debugStrWin("No creature found.");
   }

   c->return_address = 0x442259;

   return NO_EXEC_DEFAULT;
}

So for the attack it is working. But now I want to take influence on the defense and duration. I have the feeling that it is not done by just setting he properties of the structure? Or is it possible to change them and return to an address after those functions?

I have the feeling that I am right before the line of my dream frenzy. But for this I need the right address for the hooks for the defence and duration as well as the possibility to get the heroes speciality. I tried to figure it out but the H3Hero has no speciality property and I don't see where the structure H3HeroSpecialty is effectivly used.

Have a nice evening

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Jump To: « Prev Thread . . . Next Thread » This thread is 42 pages long: 1 10 20 ... 29 30 31 32 33 ... 40 42 · «PREV / NEXT»
Post New Poll    Post New Topic    Post New Reply

Page compiled in 0.1016 seconds