32bit if code type

Started by Dude, March 03, 2010, 02:17:30 PM

Previous topic - Next topic

Dude

Hey again guys and gals.

I'm not sure waht would be the correct IF codetype to use for this...

I've found an address and I want to build a code that checks this address and then writes a value to it, dependant on the current value.  I'm aiming to make it only work when I press a button combination.  I think it's the Regular IF Codes that I'll need to use, 32bit.

Example:

80104920 00000000

I want to first check if this value is less than 15.  If it is, then set to 14.
I then want to check if it is between 15 and 30.  If it is, then set to 29.
I then want to check if it is between 30 and 45.  If it is, then set to 44.
All in the one button press.

The purpose is to make it that I can press a button combination and have it check the value at the address and write to it accordingly.  The value naturally increases on it's own depending on what I do in the game, but want to speed it up by making it 1 value less than is required to get to the next level.  This will ensure that it triggers the unlockable when it reaches 15/30/45, etc.

I've thought of the logic and think this should work.  It should write the value without jumping straight to writing 44 to the address until I've gotten the unlockable.  I just don't know how to do it lol  Being able to do this for two or more addresses (using different values) from the one button combo would be perfect.

Anyone help please?

dcx2

Are you sure you need a 32-bit if?  Your values are small enough that it might be 16-bit or even 8-bit.  Anyway, here's pseudo-code for what you're trying to do.

if (val < 15) {
  val = 14;
}
else if (val < 30) {
  val = 29;
}
else if (val < 45) {
  val = 44;
}

You need to use else-if's.  Then, if you make it to the second else-if, you know for sure that you're at least 15.

Dude

#2
Thanks for the reply, dcx2.

The way you structured that is more simplified than the way I was initially trying to do it, but might result in writing the final 44 value into the address.  It will check if it's less than 25, then write 24, but then move onto the next line and check if it's less than 30, then write 29, etc.  I don't think that there is a "else if" in the code types to end the branch.

You're probably correct about the 32bit if though.  I've just been using the entire 32bits out of laziness lol

My only problem now is how I turn this into codes for use in Geckos using these Code Types:

CST4 : 16bits (endif, then) If equal

28______ ZZZZYYYY : 16bits If equal (ba) 16bits compares if ([ba+address] and not(ZZZZ))==YYYY.
If yes, codes are executed (else code execution set to false).

38______ ZZZZYYYY : 16bits If equal (po) 16bits compares if ([po+address] and not(ZZZZ))==YYYY.
If yes, codes are executed (else code execution set to false).

28_____1 ZZZZYYYY : Endif, then 16bits If equal (ba) Makes one endif, then 16bits compares if ([ba+address] and not(ZZZZ))==YYYY. If yes, codes are executed (else code execution set to false).

38_____1 ZZZZYYYY : Endif, then 16bits If equal (po) Makes one endif, then 16bits compares if ([po+address] and not(ZZZZ))==YYYY. If yes, codes are executed (else code execution set to false).

CST5 : 16bits (endif, then) If not equal

2A______ ZZZZYYYY : 16bits If not equal (ba) 16bits compares if ([ba+address] and not(ZZZZ))!=YYYY. If yes, codes are executed (else code execution set to false).

3A______ ZZZZYYYY : 16bits If not equal (po) 16bits compares if ([po+address] and not(ZZZZ))!=YYYY. If yes, codes are executed (else code execution set to false).

2A_____1 ZZZZYYYY : Endif, then 16bits If not equal (ba) Makes one endif, then 16bits compares if ([ba+address] and not(ZZZZ))!=YYYY. If yes, codes are executed (else code execution set to false).

3A_____1 ZZZZYYYY : Endif, then 16bits If not equal (po) Makes one endif, then 16bits compares if ([po+address] and not(ZZZZ))!=YYYY. If yes, codes are executed (else code execution set to false).

CST6 : 16bits (endif, then) If greater

2C______ ZZZZYYYY : 16bits If greater (ba) 16bits compares if ([ba+address] and not(ZZZZ))>YYYY. If yes, codes are executed (else code execution set to false).

3C______ ZZZZYYYY : 16bits If greater (po) 16bits compares if ([po+address] and not(ZZZZ))>YYYY. If yes, codes are executed (else code execution set to false).

