Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Cheating on HOMM3 / Paging heroes.
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Wed Feb 07, 2018 2:22 pm    Post subject: Cheating on HOMM3 / Paging heroes. Reply with quote

Hello, this is my first post.

First of all: thank you for CE. I've been using it for the last year or so essentially as a replacement for ArtMoney, which I have been used for far longer but its last free version is now behaving wankily on W10.

At any rate, I have recently discovered the power of pointers (the sticky tutorial in the pointer forum really did it, thanks!) and I've put this knowledge to use getting finally an address list table which retains its validity even after a game restart.

So far so good. My next step is venturing into scripting. I have a basic knowledge of programming but I am not skilled with lua at all.

Well I'm digressing. Here's my question:

I want to create an elegant solution for cheating on HOMM3 heroes. HOMM3 (Heroes of Might and Magic 3) often involves usage of several characters at once. Every character has a rather complicated list of attributes and items. I have used CE's dropdown functionality extensively to make sure to be able to insert/specify correct values for certain fields. When all is said and done however, mapping out all features for a single character creates a rather long address list, with up to a couple hundred elements. With 179 possible characters to choose from, I am worried that if I were to map them all, the final address list will occupy several MB's on the disk and be so long (even with grouping) to be difficult or even impractical to use.

Since all characters are evenly spaced on memory at a fixed interval, I was wondering if there was any way to create or script a sort of up/down paging system so that I can cycle through the characters without having to create separate collections of entries for each of them. As now all the addresses in the addresslist are listed as pointers, I was wondering if I could just be able to add/subtract a multiple of the spacing value to the offset of each address dynamically and if whether such a solution would constitute a best practice for CE.

Thank you very much for your attention and help.

If anyone had some sort of working example for a similar situation I could put my hands on, that would be terrific.

Please do feel free to remove this post in case this question has been answered already, apologies if that's the case.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Wed Feb 07, 2018 4:24 pm    Post subject: Reply with quote

