Ironically, I was going for a third =X I didn't, because he mentioned GitHub, and I don't know the equivalent names of labels etc. Didn't want to confuse the situation...
Well, that is the help I needed! Thank you very much both of you, I will get into it when I come back from uni.
Hi, I'm a newbie to this whole hacking business. I have some programming experience, but no reverse engineering experience. I got my hands on the Cheat Engine a little while ago and have been playing around the the cheat table for Sonic Adventure 2. Two general questions I have: 1. How hard is it to mod the default values a game writes for a variable? I want to make a modded copy of Sonic Adventure 2 that writes different values for the "Speed Modifier" variable for different characters. Is this possible with only the Cheat Engine by detecting what code writes to that variable? Is this something that would be easy for a newbie like me to learn or do I need super 'leet assembly coding skills or something like that? 2. Is it reasonably possible to port mods between the PC version and the PS3 version of Sonic Adventure 2, or any game for that matter? Like, could I make a modded .exe for the PC version of the game, then take that to the PS3 version? How about porting game saves between the two version? I actually tried dropping my PS3 SA2 save files renamed to the PC version's style of save game files in the save directory for the PC version, but the game couldn't read it saying the save file was corrupted.
1. That requires knowing where the game gets the initial value of the variable from. I don't know off the top of my head what the "Speed Modifier" in the cheat table is, but it's probably in the giant array of physics data for each character, which is known, and can be edited with a hex editor. 2. No. Save data may be ported between all the different versions of the game, if someone can find out exactly how each version formats the data.
^Thanks for answering. So, ideally I'd just need to do some hex editing? On a side note, can Cheat Engine be used for making mods like that or is CE generally only used for mid-game hacking? Also, porting mods between platforms of a game is never possible in some loose sense? I feel like the PC and PS3 versions of SA2 would be very similar. Is there any likelihood that I could do a minor hex edit on the .exe of the ps3 version (assuming I can get to it, which I'm pretty sure there are not-too-hard ways) in a similar way as the PC version to change the speed modifiers? And one last question: Does anyone know how the speed ramps are coded in SA2 (and SADX for that matter)? Are they scripted individually or can their properties be edited from some central location in the code? From my experience it seems possible that there are "versions" of speed ramps; fast ones and slower ones that if you hit at high speed actually slow you down.
1. Cheat Engine can only be used for mod making insofar as it allows you to trace the instructions that write to memory addresses, which you can then locate in the exe and modify/disable. 2. The PS3 uses completely different executable formats than Windows, not to mention a completely different processor. It's probably possible to modify it, but I have no clue how you would do it. 3. I would imagine that the speed and angle is controlled by the data in the SET files (use SETedit or DXEdit to edit them).
^Cool stuff. Thanks for the help so far. After foraging around a bit I see there's a lot of tools that I didn't take a good look at before besides SETedit and DXedit, like your SA Tools pack. Only thing is I'm a little unclear on how to use any of these tools. So far snooping around on Google and on the forums here I've only been able to find sparse snippets on how SA2 modding works in general. For example I tried opening a .pak file in PAKEdit, but it just kept giving me errors. So far I can't make any sense out of the set files when I open them in SETEdit. Is there anywhere specifically I can learn more about SA2 modding basics? I've looked around the SA2 modding topic a bit but it seemed more like a discussion among veteran hackers on how to hack the game more, which is a bit confusing for a noob like me.
PAKEdit only works with .pak files in the PRS folder, which are designed to mimic the PRS-compressed GVM files used for textures; the .pak files in the SOC folder don't do that, and can only be used with PAKtool. SA2 modding is relatively new and basic compared to SADX. There isn't a lot of information out there. For SET editing, the wiki has a page, but only lists object IDs for City Escape. Finding the IDs for other levels requires finding the object list in the EXE and/or a lot of screwing around with the objects to see what's what.
I'm working on a little macro, something that I've never really done before. The macro is a converter to simplify ASCII-to-Hex inputs of a custom text type. Something like this (taken from the creditsText macro and slightly changed): Code (ASM): itext macro text c := 0 rept strlen(text) t := (substr(text,c,1)) dc.w $8000|(t-4) c := c+1 endm endm itext "SOME TEXT" Sounds simple enough, right? Unfortunately, it appears as though AS can't convert ASCII characters on the fly into integers, so I'm getting a ton of invalid operand type errors, as it obviously can't "substract 4 from S". I tried val(), but that didn't work. Is there any other instruction to convert the character into an integer?
Is anyone experienced with object loading in Sonic's routine of S1?: Code (Text): ; --------------------------------------------------------------------------- ; Subroutine for Sonic's hammer spin animation ; --------------------------------------------------------------------------- ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| Sonic_HammerSpin: move.b ($FFFFF603).w,d0 ; move the current button press to d0 btst #1,($FFFFF602).w ; is Down button pressed? beq.s HS_End1 ; if not, return and.b #$40,d0 ; get only button A beq.s HS_End1 ; if A was pressed, branch tst.b ($FFFFFFCC).w ; was jumpdash flag set? beq.s HammerSpin_Cont ; if yes, branch HS_End1: rts HammerSpin_Cont: move.b #1,($FFFFFFCC).w ; if not, set jumpdash flag move.b #$20,$1C(a0) ; show hammer animation move.w #$BC,d0 ; set jumpdash sound jsr (PlaySound).l ; play jumpdash sound HammerSpin_Hearts1: cmpi.b #1,$1B(a0) bcs.s HammerSpin_Hearts2 ; if not, branch bsr.w SingleObjLoad bne.w HammerSpin_Hearts2 move.b #$10,(a1) ;Obj10 move.w 8(a0),8(a1) move.w $C(a0),$C(a1) sub.w #$20,8(a1) btst #0,$22(a0) beq.s HammerSpin_Hearts2 neg.w $10(a1) add.w #$40,8(a1) HammerSpin_Hearts2: cmpi.b #3,$1B(a0) bcs.s HammerSpin_Hearts3 ; if not, branch bsr.w SingleObjLoad2 bne.w HammerSpin_Hearts3 move.b #$10,(a1) ;Obj10 move.w 8(a0),8(a1) move.w $C(a0),$C(a1) sub.w #0,8(a1) btst #0,$22(a0) beq.s HammerSpin_Hearts3 neg.w $10(a1) add.w #0,8(a1) HammerSpin_Hearts3: cmpi.b #5,$1B(a0) bcs.s HS_End2 ; if not, branch bsr.w SingleObjLoad bne.w HS_End2 move.b #$10,(a2) ;Obj10 move.w 8(a0),8(a2) move.w $C(a0),$C(a2) add.w #$20,8(a2) btst #0,$22(a0) beq.s HS_End2 neg.w $10(a2) sub.w #$40,8(a2) HS_End2: clr.w $10(a0) ; clear X-velocity to move sonic directly down tst.w $12(a0) ; is Sonic moving upwards? bpl.s HS_End3 ; if not, branch clr.w $12(a0) ; clear X-velocity to move sonic directly down HS_End3: rts ; return ; End of function Sonic_HammerSpin Basically I want the objects to load with each frame of the player's animation so there is some delay, leaving a trail as the player moves. However in this form, you either only get all of them at the start of the animation or none at all.
@FeliciaVal (stupid Italians ninja'ing me :v: The thing is, it doesn't actually ever reach your code. In the beginning, you check if the necessary buttons are pushed and then check if the flag is set. Said flag gets set immediately when the buttons are pushed, during which the animation counter is far away from your desired frames. Since the comments mention "jumpdash", I assume the flag gets reset when touching the ground. Therefore, you should add a branch after the check for the flag to continue to your hearts: Code (ASM): ... tst.b ($FFFFFFCC).w ; was jumpdash flag set? beq.s HammerSpin_Cont ; if yes, branch bra.s HammerSpin_Hearts1 ; if not, we're in a HammerSpin - continue hearts sprite check HS_End1: rts ... @nineko: Flamewing has pointed out the correct instruction, which was "CharFromStr(input,size)". Of course it was mentioned in the manual, but without knowing the name you have no chance of finding it. Plus, it was for the updated AS assembler, not the 2007 one, so I was helpless anyway. "asc()" isn't known, btw.
Felicia Val? I'm E-122-Psi. And I'm British. :P Anyway, tried that code, but still has no effect. There is no order or delay in how they appear, they either all just appear at the start of the animation or not at all.
Oh my god, please excuse my brainfart there... :specialed:/> To make up for it (and also I don't really know where the problem is from here), I'm willing to give some private help on the matter. You can find in the #ssrg IRC.
I would actually load all three at the same time and have them wait for a timer that gets set right as their loaded, like this for example: [68k]TrailFrameDuration: = ; whatever the frame duration of your animation is Sonic_HammerSpin: tst.b ($FFFFFFCC).w ; was jumpdash flag set? beq HS_End3 ; if yes, branch move.b ($FFFFF603).w,d0 ; move the current button press to d0 btst #1,($FFFFF602).w ; is Down button pressed? beq.s HS_End3 ; if not, return and.b #$40,d0 ; get only button A beq.s HS_End3 ; if A wasn't pressed, branch HammerSpin_Cont: move.b #1,($FFFFFFCC).w ; set jumpdash flag move.b #$20,$1C(a0) ; show hammer animation move.w #$BC,d0 ; set jumpdash sound jsr (PlaySound).l ; play jumpdash sound bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.w 8(a0),d0 move.w $C(a0),$C(a1) subi.w #$20,d0 btst #0,$22(a0) beq @Set1stXPos neg $10(a1) addi.w #$40,d0 @Set1stXPos: move.w d0,8(a1) move.b #1*TrailFrameDuration,$2A(a1) bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.w 8(a0),8(a1) move.w $C(a0),$C(a1) btst #0,$22(a0) beq @Set2ndFrameDuration neg $10(a1) @Set2ndFrameDuration: move.b #3*TrailFrameDuration,$2A(a1) bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.w 8(a0),d0 move.w $C(a0),$C(a1) addi.w #$20,d0 btst #0,$22(a0) beq neg $10(a1) subi.w #$40,d0 @Set3rdXPos: move.w d0,8(a1) move.b #5*TrailFrameDuration,$2A(a1) HS_End2: clr.w $10(a0) ; clear X-velocity to move sonic directly down tst.w $12(a0) ; is Sonic moving upwards? bpl.s HS_End3 ; if not, branch clr.w $12(a0) ; clear X-velocity to move sonic directly down HS_End3: rts[/68k] Then you could just make the beginning of the object look like this: [68k]Obj10: subq.b #1,$2A(a0) bmi @Start rts @Start: ; object init stuff[/68k] Oh, whoops, Selbi's already helping. Eh, whatever, someone may get something out of this.
The problem with that method is that while it delays the animation, they still are all loaded at the same time and place, rather than following the player in a trail. I appreciate it very much, but I'll need to wait, on early morning shift so need to go bed right now.
Add this somewhere: [68k]asc function chr,charfromstr(chr,0)[/68k] Then go wild :v: (I told you user defined functions are great) In Shockwave677's code, add code to reposition the heart to the desired spot right after this label: [68k]@Start:[/68k] If you set the correct X position in HammerSpin_Cont, you probably just need to set the Y position based on Amy's position.
Ah, this seems to be having results, thanx. One thing, is there a way to keep this going on a loop for as long as the attack runs, like running this delay every two seconds until the animation stops? I take this is running on a timer rather than animation frame specifics now, so may be harder to program for such a routine. EDIT: Wait there seems to be an issue with this method. Putting a Y pos check in the object coding itself makes the player pos recognition static. It means I can't edit the Y position for one particular trail. Similarly the X position sticks and doesn't move with the player, if I add a check on the object data it means none of the objects can be positioned separately.
Well, hello again. I would like to say that I had succeed in my mission of adding frames, but that wouldn't be totaly true. Im having some serious problems with this thing, and its starting to really pissing me off. I sort of managed to make it work by making 16 frames instead of 14 (frames 6 & C had a duplicate each, making a 16 total). It work wonderfull, but part of me wasn't happy with such a lazy path, so now I stroke again. My logic was simple: If d0 is the angle of Sonic (0, 2, 4 or 6), and to load 6th frame the game does [68k] move.b d0,d1 lsr.b #1,d1 add.b d1,d0 [/68k] so basicaly what I think it does is d0 + (d0-1) if d0=/0, and d0+d0 if d0=0. (lsr is Logic Shift Right, does this sub 1 to d0 if it is not equal to 0?) then an extra command somewhere makes the final multiplication by 2, resulting in the desired frames. As I want 14 frames, this is my new nomodspeed label: [68k] @nomodspeed: lea (SonAni_raaan).l,a1 ; use fastah animation! cmpi.w #$F00,d2 ; is Sonic running fastah!? bcc.s @gofastah ; if yes, branch lea (SonAni_Run).l,a1 ; use running animation cmpi.w #$600,d2 ; is Sonic at running speed? bcc.s @running ; if yes, branch lea (SonAni_Walk).l,a1 ; use walking animation add.b d0,d0 ; x2 /0=0 2=4 4=8 6=C add.b d0,d0 ; x2 (x4) /0=0 2=8 4=10 6=18 lsr.b #1, d0 ; minus 1 if not 0 (x4-1) /0=0 2=7 4=1F 6=17 [/68k] What I want with this well... it is in the comments, then the aftermentioned extra command located somewhere makes the final multiplication, turning 0 into 0, 2 into 14 ($E), 4 into 28 ($1C) and 6 into 42 ($2A). But either the game is trolling me, or I don't understand LSR operation properly, or I have to retire from hacking. The game just loads bullshit when Sonic is walking in angles, most of them are sprites of Sonic running at random angles. Running animation works perfect, as it has 8 frames so that's easy to make. My other problem is within the 3rd animation. I want to introduce a new animation for when Sonic is running 'fastaah than evah!', wich it would be above his normal maximium speed. What's the problem then? When it loads, game frozes. The animation is defined at the end of the index to avoid changing other animation's indexes; same care was taken with its frames to avoid even more interference (I have enough interference already and hurt animation never loads, just frezees current frame 'till Sonic reachs the ground). Also, in the walking-running transition, rolling animation is shown for a short period, and I don't know why. What is that thing that I am not seeing now? I don't want to go back to the lazy solution... Edit: corrected some grammar that could make you eyes bleed.
I'm not sure if I fully understood what you're trying to achieve here, but one thing to be told right away, bit shifting has nothing to with subtraction. At all. Let's take a look at an example: Say we have $75 in d0. In bits that equals to (if we only look at that one byte): 0111 0101 Now, if we do a bit shift, in particular your mentioned "lsr", what happens internally is pretty much what it says on the tin: The bits get shifted. All bits that leave the range are getting thrown out (marked by the dark blue) and the freed up bits are filled up with 0's (marked by the green): 0011 1010 1 This equals to $3A, half of $75-1 (because the first bit was thrown out and the least significant bit is now a zero). "lsr" moves to the right (thus the result being roughly halved) and "lsl" moves to the left (thus the result being roughly doubled). If you want to a "subtract 1 if the current value is anything but zero", you should probably do something like this: Code (ASM): tst.b d1 ; is value zero? beq.s @Zero ; if yes, branch subq.b #1,d1 ; subtract 1 from d1 @Zero: ...
Okay I've got that previous move working, but I want to edit it. Thus far it makes a trail of the same object appear four times in a row with a specific animation: Code (ASM): ; --------------------------------------------------------------------------- ; Subroutine for Sonic's hammer spin animation ; --------------------------------------------------------------------------- ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| Sonic_HammerSpin: move.b ($FFFFF603).w,d0 ; move the current button press to d0 btst #1,($FFFFF602).w ; is Down button pressed? beq.s HS_End1 ; if not, return and.b #$40,d0 ; get only button A beq.s HS_End1 ; if A was pressed, branch tst.b ($FFFFFFCC).w ; was jumpdash flag set? beq.s HammerSpin_Cont ; if yes, branch ;bra.s HammerSpin_Hearts HS_End1: rts HammerSpin_Cont: move.b #1,($FFFFFFCC).w ; set jumpdash flag move.b #$20,$1C(a0) ; show hammer animation move.w #$BC,d0 ; set jumpdash sound jsr (PlaySound).l ; play jumpdash sound HammerSpin_Hearts: cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation? bne.w HS_End2 ; if not, return bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.l 8(a0),d0 move.l $C(a0),$C(a1) move.b #0,$1C(a1) btst #0,$22(a0) beq @Set1stXPos neg $10(a1) move.b #2,$1C(a1) @Set1stXPos: move.b #0*2,$2A(a1) cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation? bne.w HS_End2 ; if not, return bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.l 8(a0),8(a1) move.l $C(a0),$C(a1) move.b #1,$1C(a1) @Set2ndFrameDuration: move.b #2*2,$2A(a1) cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation? bne.w HS_End2 ; if not, return bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.l 8(a0),d0 move.l $C(a0),$C(a1) move.b #2,$1C(a1) btst #0,$22(a0) beq @Set3rdXPos neg $10(a1) move.b #0,$1C(a1) @Set3rdXPos: move.b #4*2,$2A(a1) cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation? bne.w HS_End2 ; if not, return bsr SingleObjLoad bne HS_End2 move.b #$10,(a1) move.l 8(a0),8(a1) move.l $C(a0),$C(a1) move.b #3,$1C(a1) @Set4thFrameDuration: move.b #6*2,$2A(a1) HS_End2: clr.w $10(a0) ; clear X-velocity to move sonic directly down tst.w $12(a0) ; is Sonic moving upwards? bpl.s HS_End3 ; if not, branch clr.w $12(a0) ; clear X-velocity to move sonic directly down HS_End3: rts What I want it to do is make a trail of these four objects in a never-ending loop until the player's animation changes. Any idea how to keep it going?