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 > Library of Enlightenment > Thread: Heroes 3 - Editing heroes in memory
Thread: Heroes 3 - Editing heroes in memory This thread is 4 pages long: 1 2 3 4 · «PREV
New_User
New_User

Tavern Dweller
posted February 17, 2020 09:37 PM

AlexSpl said:
Here is the example of how you can use LMOracle.SkillTreeAPI in your code...


Hey AlexSpl and all,

I changed an ID of a group of neutral creatures with HxD and saved the game. However after loading it, they still look the same as before on the map.
E.g. I changed wood elves (12) to dendroid guard (16), but they still look like elves on the map. When I right-click on them or attack them, they are displayed as dendroids, but I would like them to display as dendroids on the map, too.

Any way to do so?

Thanks!

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


Responsible
Supreme Hero
posted February 17, 2020 11:50 PM
Edited by AlexSpl at 00:18, 18 Feb 2020.

The following fields are responsible for how a tile is drawn.



It seems they are pointers. Go to the corresponding addresses and check, if you can find something meaningful there What those structures are, they point to, I don't know (tile frame numbers? can't be sure without disassembling). But beware of crashes while testing. Actually, you can replace the 3 pointers above with those of another monster and check that they are really about drawing. Also you'll notice that not only those pointers (or, rather, what they point to) should be changed to change monster's appearance, but also ones of the adjacent tiles.

Btw, in Heroes 1 there are no any pointers in the _MapItem_ structure. Instead, there is info about layers (ICN number and # of frame inside that ICN). So, it's logical to assume that those pointers in Heroes 3 have something to do with layers.

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


Admirable
Supreme Hero
posted February 18, 2020 12:57 AM

I documented this in H3API.
H3MapItem
H3ObjectDraw

It's not impossible to modify by hand but your sanity would greatly benefit from doing this using plugins.
____________
My Let's Plays: Metataxer's Revenge - The Empire of The World 2

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

Tavern Dweller
posted February 18, 2020 11:17 PM

AlexSpl said:
The following fields are responsible for how a tile is drawn.
It seems they are pointers. Go to the corresponding addresses and check...

@AlexSpl
Can you please clarify how I can find those addresses?
To find the creature stack, I use your instructions from another thread (where you explained how to change the creature aggressiveness):
1) Go to 6992B8
2) Find map offset
3) Find the offset of monsters with their coordinates
4) Find PackedMonInfo
Then I look for the creature ID that is the closest to those bytes.

RoseKavalier said:
I documented this in H3API.
H3MapItem
H3ObjectDraw
It's not impossible to modify by hand but your sanity would greatly benefit from doing this using plugins.

@RoseKavalier
Please elaborate. Did you mean that there is already a plugin for that, or did you just suggest that I create a plugin with the info you provided?
If there is a plugin that can let me edit creatures on the map of a started game (on an automatically generated map), with the memory editing or savegame editing, please let me know where I can find this plugin and how I can use it.
I checked SoD_SP but did not see such a feture there.

Thanks!

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


Responsible
Supreme Hero
posted February 19, 2020 12:28 AM
Edited by AlexSpl at 01:10, 19 Feb 2020.

Quote:
Can you please clarify how I can find those addresses?

PackedMonInfo, or, in general, setup of a tile is the first field of the _MapItem_ structure. Just add 0x12, 0x16, or 0x1A to the offset of monsters you found. Then go to the addresses there (I highlighted them in the example above).

There you'll find the H3ObjectDraw structure:

struct H3ObjectDraw
{
// * +0
// index of H3ObjectAttributes
UINT16 sprite;
// * +2
// * reference to which square of the DEF (bottom right = 0, then left to right, down to top. Row 1: 0x10 and so on)
UINT8 tileID;
// * +3
// * 0~6 drawing layer, 6 being top and 0 bottom
UINT8 layer;

_H3API_ H3ObjectDraw(UINT16 sprite, UINT8 tile_id, UINT8 layer);
};


Here you have to change sprite field, 2 bytes (I think their numbers shoud be sequential), and tileID field, 1 byte (a square within a DEF). That's all. Don't change a layer, unless you understand what's this field for.

By doing so you'll change only one tile of monsters (x, y, z). Repeat for all the other tiles of monsters (x, y - 1, z, and so on).

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


Responsible
Supreme Hero
posted February 19, 2020 05:51 PM
Edited by AlexSpl at 17:52, 19 Feb 2020.

Quick guide to replacing monsters in memory

Let's replace Griffins (ID = 4) at 10:7:0 with War Unicorns (ID = 25) at 13:7:0.



First, let's find them in memory:

Quote:
1. Find the address of Adventure Manager.
a) Open main memory of heroes3 process with HxD, for example;
b) Go to 6992B8 and there you'll find four bytes of the Adventure Manager address (for example, 01 EF CD AB means ABCDEF01);
c) Write this address down, let it be AdvMgrAddr.

2. Find map offset.
Calculate MapOffset - go to AdvMgrAddr + 5C and write down four bytes there just as in the example above;

3. Find the offset of monsters with coordinates x, y, and z.
Calculate the following value MonOffset = 38 * (X + MapSize * (Y + Z * MapSize));

4. Find PackedMonInfo.
a) Go to MapOffset + D0, and yet another time write down four bytes there, it will be MapItemsAddr;
b) Go to MapItemsAddr + MonOffset ...


Let MonAddr = MapItemsAddr + MonOffset.

Suppose, MonAddr of Griffins = 0x0F694D60, and MonAddr of War Unicorns is 0x0F694DD2.

Now we're going to the first draw field (+0x12) of Griffins: 0x0F694D60 + 0x12 = 0x0F694D72. There we'll find four bytes, write them down. For me it's 30 A1 D7 07 = (0x)07D7A130 (0x means that a number is hexadecimal). Well, now it's time to go there (Ctrl + G in HxD). What we see there is something like this -



It's a H3ObjectDraw structure: first two bytes (04 00) is the number of sprite. Then we have 1 byte of tileID within that sprite, and 1 byte of layer field, we don't want to change.

Now let's look at draw fields for War Unicorns. The first draw field (+0x12) of War Unicorns: 0x0F694DD2 + 0x12 = 0x0F694DE4. I go there and what I see is F0 A0 D7 07, or 0x07D7A0F0. Yet another time I press Ctrl + G and go to 7D7A0F0. Here I see the following bytes -



Let's try to replace 04 in the previous address with 05 from here. Wowsers! It worked immediately



Now you have to repeat this procedure for all the rest tiles of monsters being replaced. Just calculate new MonOffset for X, Y - 1, Z; X - 1, Y, Z; X - 1, Y - 1, Z. And... don't forget to change tileID field if it differs.

This is the simplest case, when monsters are not in an overlay. But you can always look at the rest two draw fields (+0x16, and +0x1A) and replace them too.


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

Tavern Dweller
posted February 20, 2020 12:30 AM

AlexSpl said:
Quick guide to replacing monsters in memory

Thanks, AlexSpl!
I followed your guide step-by-step, but the main tile (the one where the creature stack stood) converted to a pile of gold instead of how the desired creature looks (I only changed the first byte because the second one was the same for both creatures).
I tried twice, and both times it converted to a pile of gold.
Perhaps I just did something wrong. I'll try again.

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


Responsible
Supreme Hero
posted February 20, 2020 07:28 PM

Check coordinates. Maybe you really copied pile of gold near source monsters.

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

Tavern Dweller
posted February 22, 2020 12:29 AM

AlexSpl said:
Check coordinates. Maybe you really copied pile of gold near source monsters.

It seems that on different maps the IDs are different.
When changing the bytes for creatures that are placed on the same map (as in your example), the IDs are the same. However when I tried to put the same bytes on another map, it seemed to be different. This is why I got a pile of gold instead of a creature.
Anyways, thanks for your help.


If you don't mind, can you please also explain how I can build a building in a town in the memory? I mean changing the status from "not built" to "built" or upgrading an existing building.

You wrote in another thread about how I can find a town. But I am not sure how I can build a blacksmith or a marketplace or improve town hall to city hall or citadel to castle.
AlexSpl said:

