Text to Item

Started by Panda On Smack, May 18, 2010, 10:24:06 PM

Previous topic - Next topic

Panda On Smack

I was hoping to understand a little more about the text to item codes in use. I understand the principle and what is happening but using ASM to achieve it is out of my depth.

This animal crossing code is a good example, cant remember who made it:

286DFC80 9FEF6010
C0000000 0000000C
3F608062 637B5477
38A00000 3920000C
8D5B0002 2C0A003A
41800008 394A0009
714A000F 7D4A4830
7CA55214 3929FFFC
2C090000 4080FFDC
3F6090E2 637BEB22
3FC0805D 8BDE2477
38600000 606386C0
7FDE19D6 7F7BF214
B0BB0000 4E800020
E0000000 80008000

A button is pressed and the code fires but can I adapt this to another game by changing memory locations for example?

the code translates to:


lis r27,-32670
ori r27,r27,21623
li r5,0
li r9,12
lbzu r10,2(r27)
cmpwi r10,58
blt- 0x08
addi r10,r10,9
andi. r10,r10,15
slw r10,r10,r9
add r5,r5,r10
subi r9,r9,4
cmpwi r9,0
bge+ 0xFFFFFFDC
lis r27,-28446
ori r27,r27,60194
lis r30,-32675
lbz r30,9335(r30)
li r3,0
ori r3,r3,34496
mullw r30,r30,r3
add r27,r27,r30
sth r5,0(r27)


ta

dcx2

I believe this YouTube video demonstrates the code.

Animal Crossing supports an on-screen keyboard.  The value of the characters in this on-screen keyboard are stored somewhere in memory.  If you find it and parse the character values correctly, you can use this value as an input to modify other parts of memory.

Tomorrow morning I'll try to add some comments to the asm code, explaining what it's doing.

Panda On Smack

#2
Thanks dcx

I basically need to turn hex string values into their actual text equivalent in a 4 character template

So if I type this into the text box:

017A

it is held in memory as this:

0030 0031 0037 0041

So I need to read those values in and convert them back to 017A and store it all is a Dword along with the amount of the item:

017A0009

Is there asm functions to convert?

Panda On Smack

dragonboy posted some helpful codes and info here on a similar note:

http://wiird.l0nk.org/forum/index.php/topic,1856.msg32072.html#msg32072

dcx2

lis r27,-32670
ori r27,r27,21623 # r27 is a pointer to the unicode string
li r5,0 # r5 is our running total
li r9,12 # r9 is a bit-shifting value
lbzu r10,2(r27) # loads [r27 + 2] into r10, then adds 2 to r27 (accounts for Unicode)
cmpwi r10,58 # is this a digit or a character?
blt- 0x08 # if character...
addi r10,r10,9 # add 9
andi. r10,r10,15 # mask off everything but the last 4 bits
slw r10,r10,r9 # shift remaining bits to the appropriate position
add r5,r5,r10 # add shifted value to our running total
subi r9,r9,4 # adjust the shift value to load into the next nibble
cmpwi r9,0 # do we have more bits to shift?
bge+ 0xFFFFFFDC # branch back to lbzu
lis r27,-28446
ori r27,r27,60194 # load r27 with a base pointer
lis r30,-32675
lbz r30,9335(r30) # load r30 with a multiplier byte variable
li r3,0
ori r3,r3,34496 # load r3 with multiplier constant
mullw r30,r30,r3 # put product in r30
add r27,r27,r30 # add product as an offset to the base pointer
sth r5,0(r27) # store the text->hex value at the calculated pointer


Working our way through, using your example...

