Adding difficulty modes

Discussion in 'Discussion and Q&A Archive' started by InfiniteWave, Apr 27, 2013.

Thread Status:
Not open for further replies.
  1. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    I had an idea just a moment ago, would it be possible to have the game load different level layouts depending on a variable that could be used for difficulty levels.

    Like say I change the second option in Sonic 2's option screen to Difficulty, and then add Easy Normal Hard ect... and when I go to play the game it would check the variable and load a specific level layout.

    Example: Normal difficulty will load EHZ_N and Hard will load EHZ_H
     
  2. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    Yes, it's certainly possible.  And you're along the right tracks on what you just said.  You can make it set a RAM address.  Say (Difficulty_mode).w could be #0 for easy, #1 for medium and #2 for Hard.  When loading layouts, you can make it check what this RAM is set to, and make it go to a different table for loading the layout.

    Loading the layouts are here in Sonic 2.  "loadLevelLayout:"  Here's a quick example I just quickly drew up that will give you the idea that might help (using xeno dis):


    loadLevelLayout:
    moveq #0,d0
    move.w (Current_ZoneAndAct).w,d0
    ror.b #1,d0
    lsr.w #6,d0
    lea (Off_Level).l,a0
    tst.b (Difficulty_mode).w ; Is it easy mode?
    beq.s + ; If so, branch and skip next few instructions
    lea (Off_Level_medium).l,a0 ; Load medium layouts into a0 instead
    cmpi.b #1,(Difficulty_mode).w ; Is it medium mode?
    beq.s + ; If so, branch and skip next instruction
    lea (Off_Level_hard).l,a0 ; Load hard layouts into a0 instead
    +
    move.w (a0,d0.w),d0
    lea (a0,d0.l),a0
    lea (Level_Layout).w,a1
    bra.w JmpTo_KosDec
    ; End of function loadLevelLayout

    You might have to do this in other places, I'm not too sure.  But you get my drift.
     
    Last edited by a moderator: Apr 27, 2013
  3. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    So I used your example but I need some help with changing the 2player items option into "Difficulty". I already changed the text (currently can only fit Easy and Normal) but I can't find the routine for it so it can change my Difficulty_mode variable.

    Basically I need help replacing the 2Player Items into Difficulty then after that I would need to add Off_Objects_medium and Off_Rings_medium and use the same set up as before.
     
  4. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    922
    Hg Disassembly:

    Under OptionScreen_Choices, each dc.l represents an option, for example



    dc.l (2-1)<<24|(Two_player_items&$FFFFFF)


    the 2 represents the total number of choices for that option.

    2007 Disassembly:

    Under word_917A, each pair of dc.w represent an option, for example



    dc.w $1FF ; 2dc.w Two_player_items ; 3



    the 1 represents the total number of choices for that option, minus one.
     
  5. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    I found this part and changed it but when I go to test it the game still loads the layout from off_level instead of Off_level_medium.

    Here's what mine looks like.


    word_917A:
    dc.w $2FF
    dc.w Player_option ; 1
    dc.w $1FF ; 2
    dc.w Difficulty_mode ; 3
    dc.w $7FFF ; 4
    dc.w Sound_test_sound ; 5

    I stored the Difficulty_mode variable in $FFFFFA80 in the ram. (since I started from a clean dissasembly)

    Code:
    Underwater_palette_2 = 	                ramaddr( $FFFFF000 ) ; not sure what it's used for but it's only used when there's water
    Underwater_palette = 		        ramaddr( $FFFFF080 ) ; main palette for underwater parts of the screen
    Underwater_palette_line4 = 	        ramaddr( $FFFFF0E0 )
    
    Difficulty_mode =                       ramaddr( $FFFFFA80 )  
    
    Game_Mode =			        ramaddr( $FFFFF600 ) ; 1 byte ; see GameModesArray (master level trigger, Mstr_Lvl_Trigger)
    Ctrl_1_Logical =		        ramaddr( $FFFFF602 ) ; 2 bytes
    
     
  6. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    922
    The level layout is different in medium right? And shouldn't the $1FF be $2FF if there are 3 difficulty modes?

    Other than that, I can't think of anything ...wait. redhotsonic's code uses Difficulty_mode as a byte, but I think the options menu uses it as a word. Try changing the tst.b and cmpi.b to tst.w and cmpi.w.
     
  7. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    I deleted hard mode for now so I only need easy and normal. I tried changing tst.w and cmpi.w but still no go.

    I notice that unlike Player Select and Sound Test Difficulty gets reset back to Easy if I press start on the sound test option which takes me back to the sega screen.

    What I mean is if I change the first option to Tails Alone and play a song in the sound test the game will remember that but if I change Easy to Normal it won't remember that and next time I go to the options menu it resets to Easy but everything else is still the same.

    EDIT: Yup I just did a search while playing the game and the value does reset back to 0 when you exit the options screen.
     
    Last edited by a moderator: Apr 28, 2013
  8. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    Obviously going in one player mode clears the value.  All you need to do is search your ASM file for all instances when using this RAM address and get rid (or comment out) the ones that clear the RAM.  So when you pick an option then go into the game, it won't clear.
     
  9. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    Nevermind I moved it to another address and it seems to work now.

    EDIT: ran into another problem.

    I can't get the game to load from Off_objects_medium and Off_rings_medium, I used your setup for Off_layout but it didn't work. So levels still have the normal object and rings placement.
     
    Last edited by a moderator: Apr 28, 2013
  10. SuperEgg

    SuperEgg I'm a guy that knows that you know that I know Member

    Joined:
    Oct 17, 2009
    Messages:
    Location:
    THE BEST GOD DAMN STATE OF TEXAS
    That's pretty easy actually.

    Go to "ObjPosLoad" and go to this line.


    lea (Off_Objects).l,a0

    And instead, replace it with this.


    cmpi.b #0,(whatever RAM).w
    beq.w LoadReg
    cmpi.b #1,(whatever RAM).w
    beq.w LoadEasy
    cmpi.b #2,(whatever RAM).w
    beq.w LoadHard
    LoadReg:
    lea (Off_Objects).l, a0
    beq.w Load_Obj_Sub1_Cont
    LoadEasy:
    lea (Off_ObjectsEasy).l,a0
    beq.w Load_Obj_Sub1_Cont
    LoadHard:
    lea (Off_ObjectsHard).l,a0
    Load_Obj_Sub1_Cont:  
    Apply to whatever they're supposed to be named. This code is actually adapted from my hack, Build-A-Burger. It uses the same concept when switching between layout, art, levels, ect.
     
  11. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    SuperEgg, why not this?
     


    lea (Off_Objects).l, a0 ; Load easy into a0
    tst.b (whatever RAM).w ; Is it easy mode?
    beq.s Load_Obj_Sub1_Cont ; If so, branch and carry on
    lea (Off_ObjectsMedium).l,a0; Not easy, load medium into a0
    cmpi.b #1,(whatever RAM).w ; Is it medium mode?
    beq.s Load_Obj_Sub1_Cont ; If so, branch and carry on
    lea (Off_ObjectsHard).l,a0 ; Not medium, it must be hard mode

    Load_Obj_Sub1_Cont:
    It's a lot quicker and smaller, and it's doing the exact same thing you just posted. Remember, try to use "tst" when you can rather than "cmpi #0" and "beq.s" rather than "beq.w".
     
    Last edited by a moderator: May 1, 2013
  12. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    Didn't work it still loads regular objects.
     
  13. SuperEgg

    SuperEgg I'm a guy that knows that you know that I know Member

    Joined:
    Oct 17, 2009
    Messages:
    Location:
    THE BEST GOD DAMN STATE OF TEXAS
    Did you try both methods? Are you certain that address isn't being used. Personally, I'd use $FFFFFFE9. It's free and there's nothing ever going to use it, except bitches.....Actually, try tst.w on RHS's code, or cmpi.w on mine.
     
  14. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    That fixed the objects but not the rings. I tried applying the same concept you guys did to fix the objects but it doesn't work and it loads the regular ring positions instead.
     
  15. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    Hm, can you show us your code for loading the rings please?
     
  16. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    loc_172A4:
        clearRAM Ring_Positions,$600
        ; d0 = 0
        lea    ($FFFFEF80).w,a1
        move.w    #bytesToLcnt($40),d1
    -    move.l    d0,(a1)+
        dbf    d1,-

        moveq    #0,d5
        moveq    #0,d0
        move.w    (Current_ZoneAndAct).w,d0
        ror.b    #1,d0
        lsr.w    #6,d0
        lea     (Off_Rings).l, a0
        cmpi.w    #0,(Difficulty_mode).w
        beq.w    LoadNormal
        cmpi.w    #1,(Difficulty_mode).w
        beq.w    LoadHard
    LoadNormal:
        lea     (Off_Rings).l, a0
        beq.w    +
    LoadHard:
        lea     (Off_Rings_medium).l,a0
    +
        move.w    (a1,d0.w),d0
        lea    (a1,d0.w),a1
        lea    ($FFFFE806).w,a2

    loc_172E0:
        move.w    (a1)+,d2
        bmi.s    loc_17328
        move.w    (a1)+,d3
        bmi.s    loc_17308
        move.w    d3,d0
        rol.w    #4,d0
        andi.w    #7,d0
        andi.w    #$FFF,d3

    loc_172F4:
        move.w    #0,(a2)+
        move.w    d2,(a2)+
        move.w    d3,(a2)+
        addi.w    #$18,d2
        addq.w    #1,d5
        dbf    d0,loc_172F4
        bra.s    loc_172E0
    ; ===========================================================================
    This causes the game not to load any rings for any stage and the first time the stage loads the camera is way off and Sonic automatically dies. Also to see if it worked I copied the ring layout for Hill Top, and the Difficulty_mode is stored in $FFFFFFE9 just like SuperEgg suggested.
     
  17. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    First of all, you've got Easy and normal laoding the same thing into a0. Also, try this instead:

    Code:
    ;	...
    	moveq	#0,d5
    	moveq	#0,d0
    	move.w	(Current_ZoneAndAct).w,d0
    	ror.b	#1,d0
    	lsr.w	#6,d0
    	lea	(Off_Rings).l, a1	; Load Easy rings
    	tst.w	(Difficulty_mode).w	; Easy mode?
    	beq.s	+			; If so, branch
    	lea	(Off_Rings_medium).l,a1	; Load Normal into a1
    	cmpi.w	#1,(Difficulty_mode).w	; Is it Normal mode
    	beq.s	+			; If so, branch
    	lea	(Off_Rings_hard).l,a1	; Load Hard into a1
    +
    	move.w	(a1,d0.w),d0
    ;	...
    EDIT: I know it's a huge time-line for an edit, but I just quickly looked over it and it's meant to be loaded into a1! Changed code above to apply a1. That's what I get for quickly rushing to solve your problem during my lunch break. That's probably why it hadn't been working for you.
     
    Last edited by a moderator: May 2, 2013
  18. InfiniteWave

    InfiniteWave Veteran Of The Arte & Sword Member

    Joined:
    Apr 18, 2013
    Messages:
    77
    Location:
    Visiting the Hakurei Shrine
    Alright I got it working, time to get to making the layouts.

    Thanks again.
     
  19. Dark Lips

    Dark Lips Well-Known Member Member

    Joined:
    Nov 14, 2008
    Messages:
    293
    Location:
    Wolverhampton UK
    this is all pretty interesting... I started to add something simular in my sonic redemption hack ages ago but it got canned when i started work on my sonic 2 hack.
     
  20. JoenickROS

    JoenickROS ROS (bug fixing in progress) Member

    Joined:
    Feb 5, 2012
    Messages:
    929
    Hmm could this concept be used to give different characters their own layouts, objects, and rings? If so this would make it easier to have good layouts for all characters and have them have to use their own various moves to get through an act/level without running into other characters paths. Knuckles paths would not be too short in my hack for example, his path for MCZ2 and shadows double jump would have a purpose. What Im worried about though is that the ROM could become too big.
     
    Last edited by a moderator: May 22, 2013
Thread Status:
Not open for further replies.