For SoD 3.2 / HD mod:
Let GameMgrAddr = DwordAt(0x699538);
TownAddr = DwordAt(GameMgrAddr + 0x21614) + Town_ID * 0x168;
Spell_ID = IntAt(TownAddr + (0x11 + 6 * Level + Slot) * 4);
Town_ID, Level, Slot - all starting from 0.
Number of towns owned by Player_ID = ByteAt(GameMgrAddr  + 0x20B0E + Player_ID * 0x168).
List of Town_IDs owned by Player_ID starts at GameMgrAddr + 0x20B10 + Player_ID * 0x168, one byte for each town, the first byte being Town_ID of the topmost town on the game screen.
* DwordAt(), IntAt() - like in the previous example, 4 bytes @ 0x{given_address};
ByteAt() - 1 byte @ 0x{given_address}.
Note
There are no simple ways to obtain town's ID just by its coordinates. You have to look up through the whole list of town structures. Yet, there are two shortcuts. First, you can use LMOracle (or another program that shows Town_ID). Second, you can search for hexadecimal sequence of town's coordinates in memory (for example, x = 30, y = 30, z = 0 => search for hexadecimal string 1E 1E 00), then subtract from the address, you found, 5. There will be town's ID. You will significantly reduce the number of addresses to check by adding town's type (for example, Conflux at x = 30, y = 30, z = 0 => search for hexadecimal string 08 1E 1E 00).
02 - Town_ID, 00 - Owner_ID (Player_ID), 08 - Conflux, 0D 05 00 - town's coordinates, FF FF - no boat, etc. You will easily recognize a town structure after some practice Of course, this is not the way you should search for Town_ID in your programs/plugins, but it's fast for humans.


Thanks!

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


Responsible
Supreme Hero
posted February 23, 2020 03:00 AM bonus applied by Maurice on 23 Feb 2020.
Edited by AlexSpl at 06:39, 23 Feb 2020.

To build a town structure you have to modify two bitfields: TownAddr + 0x150 (8 bytes), and TownAddr + 0x158 (8 bytes). Actually, only the first six bytes of these bitfields store info about buidings. Each building is represented exactly by 1 bit (1, if a town structure is built).

But you don't even need to know anything about bitfields to effectively build town structures in memory. Just download this PDF where I shared values for every town structure.

How to use those values?

0. Choose which buildings you want to have in a town;
1. Find the sums of their values for each BYTE section separately;

Example

I want to have Mage Guild Level 4 (BYTE 0, Value = 0x08), Castle (BYTE 1, Value = 0x02), Village Hall (BYTE 1, Value = 0x04), Guardhouse (BYTE 3, Value = 0x40), Archers' Tower (BYTE 3, Value = 0x80), and also Upg. Portal of Glory (BYTE 5, Value = 0x08) in my Castle.

For BYTE 0, sum_0x150(0) = 0x08; // Mage Guild Level 4
For BYTE 1, sum_0x150(1) = 0x02 + 0x04 = 0x06; // Castle + Village Hall
For BYTE 2, sum_0x150(2) = 0x80; // see <just add anyway>*
For BYTE 3, sum_0x150(3) = 0x40 + 0x80 = 0xC0; // Guardhouse + Archers' Tower
For BYTE 4, sum_0x150(4) = 0x00;
For BYTE 5, sum_0x150(5) = 0x08; // Upg. Portal of Glory

* What's this <just add anyway>? Like the name reads, just add this value, because the game thinks that this unique building is built by default in those towns which don't have it (such a peculiarity).

2. Now find the sums of buildings' values and all of their 'downgrades' values, if any, for each BYTE section separately;

Example (cont)

We have three buildings which have 'downgrades': Mage Guild Level 4, Castle, and Upg. Portal of Glory.

Mage Guild Level 1 -> Mage Guild Level 2 -> Mage Guild Level 3 -> Mage Guild Level 4
Fort -> Citadel -> Castle
Portal of Glory -> Upg. Portal of Glory