2C_____1 ZZZZYYYY : Endif, then 16bits If greater (ba) Makes one endif, then 16bits compares if ([ba+address] and not(ZZZZ))>YYYY. If yes, codes are executed (else code execution set to false).

3C_____1 ZZZZYYYY : Endif, then 16bits If greater (po) Makes one endif, then 16bits compares if ([po+address] and not(ZZZZ))>YYYY. If yes, codes are executed (else code execution set to false).

CST7 : 16bits (endif, then) If lower

2E______ ZZZZYYYY : 16bits If lower (ba) 16bits compares if ([ba+address] and not(ZZZZ))<YYYY.
If yes, codes are executed (else code execution set to false).

3E______ ZZZZYYYY : 16bits If lower (po) 16bits compares if ([po+address] and not(ZZZZ))<YYYY.
If yes, codes are executed (else code execution set to false).

2E_____1 ZZZZYYYY : Endif, then 16bits If lower (ba) Makes one endif, then 16bits compares if ([ba+address] and not(ZZZZ))<YYYY. If yes, codes are executed (else code execution set to false).

3E_____1 ZZZZYYYY : Endif, then 16bits If lower (po) Makes one endif, then 16bits compares if ([po+address] and not(ZZZZ))<YYYY. If yes, codes are executed (else code execution set to false).

I've never used these and am not entirely sure how they work...

EDIT:  I found that there IS "End IF" and "Else" in with the terminators
CST0 : Full Terminator

E0000000 XXXXYYYY : full terminator
It clears the code execution status.
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000

CST1 : Endif (+else)

E20000VV XXXXYYYY = endifs
Applies VV endifs.
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000

E21000VV XXXXYYYY = endifs + else
Applies VV endifs, and inverse the code execution status (="else").
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000

CST7 : End of Code

F0000000 00000000 = end of code handler It tells the code handler that there are no more codes in the code list. The code handler exits.

But I am absolutely clueless how to assemble this all together with a button activator :(

dcx2

#3
Look at the bottom of the codetypes doc, Code Type 7, Code Sub-Type 1

CST1 : Endif (+else)

E20000VV XXXXYYYY = endifs
Applies VV endifs.
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000

E21000VV XXXXYYYY = endifs + else
Applies VV endifs, and inverse the code execution status (="else").
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000


...hm, now that I look at this, I'm not sure cascading else's will work properly.  Try this instead

tmp = 14;
if (val > 14) tmp = 29;
if (val > 29) tmp = 44;
if (val > 44) tmp = 45;
val = tmp;

For tmp, you can use a gecko register.

Have you considered asm, like a C2 code-type?  The code might end up being shorter.

EDIT: to add a button activator, change the last line to
if (button_pressed) val = tmp;

Every frame you will calculate tmp, but you actually only move tmp into val if your button is activated

Dude

I did consider using assembly, but I have ZERO knowledge of it and don't even know where to start :p

I do have more of an understanding of conditionals and feel I should try to find some compromise using this method first...

If it's ok, would it be possible for you to post a few examples of using the 16bit if code type?  E.G.  Using 80123456 00000000 as the test address and checking if it's less than 15 and writing in 14.  Also, perhaps using the End If + Else type?

Thank you so much for your help so far.  If I can use a few examples as a base then I might be able to figure out and even test adding in button activators and possibly stacking...

dcx2

80000007 0000000E                 # pre-load gr7 with 14
2C123456 0000000E                 # 16-bit if > 14
80000007 0000001D                 # load gr7 with 29
2C123457 0000001D                 # end if (note 7 instead of 6!), if > 29
80000007 0000002C                 # load gr7 with 44
2C123457 0000002C                 # end if, if > 44
80000007 0000002D                 # load gr7 with 45
28_____1 0000wxyz                 # end if, if buttons equal, ___ is address, wxyz are buttons
84100007 80123456                  # 16-bit write gr7 into val if buttons were activated
E0000000 80008000                  # end if

use 8420 instead of 8410 to write a 32-bit value from the gr into your memory cell.  Use 24 instead of 2C for 32-bit if >.  When doing 16-bit reads/writes, make sure you're reading/writing the correct half-word.

Dude

You are an absolute star, dcx2!

This is a more complete example than I expected.  It's so much clearer now seeing it laid out, but there are a few things that I'm not entirely sure about...

you used the If Greater Than 2C______ ZZZZYYYY.  I'm not sure if this is right for what I need, so I'll try the If Less Than 2E______ ZZZZYYYY for the example and alter it to how I HOPE it would work.

The register (gr7) is part of the actual Geckos code and not part of Wiis memory?  Or is it using the Wiis memory register to store the value?  It's just that I've done similar kind of things using CheatEngine and think that you need to "backup" what was previously in the register and then "restore" it after the code has completed.  Does this apply to here?  And/Or is this particular register safe for general usage? I.E. it's universal to every game.

I also have multiple addresses that I'd like to do this operation on, with altered values to pop into the register.  Is it possible to use the single button activator to manipulate multiple addresses?

2E123456 0000000E                 # 16-bit if < 14
80000007 0000000E                 # load gr7 with 14
2E123457 0000001D                 # end if (note 7 instead of 6!), if < 29
80000007 0000001D                 # load gr7 with 29
2E123457 0000002C                 # end if, if < 44
80000007 0000002C                 # load gr7 with 44
28_____1 0000wxyz                 # end if, if buttons equal, ___ is address, wxyz are buttons
84100007 80123456                  # 16-bit write gr7 into val if buttons were activated
2E234567 00000004                 # 16-bit if < 4
80000007 00000004                 # load gr7 with 4
2E234568 00000009                 # end if (note 7 instead of 6!), if < 9
80000007 00000009                 # load gr7 with 9
2E234568 0000000E                 # end if, if < 14
80000007 0000000E                 # load gr7 with 14
28_____1 0000wxyz                 # end if, if buttons equal, ___ is address, wxyz are buttons (Use the same button activator)
84100007 80234567                  # 16-bit write gr7 into val if buttons were activated
E0000000 80008000                  # end if

Would this example work?

dcx2

#7
Quote from: Dude on March 03, 2010, 05:44:03 PM
You are an absolute star, dcx2!
*points to "Thank You" button*   ;D

Quoteyou used the If Greater Than 2C______ ZZZZYYYY.  I'm not sure if this is right for what I need, so I'll try the If Less Than 2E______ ZZZZYYYY for the example and alter it to how I HOPE it would work.
If you do less than, make sure you test the largest value first.  If you test the smaller values first, then your larger values will always be true.

For example, assume the value you're reading was 22.  Is 22 < 14?  No, turn off code execution until we hit an end if.  Next, is 22 < 29?  Yes, set gr7 to 29.  Next, is 22 < 44?  Yes, set gr7 to 44.

You would need to rearrange them.  Is 22 < 44?  Yes, set gr7 to 44.  Is 22 < 29?  Yes, set gr7 to 29.  Is gr7 < 14?  No.

That's why I purposely wrote mine with >'s.  Is 22 > 14?  Yes, set gr7 to 29.  Is 22 > 29?  No.  Is gr7 > 44?  No.  Two ways to skin a cat.

QuoteThe register (gr7) is part of the actual Geckos code and not part of Wiis memory?
It's not a register in the classical sense, like r0 (or eax, if you used x86 asm).  Gecko OS reserves a chunk of memory low in the 80000000 range.  The Gecko Registers are just chunks of memory (80001808 is where they start, I believe).  

QuoteI've done similar kind of things using CheatEngine and think that you need to "backup" what was previously in the register and then "restore" it after the code has completed.
If you were writing an asm code, then you would have to watch out for that (or use a register that doesn't have any dependencies at that point in the program).  Gecko Registers are only used by Gecko OS, so you would only need to push/pop the value in a gecko register if some other code was using the same register.

QuoteI also have multiple addresses that I'd like to do this operation on, with altered values to pop into the register.  Is it possible to use the single button activator to manipulate multiple addresses?
Your button activator can be multiple execution lines between it and the end if, but you'll need one gecko register for each value, unless you're writing the same value to multiple places.

EDIT:

Okay, since this gecko register is only holding a temporary value, you could re-use it.  If you needed the value to be remembered between frames, you would need to use a different gecko register.

However, besides for your example testing numbers in the wrong order, your second set of if's are totally wrong.  The last bit of the address CANNOT be a 1, for two reasons.

1) The last bit of an if code-type's address is used to signify an end-if.
2) You would be doing an un-aligned read.  If you want to read a 16-bit half-word, your address MUST be a multiple of 2.  This requirement is why the least significant bit (LSbit) can be used for an end-if.

