Mac Gold Limit Editing

This forum is dedicated to platform-specific issues, discussions and tools relating to D2 modding for the Mac.

Moderator: Contrail

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Mac Gold Limit Editing

Post by Careyagimon » Fri Oct 05, 2007 7:07 pm

I've been tinkering around with the Mac D2 Carbon Application to modify the gold limit, trying to bring it inline with Windows Eastern Sun.

I've successfully quadrupled the stash limit. Ten million at clvl 100. It's done in a round about way though. 50k/clvl +5 million base. The reason for this is that I only edited the programmed calculation from (clvl/2 +1)*50k to (clvl/1 +100)*50k. I don't know enough about the structure of the code to make the equation into clvl*2*50k.

The offset for the code that controls the stash gold limit is 1942400 or so. If you take a look with a hex editor around that offset, you will see two "c350" which is hex for 50k. There are two because there are two equations for gold stash limits. One is for level 30 and under, and the other for 31+. Unfortunately, this value can't simply be changed to 200k as it is a 2-byte value.

Changing offset 1942401 from 04 to 06 changed the equation from clvl/2 to clvl/1. Offset 1942411 is the byte controlling the +X in the equation.

I only figured this out by changing different bytes to different values, loading D2(if the change doesn't make it crash) and checking how it affected the stash size. I would imagine that the change at 1942401 is a code change and not a data change (as opposed to say, the 1942411 change). Theoretically, one could make the right change to give the linear limit of clvl*4*50k. Again, I don't know enough about the structure to do that. Any Ideas?

I've also doubled the inventory gold limit. It is controlled at offset 1944958. Unfortunately, this is a signed value, or it would be very easy to quadruple the original 10k value to bring it in line with Windows ES. I think quadrupling would require a code change that I don't know how to do yet.

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Re: Mac Gold Limit Editing

Post by Contrail » Fri Oct 05, 2007 7:42 pm

I'll take a look at those areas when I get home tonight, I'll most likely be able to figure out how to change the calculation for the stash gold limit at least. The inventory gold limit may be more difficult to deal with, depending on how the code that deals with it works.

ETA:

Okay, I've sucessfully made the stash gold limit quadruple what it was while going up at the same rate as the original version, although after level 30 it goes up by 100,000 each level instead of 200,000 every two levels.

First, the original code that gets the stash gold limit, with a few annotations. This is taken from the 1.10b version of Diablo II (Carbon).

Code: Select all

001da350:  7c0802a6	mflr	r0
001da354:  3880000c	li	r4,12	- Passes 12 as an argument to the next function
001da358:  90010008	stw	r0,8(SP)
001da35c:  38a00000	li	r5,0	- Passes 0 as an argument to the next function
001da360:  9421ffc0	stwu	SP,-64(SP)
001da364:  4800fe6d	bl	0x1ea1d0	- Function call that return the player's level in r3
001da368:  60000000	nop	
001da36c:  2c03001e	cmpwi	r3,30	- compares the player's level to 30
001da370:  40810024	ble-	0x1da394	- If level <= 30 we skip down to 0x1da394
001da374:  54600ffe	rlwinm	r0,r3,1,31,31
001da378:  3c800001	lis	r4,1
001da37c:  7c001a14	add	r0,r0,r3
001da380:  7c030e70	srawi	r3,r0,1
001da384:  3804c350	subi	r0,r4,15536	- mullw treats this as an unsigned value
001da388:  38630001	addi	r3,r3,1
001da38c:  7c6301d6	mullw	r3,r3,r0
001da390:  4800002c	b	0x1da3bc	- Skips the branch for level <= 30
001da394:  3ca06666	lis	r5,26214
001da398:  3c800001	lis	r4,1
001da39c:  38056667	addi	r0,r5,26215
001da3a0:  7c601896	mulhw	r3,r0,r3
001da3a4:  3804c350	subi	r0,r4,15536
001da3a8:  7c631670	srawi	r3,r3,2
001da3ac:  54640ffe	rlwinm	r4,r3,1,31,31
001da3b0:  7c632214	add	r3,r3,r4
001da3b4:  38630001	addi	r3,r3,1
001da3b8:  7c6301d6	mullw	r3,r3,r0
001da3bc:  80010048	lwz	r0,72(SP)
001da3c0:  38210040	addi	SP,SP,64
001da3c4:  7c0803a6	mtlr	r0
001da3c8:  4e800020	blr	
001da3cc:  00000000	.word	0x00000000
Now, my revised version, which I had to add an extra instruction to that multiplies the value by 4 for the calculation for levels 30 and below:

Code: Select all

001da350:  7c0802a6	mflr	r0
001da354:  3880000c	li	r4,12
001da358:  90010008	stw	r0,8(SP)
001da35c:  38a00000	li	r5,0
001da360:  9421ffc0	stwu	SP,-64(SP)
001da364:  4800fe6d	bl	0x1ea1d0
001da368:  60000000	nop	
001da36c:  2c03001e	cmpwi	r3,30
001da370:  40810024	ble-	0x1da394
001da374:  54600ffe	rlwinm	r0,r3,1,31,31
001da378:  3c800001	lis	r4,1
001da37c:  7c001a14	add	r0,r0,r3
001da380:  5403083c    rlwinm	r3,r3,1,0,30 - Shifts left once instead of right once
001da384:  3804c350	subi	r0,r4,15536
001da388:  38630001	addi	r3,r3,1
001da38c:  7c6301d6	mullw	r3,r3,r0
001da390:  4800002c	b	0x1da3c0
001da394:  3ca06666	lis	r5,26214
001da398:  3c800001	lis	r4,1
001da39c:  38056667	addi	r0,r5,26215
001da3a0:  7c601896	mulhw	r3,r0,r3
001da3a4:  3804c350	subi	r0,r4,15536
001da3a8:  7c631670	srawi	r3,r3,2
001da3ac:  54640ffe	rlwinm	r4,r3,1,31,31
001da3b0:  7c632214	add	r3,r3,r4
001da3b4:  38630001	addi	r3,r3,1
001da3b8:  5463103a	rlwinm	r3,r3,1,0,30 - Added line - left shift by 2 = multiplying by 4
001da3bc:  7c6301d6	mullw	r3,r3,r0
001da3c0:  80010048	lwz	r0,72(SP)
001da3c4:  38210040	addi	SP,SP,64
001da3c8:  7c0803a6	mtlr	r0
001da3cc:  4e800020	blr
Also, I checked the Eastern Sun database site, and it actually says that the inventory gold stash is only doubled for that mod, so just changing 10,000 to 20,000 should work.

The necessary change, for completeness' sake:

Code: Select all

Original:
001dad7c:  1c632710	mulli	r3,r3,10000

Changed:
001dad7c:  1c634e20	mulli	r3,r3,20000
Careyagimon, thank you for making the original post with the offsets, they were very helpful in allowing me to find and change this code. The function that is used by the stash gold limit function to get the level looks to be one of the functions that gets stats in general, which will be a very useful function to know the location of.

If anyone wants a more detailed explanation of what the code is doing, I'll do my best to provide one, although I'm not an expert on PowerPC assembler by any means.

- Contrail
Last edited by Contrail on Sat Oct 06, 2007 4:03 am, edited 1 time in total.

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Re: Mac Gold Limit Editing

Post by Careyagimon » Sat Oct 06, 2007 6:20 am

although after level 30 it goes up by 100,000 each level instead of 200,000 every two levels.
I would guess this is because of your change to shift left once at 001da380. The calculation is normally something like "(Integer (clvl/2)) x 50000" hence a change only every other level. The shift left once makes it "(Integer (clvl*2))*50000." Since clvl*2 is always an integer, the change happens every level. Sorry for the psuedo-code. I don't actually know any assembly, I am just guessing at the structure of the equation.


How is it that you add a line to the code? The app stops working when I tried doing that.

http://miyoshino.la.coocan.jp/eswiki/?FAQ#sdd9e562 says ES has an octupled stash and quadrupled inventory. Maybe that is an old section of the wiki.

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Re: Mac Gold Limit Editing

Post by Contrail » Sat Oct 06, 2007 6:56 am

Careyagimon";p="358300" wrote:
although after level 30 it goes up by 100,000 each level instead of 200,000 every two levels.
I would guess this is because of your change to shift left once at 001da380. The calculation is normally something like "(Integer (clvl/2)) x 50000" hence a change only every other level. The shift left once makes it "(Integer (clvl*2))*50000." Since clvl*2 is always an integer, the change happens every level. Sorry for the psuedo-code. I don't actually know any assembly, I am just guessing at the structure of the equation.
You're correct about why it's happening, I was mostly just making a note of the difference.
How is it that you add a line to the code? The app stops working when I tried doing that.
Short answer: very carefully. Long answer: you need to have at least one line free at the end of the function or a no op instruction you can replace, because you don't want to increase the total number of lines in the file. Then you carefully move lines up or down in the file until you can clear out the space where you actually want your new instruction to go. The next step is to figure out the correct hex value for the instruction you want to add and place it in the correct place in the file. Finally, you correct any branch calls internal to the function that no longer point to the same line they did previously.
...ES has an octupled stash and quadrupled inventory. Maybe that is an old section of the wiki.
Hmm, I was going by the ES database website, I'm not sure which is likely to be more accurate.

- Contrail

User avatar
Hans
Dark Alliance Beta Test
Dominion
Posts: 6438
Joined: Sat Oct 02, 2004 5:14 pm
Location: Toronto, Ontario, Canada

Post by Hans » Sat Oct 06, 2007 8:49 am

The wiki is most likely up to date.
"Hi. My name is Hans, and I am addicted to a game that is not yet been made" - Card carrying member of D3 Addictions Anonymous, since June 2008.
Card carrying member of Mentaldom, since May 2006 - Zy-El Hardcore.
"German pornstar/Bee Gee lookalike" & "The Blacksmith"
Trying to picture Hans as a Dominion...nah it isn't working sorry. It's the mustache that gets me every time - Al-T.
"All men play on 127" O-H - Hans
"Okay, time out. This is Zy-El. The mod of total excess. Since when would any Zy-El lover do only what's necessary?" - Metropolis Man
Zy-El Wiki|New Zy-El Website

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Re: Mac Gold Limit Editing

Post by Contrail » Sat Oct 06, 2007 2:25 pm

Okay, well, to get 8 times the inventory gold capacity, you can make the following change instead of the previous change I listed for increasing the inventory gold limit.

Code: Select all

Original:
001dad78:  60000000	nop	

New:
001dad78:  54631838	rlwinm	r3,r3,3,0,28
That shifts the level value left three places, which is the same as multiplying by 8, before multiplying it by the original 10,000 gold value.

- Contrail

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12100
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U
United States of America

Hand-picked

Re: Mac Gold Limit Editing

Post by Myhrginoc » Sun Oct 14, 2007 3:49 pm

Contrail";p="358301" wrote:Short answer: very carefully. Long answer: you need to have at least one line free at the end of the function or a no op instruction you can replace, because you don't want to increase the total number of lines in the file. Then you carefully move lines up or down in the file until you can clear out the space where you actually want your new instruction to go. The next step is to figure out the correct hex value for the instruction you want to add and place it in the correct place in the file. Finally, you correct any branch calls internal to the function that no longer point to the same line they did previously.
I am totally ignorant of Mac executable structure, but perhaps a trick from the Windows DLL world can help. DLLs have discrete sections for code, read-only data (mostly intermodular communication) and read/write data. Since these sections are sized in pages, there is usually some slack space at the end of each section. You can replace static code at any location with a jump to slack space, put the overwritten instructions there and then your new code, and jump back to the next original line. Calls to new procedures work too.

One of the best examples of this is the skill points per level fix documented here. My post on 12 Jul, 2003 shows the basic technique. In a pinch, if you have discrete sections and run out of space code space, you should be able to put code in a read-only data section and execute it through jumps and calls. Read-write data is more risky, as the program may overwrite your new code in memory if the data location you use is actually referenced.

You need a tool that shows the executable file structure (what we call a PE viewer in the Windows world). Then look for dead bytes, probably all 00, between the last recognizable code and the section boundary.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Re: Mac Gold Limit Editing

Post by Contrail » Sun Oct 14, 2007 8:43 pm

Myhrginoc";p="359648" wrote:I am totally ignorant of Mac executable structure, but perhaps a trick from the Windows DLL world can help. DLLs have discrete sections for code, read-only data (mostly intermodular communication) and read/write data. Since these sections are sized in pages, there is usually some slack space at the end of each section. You can replace static code at any location with a jump to slack space, put the overwritten instructions there and then your new code, and jump back to the next original line. Calls to new procedures work too.

One of the best examples of this is the skill points per level fix documented here. My post on 12 Jul, 2003 shows the basic technique. In a pinch, if you have discrete sections and run out of space code space, you should be able to put code in a read-only data section and execute it through jumps and calls. Read-write data is more risky, as the program may overwrite your new code in memory if the data location you use is actually referenced.

You need a tool that shows the executable file structure (what we call a PE viewer in the Windows world). Then look for dead bytes, probably all 00, between the last recognizable code and the section boundary.
I do have a tool named PEFViewer that I downloaded from Apple's developer site that seperates out the different PEF containers and sections in a file. Unfortunately, the type of executable file being used for the Diablo II (Carbon) application doesn't have the same sort of page size requirement that a Windows DLL does, so there isn't as much dead space. Code sections are required to be 16 byte aligned, but otherwise the size of a section is fairly flexible. Some documentation on the PEF file structure that Diablo II uses on the Mac can be found on Apple's website here.

The code section for Diablo II has the actual functions, some glue code for making calls to external functions, and then some read-only data in it. There are some stretches of empty space in among the read-only data that's there that may be able to be used as you've suggested. They're not terribly large, though, so I may need to look into if it'd even be possible to add new external libraries and functions to the loader section without disturbing everything else too much. On the other hand, if that does turn out to be possible, it'd open things up quite a bit.

- Contrail

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12100
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U
United States of America

Hand-picked

Re: Mac Gold Limit Editing

Post by Myhrginoc » Tue Oct 16, 2007 1:31 am

If you can make an auxiliary library, then you could write your own "importer" function. The importer would have one parameter, the offset to the first instruction of a function in your module. The function itself should get the library's load address and save it in a read/write space if not already defined, then add the offset to the load address to get the true address of the function...and then call it. This is definitely a kludge but it works if you can't edit import/export lists. You only need one function, in the Diablo code you only need to "relocate" the bytes needed for the parameter and call for the importer. If you were calling a custom function used in several places, then you would have a number of "header" functions with the relocated code and a call to the custom function so the latter doesn't need to be burdened with relocated code.

There are other methods available that are more elegant, if you know how to patch code in memory. Then you just need to tag onto a function that executes very early (such as mpq load time) for the patcher.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Post by Careyagimon » Wed Oct 17, 2007 10:11 pm

Contrail, could you reiterate the edit to quadruple the inventory stash? I can't get it to work as it is. Thanks

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Post by Contrail » Thu Oct 18, 2007 12:41 am

Careyagimon";p="360362" wrote:Contrail, could you reiterate the edit to quadruple the inventory stash? I can't get it to work as it is. Thanks
Are you having trouble with the one to increase the stash gold limit by four, or with one of the inventory gold limit increase code edits I posted (one is for 2x the limit, and the other is for 8x the limit)?

- Contrail

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Post by Careyagimon » Thu Oct 18, 2007 1:13 am

Whoa, I just reread my last post... Sorry about that.

The stash gold limit. The code listed above isn't working for me.

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Post by Contrail » Thu Oct 18, 2007 2:04 am

Careyagimon";p="360378" wrote:Whoa, I just reread my last post... Sorry about that.

The stash gold limit. The code listed above isn't working for me.
Okay, the specific changes that need to be made are as follows:

With a hex editor, at offset 001da380 change 7c030e70 to 5403083c.
Then you insert 5463103a between the instruction at offset 001da3b4 and the instruction currently at offset 001da3b8.
Finally, at offset 001da3d0 (was originally 001da3cc), remove 00000000, to make up for the insertion at offset 001da3b8.

- Contrail

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Post by Careyagimon » Thu Oct 18, 2007 2:13 pm

Perfect. Thank you, Contrail.

User avatar
Contrail
Retired staff
Paladin
Posts: 169
Joined: Sun Jul 13, 2003 1:37 am
Location: Austin, TX

Re: Mac Gold Limit Editing

Post by Contrail » Thu Oct 18, 2007 7:29 pm

Turns out I forgot one more thing that needs to be changed. :oops:

At offset 001da390 you need to change 4800002c to 48000030, otherwise it ends up multiplying the stash gold limit by 50,000 twice instead of once if the character's level is over 30.

- Contrail

Careyagimon
Posts: 15
Joined: Tue Jun 18, 2002 7:43 pm

Post by Careyagimon » Fri Oct 19, 2007 2:36 am

One minor edit to make it exactly 4x stash limit:

Change offset 1DA38B from 01 to 04.

Return to “Mac Modding”