For BYTE 0, sum_0x158(0) = 0x01 + 0x02 + 0x04 + 0x08 + 0x80 = 0x8F; // Mage Guild Level 1 + Mage Guild Level 2 + Mage Guild Level 3 + Mage Guild Level 4 + Fort
For BYTE 1, sum_0x158(1) = 0x01 + 0x02 + 0x04 = 0x07; // Citadel + Castle + Village Hall
For BYTE 2, sum_0x158(2) = 0x80; // see <just add anyway>
For BYTE 3, sum_0x158(3) = 0x40 + 0x80 = 0xC0; // Guardhouse + Archers' Tower
For BYTE 4, sum_0x158(4) = 0x10; // Portal of Glory
For BYTE 5, sum_0x158(5) = 0x08; // Upg. Portal of Glory

3. Time to write to memory. Go to TownAddr + 0x150 and write 6 bytes of sum_0x150, then go to TownAddr + 0x158 and write 6 bytes of sum_0x158.

Example (cont)

At TownAddr + 0x150 we should write 08 06 80 C0 00 08
At TownAddr + 0x158 we should write 8F 07 80 C0 10 08

4. Once you've done with building in memory, you may want to forbid to build on this day. Go to TownAddr + 2 and write there 01.  

* * *
But... It's not all. Almost all though. For example, for Mage Guilds, which were built in memory, you have to open spell slots manually. About this next time.

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


Responsible
Supreme Hero
posted February 24, 2020 02:17 PM

Additional steps for Mage Guild

1. Set Mage Guild level at TownAddr + 0x14 (1 byte).
2. Open spell slots at TownAddr + 0xBC (5 bytes, 1 byte for each Mage Guild level).

You can open as many as 6 slots at level 1, 5 slots at level 2, 4 slots at level 3, 3 slots at level 4, and 2 slots at level 5:
06 05 04 03 02

In the Horn of the Abyss don't open more than 5/4/3/2/1 slots for level 1/2/3/4/5, because additional slots are filled only for Tower with Library (when you build it in the game).

3. You may also want to change spells at TownAddr + 0x44 (4 bytes for a spell, 6 spells for each Mage Guild Level).

To quickly find a spell you can use this formula (Level, Slot starting from 0):
SpellAddr(Level, Slot) = TownAddr + (0x11 + 6 * Level + Slot) * 4

Additional step for creatures' dwellings

You may change the number of creatures in dwellings here: TownAddr + 0x16 (2 bytes for each tier).

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


Known Hero
Making map for HotA then WoG
posted March 23, 2020 12:30 PM

You know, after all these years, I'm still wondering how to change resources.

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


Legendary Hero
Heroes is love, Heroes is life
posted March 23, 2020 12:51 PM

You mean in Resource Silos or...?
If that's the case, I would like to know as well.

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


Known Hero
Making map for HotA then WoG
posted March 23, 2020 01:01 PM
Edited by FirePaladin at 17:00, 23 Mar 2020.

phoenix4ever said:
You mean in Resource Silos or...?
If that's the case, I would like to know as well.


No, just simply adding/subtracting resources from a player. The first part of the first post of this thread "explains" how to do that, but I can't find any _mputer, "[player_color] (like: Red, Blue, etc.)" or Player.

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


Responsible
Supreme Hero
posted March 23, 2020 09:11 PM

2FirePaladin: They are here -

DwordAt(0x699538) + 0x20AD0 + 0x168 * Player_ID + 0x9C,
or
DwordAt(0x69CCFC) + 0x9C for the active player.

Four bytes each.

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


Known Hero
Making map for HotA then WoG
posted March 23, 2020 10:31 PM
Edited by FirePaladin at 14:51, 29 Mar 2020.

AlexSpl said:
2FirePaladin: They are here -

DwordAt(0x699538) + 0x20AD0 + 0x168 * Player_ID + 0x9C,
or
DwordAt(0x69CCFC) + 0x9C for the active player.

Four bytes each.


Thank you! I'm gonna try and see if it works!

Edit: One more thing; I don't understand almost anything you wrote.

 Send Instant Message | Send E-Mail | View Profile | PP | Quote Reply | Link
Jump To: « Prev Thread . . . Next Thread » This thread is 4 pages long: 1 2 3 4 · «PREV
Post New Poll    Post New Topic    Post New Reply

Page compiled in 0.0871 seconds