Dude

I've clicked your applaud button and intend to click it again - I didn't have a good enough idea about how to use the IF conditionals until now ;D

Hmm, I walked into the same trap that I mentioned that I wanted to avoid in my earlier post about the logical order of the value tests lol  I should consider getting some sleep soon  :p

I had assumed that the registers operated in the same style as I had encountered on the PC.  It was a bit of a headache jumping through hoops to manage them and that is why I avoided them until I understood the inner workings for the Wii better.  I have a lot of plans for these Gecko registers now...

Ok, about the endif, it's not possible to start a new if conditional while the current one is still active? (would a terminator for this resolve it if it is?)  Or it's because the example address just wouldn't work?

I'm sorry to keep bombarding you with questions :p  Everything else I now understand and can figure out.  It's just the ability of inserting a second set of new if statements that I'm fuzzy on.  Other than this, I'm all set to go ;D

dcx2

#9
Gecko "register" is a bit of a misnomer.  It's not a register in the sense of single-cycle memory inside the CPU.  For that matter, "if" is a bit of a misnomer, too.

The code handler reads every code during each frame.  If codes work by telling the code handler to turn off execution of codes for a little bit.

When the code handler encounters an if that resolves to true, it sets code execution status to true.  Any code the code handler reads will then be executed.

When it encounters an if that resolves to false, it sets code execution status to false.  Any codes that the code handler reads will NOT be executed.

End-ifs and full terminators reset code execution status to true.

So if you have a series of ifs separated by endifs, each one will always be tested every frame no matter what.  No if will have any effect on any other ifs.

If you have a series of ifs that are NOT separated by endifs, then it will be much like a logical AND.  If all of the ifs resolve true, then the code execution status will be true.  If ANY of the ifs resolve false, code execution status will be false, and the rest of the ifs and the associated codes will be skipped, until the code handler encounters an endif or terminator.

EDIT:

Examples: if-code-endif,if-code-terminator

2E123456 0000000E                 # 16-bit if < 14
80000007 0000000E                 # load gr7 with 14
2E123457 0000001D                 # end if (note 7 instead of 6!), if < 29
80000007 0000001D                 # load gr7 with 29
E0000000 80008000                 # terminator

If value < 14, then store 14 to gr7.
If value < 29, then store 29 to gr7.


if-if-code-terminator

2C123456 0000000E                 # 16-bit if > 14
2E123456 0000001D                 # (note 6!  NOT AN ENDIF), if < 29
80000007 0000001D                 # load gr7 with 29
E0000000 80008000                 # terminator

if (value > 14)
 if (value < 29)
   then store 29 into gr7

If value <= 14, the first if sets code execution status to false, the second if and code are not executed, and the terminator sets code execution status back to true.

If value >= 29, the second if sets code execution status to false, the code is not executed, and the terminator sets code execution status back to true.

If 14 < value < 29, both ifs will set code execution status to true, the code IS executed, and the terminator still sets code execution status to true, even though it's already true.

btw, your example two posts ago has another error.  You should have two terminators, not one.  Each if must always be matched with an endif or a terminator.

Dude

#10
Ohhhhhhhhh.

I was treating it like general code from programming.  It doesn't JUMP to the end of the if statement, it just tells Geckos to not execute the the following codes in the list while the execution status is set to false.

Ok.  I just have to make sure I place my logic in the correct order and ensure that I use the read address correctly (Im sure I'll be able to iron out any kinks related to this now) and I'm all set ;D ;D

I really can't thank you enough!  I'm gonna click your applaud button twice.  I had been pondering about creating codes like this for a game I'm currently working through for a while now but then couldn't get my head around how it all came together when I decided to look into it.

Thanks again, dcx2 :D

Edit:  Can't applaud you more than once in 15 hours.  Thought I could do it another two times lol  Whoops XD  I'll be checking back to this thread for reference tomorrow when I start to throw my codes together for testing, so I'll be sure to give you your second applaud then.  You more than deserve.

kenobi

Quote from: Dude on March 03, 2010, 02:17:30 PMExample:

80104920 00000000

I want to first check if this value is less than 15.  If it is, then set to 14.
I then want to check if it is between 15 and 30.  If it is, then set to 29.
I then want to check if it is between 30 and 45.  If it is, then set to 44.
All in the one button press.

This is an interessing question (and interessing answers).

The problem being to check a value against different ranges, and update that value accordingly.

There are of course many ways to achieve the effect you want.
As dc2x stated, using ifs/endifs/elseifs, along with storing the value in a gecko register (or copying it somewhere in RAM), is one way.

Another would be to code a small ASM routine (that solution could be used each time you wanna do something "complicated"). But in the end using ASM is "too easy" (once you know ASM, nothing can stop you, but you might stop understanding all the possibilities of the codes type and only rely on ASM).

So, as I liked your question, I tried to think of other ways to do it :

1) My first approach would be to mix if/endif and GOTO codes types.