Quote:
Since all characters are evenly spaced on memory at a fixed interval, I was wondering if there was any way to create or script a sort of up/down paging system so that I can cycle through the characters without having to create separate collections of entries for each of them.
Sure, set a memory record with the address of the base of the player and then have each attribute nested under it with the address being "+Offset" so if health is playerbase+4 the address for health would just be +4 (alternatively if you've created a struct in the dissect data/structure window you can use +structname.elementName). Then you just need to change the relevant offset for the base memory record with some lua code like this (offset 0 is the top offset shown in the pointer window, 1 the second etc.):

Code:
local mr = getAddressList().getMemoryRecordByDescription('Player Base')
mr.Offset[0] = mr.Offset[0]+OffsetDiff
if mr.Offset[0] > lastPlayerOffset then mr.Offset[0] = firstPlayerOffset end


If you end up trying to do something more complex and start messing with mr.Address then note that unlike the offset and CurrentAddress it's stored as a hex string and you should assign a hex string back to avoid issues (it'll convert numbers to strings but eg. 111 becomes '111' which is read as the hex string 111 not the decimal number 111 which is hex 6F so you'd need to actually assign '6F' to get the decimal address 111), to convert a number to a hex string you can use string.format('%x', number) or ('%x'):format(number), there's no difference, the second is just slightly shorter Smile

To convert a string to a number you can use getAddressSafe(stringAddress) which will return the number or nil if it's an invalid address.

Here's a working example for step 9 of the tutorial: https://github.com/FreeER/CE-Examples/blob/master/cycle%20player%20addresses%20-%20step%209%20-%20PW%2031337157.CT


edit: you could also abuse the struct mechanism to create names for each player, eg. create a struct called "players" and insert each offset for the players and name them based on the player names (I'd avoid spaces not sure how CE handles those). Then to pick a specific player you could use players.playername)
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Wed Feb 07, 2018 5:19 pm    Post subject: Reply with quote

Hi, thank you so much for your reply.

I tried to download the example you pointed me to, but CE6.7 won't let me load it, returning a data error message.

However by looking at the XML I think I understand what you referred to. I must admit, I didn't even know CE had the Structures section. I do understand how it would make sense, except I have already painstakingly mapped the "structure", as it is, on the addresslist table. Unless there is an easy way to create a structure from an existing addresslist table, I am not sure I want to go through mapping everything again, including the references to pointers. It's 200+ fields, a healthy mix of Byte, 2 Bytes, 4 Bytes and Strings. And a lot of those fields can only take certain values which I have mapped to dropdown lists. However there might be an easy solution which my ignorance can't point me to.

Thank you again for your help.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Wed Feb 07, 2018 5:28 pm    Post subject: Reply with quote

I created it in 6.7 so that's odd...

You could probably write some lua code to create the structure but if you're new to lua I can't say for sure whether getting it right would take more or less time than doing it manually Smile
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Thu Feb 08, 2018 2:09 pm    Post subject: Reply with quote

Hi,

I managed to create the structure, essentially re-doing the same work I did for the address list. Took me a while.

So now I have:

- A basic starting address and offset to create the pointer to the memory block where characters are located;
- An address list with all the fields I want to be able to modify; at the moment the fields are all defined as pointers to the first character in memory;
- A structure, based on a fixed address (so it won't work the next time around, but I couldn't find how to make it start from a pointer) with, again, all the fields I am interested in;
- The precise length of a character structure (1170 bytes).

I am really grateful for your patience with me in showing me an example and the code. However, would you be so kind as to ELI5 a little bit how I would go about tweaking and arranging all these things so that in the end I will be able to page through every single character in memory, from a concept point of view?

Thank you again.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Feb 08, 2018 2:54 pm    Post subject: Reply with quote

Once you have the addresslist setup as I demoed, a base pointer with all the attributes setup as children (slightly indented) and their addresses based on the parent then all you have to do is change the offset of the parent to move to the next player and all the addresses and values will update accordingly.

That could be done manually by opening the pointer/address window and clicking the arrows or typing it in, or

with a lua script as I demoed in the ct that gets the basepointer memory record by it's name/description and changes the offset by adding some constant value to it (probably 4 or 8 which are the sizes of a pointer depending on x86 or x64).

Hm, it could probably be done with the attributes setup as pointers but you'd have to have a way to reference all of them... descriptions are obviously different and ids probably are too unless you opened the file and edited to make them consecutive, or the code could put them all in a table and loop over it but that's just as much manual work... hm. ah, this might be a good case for using the plain positional based function, it typically breaks if anything gets moved around so I never use it but... something like this could probably update all of the offsets to be the same as the base pointer's offset when it changes.

Code:
local al = getAddressList()
local player = al.getMemoryRecordByDescription('Player Base')
local firstAttribute = position of first attribute memory record in list (0 based)
local lastAttribute = position of last attribute memory record in list (0 based)

-- called when player base value changes, should be triggered when offset changes
player.OnGetDisplayValue = function(player, value)
  local newOffset = player.Offset[1]
  for i = firstAttribute,lastAttribute do
    local mr = al.getMemoryRecord(i)
    mr.Offset[1] = newOffset
  end
end


you'd still need to be able to change the player pointer by changing the offset but then you wouldn't have to edit all the attributes to be based on that memory record (though it wouldn't be that bad if you used a text editor with macro functions so you could record changing one in the CT and then rerun that for each of the others).


If you'd like you could provide me a link to the table and I could probably setup the scripts, I don't have the game but I could still manage some testing. Might take less time than providing step by step instructions like an actual 5yo would need Smile
I'd also need to know how the offset changes for each character however.
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Thu Feb 08, 2018 5:46 pm    Post subject: Reply with quote

Hello again,

So I think I understood much better how the structure plays into the address list. I just finished translating all of my addresses from being individual pointers to being structure-driven offsets to the base pointer (a la your example). It took a very long time and a lot of mouse clicks.

By the way I found out why loading your example gave me a data error. I didn't want to clone the git repository for just one file so I just copy-pasted it from github to a new file. However my editor saved it as utf8 with bom and the bom screwed with CE. Saved again without bom - no problem. (I think CE could be made to recognize and ignore the BOM for a future release).

Another problem I had, is that in my address list I had already added plenty of groups and subgroups by way of the context menu item "Create header". One problem with it is that I couldn't find how to convert a header to an address item. The only way is to create a new address and then group other addresses behind it. I already had about 20 groups so it took even more time ungrouping and regrouping. Having headers without addresses meant I couldn't pass through the offsets to the grouped addresses.

Now I'm at the point when I can finally put lua into it, but my first attempt did not work. I will try to work some more, if I see no way out I will reply again attaching my current CT.

Thank you again for your help.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Feb 08, 2018 5:58 pm    Post subject: Reply with quote

Good luck (mostly posting because I know CEF prevents double posting for a period of time and edits don't provide notifications lol)
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Thu Feb 08, 2018 6:00 pm    Post subject: Reply with quote

I'm a bit at a loss,

I copy-pasted "Prev Player" from your table to mine.

I edited it to tweak the variables.

When I OK it, it throws an error:

Code:
Lua error in the script at line 1:[string "local syntaxcheck,memrec=......"]:2:too many C levels (limit is 200) in main function near "Player Base")


This is the first time I use lua and I got an error for which I get no relevant hits. Bad omen.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Feb 08, 2018 6:09 pm    Post subject: Reply with quote

Hm strange... sounds like it tried to recursively run itself somehow (too many C levels).

Try adding if syntaxcheck then return end at the top, right after the {$lua} part. That will prevent CE from trying to run the code when you're editing it to check the syntax, if there's a deeper problem (though I can't think of one right now) it'd probably cause the same to occur when you tried to activate it however.
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Thu Feb 08, 2018 6:12 pm    Post subject: Reply with quote

I added the line you suggested (through right click and Change script) but it still gives me the same error.

It's really weird. In your table, the code works. I open your table, right click on Prev Player, "Change script", select all, copy, then I go to my table, right click on Prev Player, "Change script", select all, paste, change OffsetDiff to 360 and 3 to 8 in lastPlayerOffset, click OK, and it returns the error.


* * * * * * * *

EDIT (now I understand what you meant by double posting):

Quote:
you could also abuse the struct mechanism to create names for each player, eg. create a struct called "players" and insert each offset for the players and name them based on the player names (I'd avoid spaces not sure how CE handles those). Then to pick a specific player you could use players.playername)


Alright, I managed to apply the quoted method, with the help of excel and a couple regexps. I am really curious to know what went wrong with lua but at least I have reached a fairly acceptable solution for now.

I tried to attach my cheat table, but it weighs in at 943KBs and my attachment limit is a whopping 8 bytes, and I am afraid I don't know of any compression mechanism that good. If you have a good idea on how to share it I'd be grateful to know.

Thank you again for your help.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Feb 08, 2018 6:43 pm    Post subject: Reply with quote

Hm, I can't get the same error to occur by changing things to be invalid so I can't guess what the problem is without the table...
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Thu Feb 08, 2018 6:50 pm    Post subject: Reply with quote

I managed to paste my table on the website paste.ee, the ID of the paste is w3MDI. I cannot paste URL's so you'll have to compose it by yourself. The syntax is https, followed by colon, double forward slash, paste dot ee, slash, p, slash, w3MDI.


The link will expire in 24 hours.
Back to top
View user's profile Send private message
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Feb 08, 2018 8:52 pm    Post subject: Reply with quote

Well CE didn't like opening it but I got a working table by editing it together in vim lol

You've got a different setup so it required different code, can't guarantee without testing that it'll work when attached to the game but it's changing the offsets when unattached at least.

https://www.dropbox.com/s/z7tdjnhy1cb5fzf/HOMM3.CT?dl=0

This does have fewer attributes etc. to keep the file smaller (~380 instead of ~900), should be enough for testing and even if CE doesn't like you copy/pasting the scripts you could open the tables in a text editor and copy/paste the relevant cheat entries.


if you'd like me to delete that after you've downloaded it just let me know Smile (paste.ee failed for me so I just used dropbox)

You'll notice that there's two versions, a "simple" one that only works with numbers and another that tries to work with the struct names. That one adds a couple functions at the top which you can mostly ignore since they're just nice ways to get the structure by name (CE doesn't support that by default, multiple structures can have the same name). Since it's already working with the structure it also gets the first, last, and offset difference from there as well.
Back to top
View user's profile Send private message
wlog
How do I cheat?
Reputation: 0

Joined: 07 Feb 2018
Posts: 8

PostPosted: Fri Feb 09, 2018 11:55 am    Post subject: Reply with quote

FreeER wrote:
Well CE didn't like opening it but I got a working table by editing it together in vim lol


Might it be the same BOM issue I had earlier?

Quote:
You've got a different setup so it required different code, can't guarantee without testing that it'll work when attached to the game but it's changing the offsets when unattached at least.


Your CT file works; however I had to change line 66 of both scripts for Next Player and Prev Player, from "Heros." to "Heroes." as the structure with the list of heroes is called Heroes.

Thank you very much for your help.

While we're at it, do you think there is any way I can choose the character with a dropdown menu of some sort?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites