Jump to content

Sharing of cheat used in Raine


ffman1985

Recommended Posts

No rush... and I found a very particular crash here while testing something else, linux only, 32 bits only, and recent system updates only, it reminds me of the recent problems in windows with the cps2 driver. I committed a workaround in git, there doesn't seem to be a better fix for now.

edit : finally found the problem, it was rather tricky, sdl2 was using a SSE memcpy in this case, but starscream, the asm 68k emulator we use in 32 bits aligns the stack on 4 bytes boundaries, which seems reasonable, except that SSE requires 16 bytes boundaries for the stack ! Luckily there is a function attribute to ask for a stack realignment in this case, it saved the day. Still no rush though, I have other ideas but it will take some time.

Edited by Tux
Link to comment
Share on other sites

Update for Real Bout Fatal Fury Special (rbffspec.zip):

https://drive.google.com/file/d/1naLV90TyNSbpSHrd_3__W1IjU8wdm7Ah/view?usp=share_link

(temporary link, will be deleted if the script is included in the new version of Raine.)

The new version combine the vs mode and practice mode script into one called Console Mode Plus.

-In the menu, highlight 'Game Start' and press left or right to select vs mode and practice mode.

-In vs mode, it can now return to character select screen smoothly without relying on savestate.

-In practice mode, press start button to change character. There is no "Here come a new challenger" message after the update.

rbffspec.png

Edited by ffman1985
Link to comment
Share on other sites

Update for Street Fighter Alpha Phoenix Edition (sfad.zip):

https://drive.google.com/file/d/1FFksCbzAi1VUz_X1IP4dWu5AsRVeJf8O/view?usp=share_link

(temporary link, will be deleted if the script is included in the new version of Raine.)

 

There are several fixes:

-Prevent skipping the opening if the cheat is enabled at start up.

-In the menu, the text 'Akuma' or 'Gouki' is changed automatically according to region chosen.

-In akuma(gouki) mode, in case of akuma vs akuma, the cpu can have a different color from the player.

-In Dramatic Battle mode, the characters are automacally selected. This prevent player from choosing the alt. color and auto block which result in failing to enter the Dramatic Battle.

 

Besides the fixes, there are some new seperated cheats for Dramatic Battle (use together with the console mode). Considering that most people play the game alone for most time, I create the cheat called Single Dramatic Battle which allows to play singlely. There are 3 variations:

1. Play as Ryu and CPU as Ken

2. Play as Ken and CPU as Ryu

3. Control both Ryu & Ken instantaneously

All of these are actually quite challenging. For the first two, you may find the cpu partner is so weak and you may finally want to switching to the instantaneous mode. However, you may need some special practice first before winning the the battle. Please have a try on it.

P.S. These 3 cheats only support for controller 1 and you do not need the second controller for selection and continue.

 

sfad_000.jpg

Edited by ffman1985
  • Like 1
Link to comment
Share on other sites

After looking a little more at your scripts, some notes about optimizations :

when I added support for these scripts, I thought they would run only for 1 frame, and that's all.
But then mame introduced the "run:" part, where the scripts run as long as they are active, every frame. Yeah I had thought about that too for values which need to be poked every frame, like invulnerability, but simple stuff that's all, but sometimes it really became quite big.

And you beat them to the record of the big stuff which runs every frame ! But since you change the way the game works, you are forced to do it this way of course, it was just unexpected.
I chose this script system because it was easy to add, but in this kind of circumstances it's awfully inefficient, there is no compilation so all the lines in the script which are executed are interpreted all the time, and this every frame, so it means 60 times / second. At least we have crazily fast cpus now, so they can sustain the load, but here it's a lot of wasted cycles anyway...

So if you want to see the load of your script on the cpu, just switch to the profiler display (press f11 until you get some % displays on the upper right corner of the screen), the cheats appear in the misc section, it's always at 0% in normal operation...
Now some simple tricks you can use to lower the load : when changing the menu displayed on the screen, what is displayed stays, it doesn't have to be sent in every frame. So you can use a variable here like printed. Set it to 0 by default, then when you have displayed one entry set it to 1, so this entry won't be displayed again in the next frame. For xmcotar1d it produces something like this :

    if (dpeek(choice)==$0000)and((peek($FF4BAB)==$04)or(peek($FF$4BAD)==$04))
        dpoke choice $01FF
        printed=0
    endif
    if (dpeek(choice)==$0100)and((peek($FF4BAB)==$04)or(peek($FF$4BAD)==$04))
        dpoke choice $02FF
        printed=0
    endif

Oh yeah I also added
credits=$ff4bdd
choice=$ff2000
at the beginning of the script to be able to use variables here.
So this is the part where you navigate the menu and update the choice address with what you receive, for each update you set printed to 0. Then the display itself :
#Menu Text#
    if !printed
        poke $908E73 $14 #Text Color#
        poke $908EF3 $14

...
       if (peek(choice)==$00) #Arcade#
        poke $908E71 $20
        poke $908EF1 $41
        poke $908F71 $52
        poke $908FF1 $43
        poke $909071 $41
        poke $9090F1 $44
        poke $909171 $45
        poke $9091F1 $20
        printed=1
        endif
This way you set printed to 1 once Arcade has been displayed, so in the next frame it won't have to do it again.
The small drawback of this method is that if you exit this menu by an unexpected way like the f1 key to reset the game, next time you arrive to it, the computer will believe it's already displayed since printed will still be at 1. Well just press up or down key and the menu text appears again. It's a choice...
The if !printed finishes after the last entry has been displayed, so after Option here.

Anyway these are just some ideas, you can keep your script as it is if you prefer, I'll just have to find more complex ideas to work with this !
And if !printed means "if not printed", it's the way to write it in most languages like C, but you can do this in basic too... (except in basic it's "not " instead of ! alone).

Edited by Tux
Link to comment
Share on other sites

Hello, Tux, thank you for spending your time on reading my script and providing the way to optimise it. There are many instructions that I want it only operate once and then stop. For example, the change in text color in the menu, and all instructions involving rom hack (like the switch of control and the change of ‘press start’ text in the opening), etc. Can I use the printed at different area in my script to do so?

Also, I have set the conditions requirement for different part of instructions. For example, for the cheat to enable bosses, I use the if…endif  statement to make it only operate in the character select screen. However, does that mean that it will not affect the run during the actual game (during the battle)?

Similarly, as you can see, the script for different modes (vs mode, training mode, etc) are divided into group under the if..endif statement. If I play in the vs mode, it surely not operate the instructions  inside the training mode part, but can it still affect?

In short, I want to know, if there are too much if..endif statement, and the instructions inside is very long, can they still affect the run even the condition is not fulfilled?

Link to comment
Share on other sites

38 minutes ago, ffman1985 said:

Hello, Tux, thank you for spending your time on reading my script and providing the way to optimise it. There are many instructions that I want it only operate once and then stop. For example, the change in text color in the menu, and all instructions involving rom hack (like the switch of control and the change of ‘press start’ text in the opening), etc. Can I use the printed at different area in my script to do so?

Yes but careful if you use that on 2 scripts which can be activated at the same time : variables are global only for now so if they have the same name, they will collide.

38 minutes ago, ffman1985 said:

Also, I have set the conditions requirement for different part of instructions. For example, for the cheat to enable bosses, I use the if…endif  statement to make it only operate in the character select screen. However, does that mean that it will not affect the run during the actual game (during the battle)?

You have some useful instruction to check that : print_ingame. It works like this :
print_ingame number_of_frames text
so if you want to check if a part of a script remains active at a certain time, add something like

print_ingame 1 "message"

at the start of the section you want to check. If you see the message all the time, it means it's always active.
I am not sure I understood completely your question here, but this instruction should be useful anyway !

38 minutes ago, ffman1985 said:

Similarly, as you can see, the script for different modes (vs mode, training mode, etc) are divided into group under the if..endif statement. If I play in the vs mode, it surely not operate the instructions  inside the training mode part, but can it still affect?

In short, I want to know, if there are too much if..endif statement, and the instructions inside is very long, can they still affect the run even the condition is not fulfilled?

For now yes they do sadly. As I said the scripts are really not intended to be run this way and there is no optimization to jump a big section of an if whose condition is false, which means that it will still parse all the lines inside, but not execute them, so it will not take too much time, but it will still take some execution time.

I am thinking of a way to improve that, but for now that's how it works yeah.