lbzu loads r10 with 0x30, and increments r27 by 2 (that's the 'u' part).  It is then compared against 58 = 0x3A.  Since 0x30 is less than 0x3A, it skips the addi.  The andi then masks off the 3, leaving you with 0x00.  slw shifts the nibble from r10 over by r9 bits so that it's in the right nibble, and then r10 is added to r5 (the running total).  r9 is adjusted so that it shifts to the next nibble on the next iteration of the loop.  If r9 is less than 0, we've shifted all the bits we're interested in, so we're done.  Otherwise, we have to start over.

lbzu loads r10 with 0x31, incs r27 by 2.  0x31 < 0x3A, skip addi.  andi masks the 3 off, leaving 0x01.  slw lines the nibble up, add puts it in the running total in r5, r9 is subbed so that it points to the next nibble, and we keep going.

skip 0037...

lbzu loads r10 with 0x41, incs r27 by 2.  0x41 > 0x3A, so addi changes it to 0x4A.  Mask off the 4, leaving 0x0A.  By this time, r9 = 0, so the slw won't actually do anything.  Add to the running total, sub r9 so that it's negative, and the loop terminates.

The last bit is just a really complicated way to get a hold of the address where we want to put this value, because it depends on a pointer and a variable offset which needs calculated.  Your game might not require this kind of belly-rubbing-and-head-patting type stuff.

If you have Animal Crossing, you might want to load it and try to set a Breakpoint so you can step through the ASM and see what it's doing.  But everything before the bge is probably going to be about the same.

Skiller

Cant u just use 2 32bit activators ? and tie it to the Keyboard Pad section ?

dcx2

#6
I'm not sure I follow you, Skiller.  Two activators?  Are they reading the Unicode characters?

When you press on the keyboard, it generates Unicode values in memory somewhere.  There's a non-trivial amount of massaging necessary to do Unicode -> integer casts.

Unicode is 16 bits per character, so you need to ignore every other byte.  Hence the lbzu offset of 2.  lbzu not only loads the destination register with the [source register + offset], but it *also* adds the offset to the source register.  It does two things at once.  This accounts for progressing through the Unicode string one character at a time.

Each character needs to be reduced to a 4-bit nibble that represents the character as an int.  For example, '3' must be turned into 0x03.  However, '3' = 0x33 (technically, a Unicode '3' is 0x0033).  '4' = 0x34.  Check out the ASCII chart (Unicode is something like an extension of ASCII).  That's why we andi with 15 = 0xF; this removes everything but the last four bits.

The letter Hex values need handled separate.  0x41 = 'A', which is why he adds 9 to anything greater than '9' = 0x39.  0x41 + 9 = 0x4A, mask with 0xF = 0xA.

Now we can turn Unicode characters into integer values.  But we have to add up the digits that we create.  In Panda's case, we want 0x100 + 0x70 + 0xA.  This is the purpose of the slw with r9 and the subi with r9.

Panda On Smack

#7
Awesome, thanks dcx

Ours should be easier because the place i want to store it is always the same and the place we get the digits from is always the same

This image shows the place where the text is stored, we just want the 4 characters 'h e l l' from hello


so

char1 = 92AA1CE9
char2 = 92AA1CEB
char3 = 92AA1CED
char4 = 92AA1CEF

They then need to be written to 900E0610 as 'XXXX' and then the amount to 900E0612 as '00XX'

dcx2

How familiar are you with asm?  Can you load r27 with 0x92AA1CE9?  Are you familiar with bit masking and bit shifting?

This is a good reference when trying to figure out what different instructions do.

http://pds.twi.tudelft.nl/vakken/in1200/labcourse/instruction-set/

Skiller

Example of what i mean .. if hes just trying to do a few things not every digit ..

92AA1CE8 ????????
92AA1CEC ????????

900E0610 ????00VV

Set them Red Addresses as your 32bit = to Activator . set the values to what u want to type in . doin so should set the 900E0610 ????00VV

but i know u want to be able to type everything in not just 1 :P

dcx2

I think you're suggesting an ifeq code that tests for "00000031" = Unicode '01', and another ifeq code "00370041" = Unicode '7A', and if both ifeq codes are true, then write 0x017A to 900E0610.

That's good if you're only watching for a few different inputs, but I think he wants to be able to type in an arbitrary hex value using the keyboard.

Skiller

Quote from: dcx2 on May 19, 2010, 05:24:14 PM
I think you're suggesting an ifeq code that tests for "00000031" = Unicode '01', and another ifeq code "00370041" = Unicode '7A', and if both ifeq codes are true, then write 0x017A to 900E0610.

That's good if you're only watching for a few different inputs, but I think he wants to be able to type in an arbitrary hex value using the keyboard.

ya thats why i put the Second part .. it would make for some intresting Effects being able to do that :P

Panda On Smack

#12
Yeah, i want to type in one of the Item Digits starting at 0001 all the way up to 02EA

I tried this but it freezes the game:

2865944C 00000008
C0000000 00000009
3F6092AA 637B1CE8
38A00000 3920000C
8D5B0002 2C0A003A
41800008 394A0009
714A000F 7D4A4830
7CA55214 3929FFFC
2C090000 4080FFDC
3F608000 637B180C
B0BB0000 00000000
E0000000 80008000

lis r27,-27990
ori r27,r27,7400
li r5,0
li r9,12
lbzu r10,2(r27)
cmpwi r10,58
blt- 0x08
addi r10,r10,9
andi. r10,r10,15
slw r10,r10,r9
add r5,r5,r10
subi r9,r9,4
cmpwi r9,0
bge+ 0xFFFFFFDC
lis r27,-32768
ori r27,r27,6156
sth r5,0(r27)


Are we sure it's unicode? geckoDotNet cant read it as that, only ascii

dcx2

That's a good start.  But your last lis r27/ori r27 is not writing to 900E0610.  You're actually writing to 8000180C.  Look at the immediate part of the op-code (bolded) to see the hex address instead of the decimal address.

3F608000 637B180C = lis r27,-32768; ori r27,r27,6156

Another problem is that you forgot to end your C0 code with a blr = 4E800020.  Check the code-type doc.

And there's still the small issue of how you wanted to write the item count at the same time.  You'll need to li your item count value into some register, and then sth that into 900E0612.  Something like this, before the blr but after your sth.

li r5,10
sth r5,2(r27)

Try this code (I think the li/sth will work in this, but I'm not sure, might want to run this through the ASM converter to double-check)

2865944C 00000008
C0000000 00000009
3F6092AA 637B1CE8
38A00000 3920000C
8D5B0002 2C0A003A
41800008 394A0009
714A000F 7D4A4830
7CA55214 3929FFFC
2C090000 4080FFDC
3F60900E 637B0610
B0BB0000 38A0000A
B0BB0002 4E800020

E0000000 80008000

Panda On Smack

#14
nice one

It should now be C0000000 0000000A though as it's got an extra line of code
I also change the 2nd line to 3F6092AA 637B1CE7 because leaving it at E8 gave me all 0's and using E9 missed the first digit off

Text to Item (C & -)
2865944C 00000048
C0000000 0000000A
3F6092AA 637B1CE7
38A00000 3920000C
8D5B0002 2C0A003A
41800008 394A0009
714A000F 7D4A4830
7CA55214 3929FFFC
2C090000 4080FFDC
3F60900E 637B0610
B0BB0000 38A0000A
B0BB0002 4E800020
E0000000 80008000

So this puts what you type in your first slot

no error checking though

thanks dcx!