Like that :

IF<45
  IF<30
    IF<15
      write 14
      goto terminator
    endif
    write 29
    goto terminator
  endif
  write 44
terminator


In term of code types, it should be something like this (of course, the button check code should be added at the very start of the code) :
2E104920 0000002D
2E104920 0000001E
2E104920 0000000F
02104920 0000000E
66000005 00000000
E2000001 00000000
02104920 0000001D
66000002 00000000
E2000001 00000000
02104920 0000002C
E0000000 80008000



2) One other 'interessing' way to do it would be to load the value in the Pointer, then use the offset 'if in range' codes. This will only work for direct RAM accesses (ie. not using pointers), and for values of 16bits (or less). To achieve this we first need to load the 16bits data in a gecko register(gr7 for exemple), then left shift it so it'll be placed in the upper 16bits, put it in the Pointer, and then do the Pointer range comparison (because the range comparison only looks for the upper 16 bits, as it was meant for memory range comparison). (here again, the button check code should be added at the very start of the code) :

82100007 80104920 <- load into gr7 the 16 bits at 0x80104920
86500007 00000010 <- left shifts gr7 by 16
4A001007 00000000 <- Pointer = gr7
DE000000 0000000F <- If PO>=0 and PO<15
02104920 0000000E <- writes 14 to 0x80104920
DE000001 000F001E <- Endif, If PO>=15 and PO<30
02104920 0000001D <- writes 29 to 0x80104920
DE000001 001E002D <- Endif, If PO>=30 and PO<45
02104920 0000002C <- writes 44 to 0x80104920
E0000000 80008000 <- Terminator

As you can see, this second method needs 3 lines to load the desired value into the Pointer, but it woud create smaller codes if you do a lot of comparisons as it uses 2 lines per new comparison, instead of 4 for the other method.


Of course all of this is only theorical (untested), so forgive me if anything I said is wrong (I haven't touched my wii or wiird since a good year...).

And the point of this post is not to confuse you, but to put in the light some "advanced" (=rarely used) codes type (that can be useful sometimes).

dcx2

Thanks obi-wan!

I had not considered using pointer bounds checks to make sure code is in a certain range.  That's definitely a clever idea, but will only work for 16 bit values.

I had also never seen goto in action.  Thank you for that, too.

QuoteBut in the end using ASM is "too easy" (once you know ASM, nothing can stop you

Quoted For Truth.  I develop ASM hacks almost exclusively...I find it much easier than pointer hacks because ASM doesn't move around (not quite the whole truth...in Resident Evil 4, the code that handles guns is "paged out" so that only the code for the gun you're currently using will be loaded into memory).  You can also do pretty much anything, especially once you learn to use C2 codes.  I've done some really, really cool stuff with C2 codes, like preventing the player's A button from working if they would miss an enemy.

Dude

You know, I think every possibly solution at pretty much every skill level has been covered for this problem!  :D

I also don't think that there are any tutorials and examples for creating codes using the "if" codetype (I know I couldn't find any).  I would definatley nominate both of you guys for this, though I think the content of this thread should suffice  ;D

I think I'll start with just using the "if" code type first and see if I can succeed, then try to work my way up to the ASM methods.

I agree that using ASM is the ultimate way to go since it's effectively just like writing raw code.  It has almost no barriers and opens up so many amazing possiblities...I just don't know enough about it yet lol  The closest I've gotten to this is using "code injection" in CheatEngine and using it's debugger to alter the way a game works.  Not able to create ASM gecko codes just yet :p

But thank you both so so much.  Lots more info and examples than I expected and I'm sure others are gonna benefit from it all too.  both applauded!

Romaap

If you need more tutorials, you could just check the Game Hacking Guides topic. ;)