By the way you can also use print_ingame to display variables, but it works like the printf command in C, so it's a little special : %d is replaced by the variable in integer form, while %c is replaced by the character whose ascii code is the value of the variable, %x is the value of the variable in hex, and so on. And contrary to what the internal help of the console says you can use this from the console, but in this case use a high number of frames to have the time to see the message, so you must do that with a loaded game, like this for example

a=3
print_ingame 120 "test a=%d" a

and you should see "test a=3" for 2 seconds (1 second is 60 frames) in the lower left corner of the screen when you close the console.
I hope it helps !

Edited by Tux
Link to comment
Share on other sites

I have some more question on printed. As I understand, it is something that cannot use multiple time in the same time. So, can I self defined some variable to deal with this function? For example, I set something like these:

stopper1, stopper2, stopper3, etc

and i set them equal to 0 or 1 at the appropriate time.

Link to comment
Share on other sites

11 minutes ago, ffman1985 said:

I have some more question on printed. As I understand, it is something that cannot use multiple time in the same time. So, can I self defined some variable to deal with this function? For example, I set something like these:

stopper1, stopper2, stopper3, etc

and i set them equal to 0 or 1 at the appropriate time.

yep as many variables as you like, no restriction, just once a variable is defined it stays there, any script can access it, even if you load another game it's still there, so just be careful that 2 scripts executed at the same time don't use 2 different variables with the same name, it wouldn't work.

Link to comment
Share on other sites

Some news : I finally committed the script for xmcotar1d, I don't think I'll change it a lot more now. One of the latest changes inside is that you can now poke directly the characters if they happen to use the ascii code, as is the case in this game obviously.

Except that there are the few variables added, the printed tests, and the whole thing is indented using a perl script. See it there : https://github.com/zelurker/raine/commit/3482f5b51a7bd8c9ba19896c5329d9fda546bc4a#diff-09023d1e9c13785c9473fd6277a4469afdae3fd95ddf7bf02d8a9a3b9dcbe2b1

You can use "view file" in the "..." menu, and then raw if you want to download it. But of course this script will work only with the git version of raine for now, you'll need to compile your version, or at least change back the poke which use character strings back to poke which use normal values !

Also I finally added something to preserve the parsed state of the script (for the run: section), it's not really compilation, but it speeds up things considerably. I am not finished with my ideas about this yet, but it's already a big improvement compared to what we had before (hoping I didn't add too many bugs !).

An example of this poke with characters :

poke $6B6F0 'PRESS START@'

or for arcade :

if (peek(choice)==$00) #Arcade#
                poke $908E71 ' '
                poke $908EF1 'A'
                poke $908F71 'R'
                poke $908FF1 'C'
                poke $909071 'A'
                poke $9090F1 'D'
                poke $909171 'E'
                poke $9091F1 ' '


And by the way it was a pretty neat trick to update the layer this way to display your text, especially with their weird layout.

By the way the text you put in rom, replacing "insert coin" by "press start", it's actually wrong, it's right only if you configure the game in free play mode (I didn't even verify if there is a free play mode in the service mode), but in the default normal mode you still need to insert a coin to arrive to the main menu and make your selection.

Edited by Tux
  • Like 1
Link to comment
Share on other sites

I reach the limit of what can be done in a "reasonable" way, that is I tried some pseudo byte code : almost no acceleration, I tried to keep marks to jump directly to the end of an if block when a condition is false, same thing, no effect or almost.

So now it appears the biggest slowdown seems to be about managing lines like :
if ((peek($FF4BAB)==$00)and(peek($FF4BAD)==$00))and(peek($FF2001)==$FF)

doesn't seem very impressive to me though, maybe it's because muparser works with doubles internally and so there are some crazy conversions behind the scene here, quite surprising because usually muparser is very fast and our modern cpus can handle double numbers almost like ints, I checked peek and dpeek and they are as fast as they can be, so I don't know. Maybe I missed something, for now I have no more ideas.

Oh well it was an interesting try at least !

The unreasonable way would be to redo a parser from scratch using ints this time and which keeps some pseudo byte code along the way, really too crazy here. Maybe some other ways like having an lua interface, but it would really be unreasonable just for that. I'll just stop here for now, I'll release the binary later.

The core code is more complex of course, but it still seems solid and error messages are much better now.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...