Add Extra Item Options for 2 Player VS Mode
From Sonic Retro
(Original guide by E-122-Psi) (most coding provided by Cinossu.)
This was largely done in the Xenowhirl edit, though the variations in GitHub shouldn't be too hard to find.
The default 2 Player VS items options are bit too limited and randomised, so let's try adding an option for the normal 1 player item layout to benefit those with muscle memory, or if you wanna go extreme, no items at all.
Contents
Adding "Normal Items" Mode
Edit Menu
To add the option in the menu, first go to word_917A and change the Two_Player_Items flag to 2FF instead of 1FF (meaning a flag of now 0 (random), 1 (teleport) and 2 (normal)):
word_917A:
dc.w $2FF
dc.w Player_option ; 1
dc.w $2FF ; 2
dc.w Two_player_items ; 3
dc.w $7FFF ; 4
dc.w Sound_test_sound ; 5
Now go to off_92BA. Add 3 items instead of 2 in off_92EA and add your byte for the option.
off_92BA:
dc.l byte_97CA
dc.w $4192
dc.w 3
dc.l byte_982C
dc.w $4592
dc.w 3
dc.l byte_985E
dc.w $4992
dc.w 3
off_92D2:
dc.l byte_97DC
dc.l byte_97FC
dc.l byte_980C
off_92DE:
dc.l byte_97EC
dc.l byte_97FC
dc.l byte_981C
off_92EA:
dc.l byte_983E
dc.l byte_984E
dc.l byte_Fixed
off_92F2:
dc.l byte_9870
Now find the menu text for the options bytes and the one you've made, with the desired text.
; options screen menu text
byte_97CA: dc.b $10,"* PLAYER SELECT *"
byte_97DC: dc.b $E,"SONIC AND MILES"
byte_97EC: dc.b $E,"SONIC AND TAILS"
byte_97FC: dc.b $E,"SONIC ALONE "
byte_980C: dc.b $E,"MILES ALONE "
byte_981C: dc.b $E,"TAILS ALONE "
byte_982C: dc.b $10,"* VS MODE ITEMS *"
byte_983E: dc.b $E,"ALL KINDS ITEMS"
byte_984E: dc.b $E,"TELEPORT ONLY "
byte_Fixed: dc.b $E," NORMAL ITEMS "
byte_985E: dc.b $10,"* SOUND TEST *"
byte_9870: dc.b $E," 0"
dc.b $10," "
Now you should have your new option available, but it won't do anything, just give you teleport monitors.
Add function
To give it a unique function go to the monitor contents routine (Obj2E) and make a branch in loc_12868 or Obj2E_Init depending on disassembly:
loc_12868:
addq.b #2,routine(a0)
move.w #$8680,art_tile(a0)
bsr.w Adjust2PArtPointer
move.b #$24,render_flags(a0)
move.b #3,priority(a0)
move.b #8,width_pixels(a0)
move.w #-$300,y_vel(a0)
moveq #0,d0
move.b anim(a0),d0
tst.w (Two_player_mode).w
beq.s loc_128C6
cmp.w #2,(Two_player_items).w ; Is it fixed items?
beq.s loc_128C6
move.w (Timer_frames).w,d0
andi.w #7,d0 ;7 means 8 different items
addq.w #1,d0 ;add 1 to prevent getting static monitor
tst.w (Two_player_items).w ; Are monitors set to teleport only?
beq.s loc_128AC
moveq #8,d0 ;force contents to be teleport
loc_128AC:
cmpi.w #8,d0 ;teleport?
bne.s loc_128C2
move.b (Update_HUD_timer).w,d1
add.b (Update_HUD_timer_2P).w,d1
cmpi.b #2,d1 ;is either player finished?
beq.s loc_128C2
moveq #7,d0 ;give invincibility instead
loc_128C2:
move.b d0,anim(a0)
loc_128C6: ; Determine correct mappings offset.
......
With your new second flag branched over all the two player data edits, your monitors should now work normally....well almost.
Since two player by default displays a question mark, that is now loaded as the content when broken (which gives you nothing). You'll have to fix it the monitors to load their normal mappings in 2-player.
Go to loc_126E2 or Obj26_Init depending on your disassembly, and now add a check for the new items flag to branch over the ? icon implement:
loc_126E2:
move.b #$46,collision_flags(a0)
move.b subtype(a0),anim(a0)
tst.w (Two_player_mode).w
beq.s obj_26_sub_2
cmp.w #2,(Two_player_items).w ; Is it fixed items?
beq.s obj_26_sub_2
move.b #9,anim(a0) ;show ? screen
And hurrah, you should now have a fully functioning 'normal' item option mimicking one player layout.
Fix bug
If to a fault, since this setup obviously means there are no Tails 1-up monitors, only Sonic ones according to normal Sonic and Tails mode.
Now there are different ways of getting around this:
1. Make separate object edits for the 2P levels, and then editing them in a level editor to have an even balance of Sonic and Tails monitors.
2. Edit the monitor layouts, to give a 1-up to the character regardless. In which case, find the pointer list for the monitor contents (Obj2E again):
; ===========================================================================
sonic_1up:
cmp.w #2,(Two_player_items).w ; Is it fixed items?
bne.s sonic_1up_1P
cmpa.w #MainCharacter,a1
bne.s tails_1up
sonic_1up_1P:
addq.w #1,($FFFFFEF4).w
addq.b #1,(Life_count).w
addq.b #1,(Update_HUD_lives).w
move.w #$98,d0
jmp (PlayMusic).l ; Play extra life music
; ===========================================================================
tails_1up:
cmp.w #2,(Two_player_items).w ; Is it fixed items?
bne.s tails_1up_1P
cmpa.w #Sidekick,a1
bne.s sonic_1up
tails_1up_1P:
addq.w #1,($FFFFFEF6).w
addq.b #1,(Life_count_2P).w
addq.b #1,(Update_HUD_lives_2P).w
move.w #$98,d0
jmp (PlayMusic).l ; Play extra life music
; ===========================================================================
And now the monitor should give a 1-up to whoever breaks it in Normal Items mode, regardless of icon. Of course the monitor will still display Sonic's icon regardless, so you may want to edit the sprite art to have something more ambiguous.
Adding "No Items" Mode
Edit Menu
Most of this is just a repeat of before, go to word_917A and change the Two_Player_Items flag. If you already added the normal flag, this time change it to $3FF for 3 (no items):
word_917A:
dc.w $2FF
dc.w Player_option ; 1
dc.w $3FF ; 2
dc.w Two_player_items ; 3
dc.w $7FFF ; 4
dc.w Sound_test_sound ; 5
Go to off_92BA again and add the new byte for the option.
off_92BA:
dc.l byte_97CA
dc.w $4192
dc.w 3
dc.l byte_982C
dc.w $4592
dc.w 3
dc.l byte_985E
dc.w $4992
dc.w 3
off_92D2:
dc.l byte_97DC
dc.l byte_97FC
dc.l byte_980C
off_92DE:
dc.l byte_97EC
dc.l byte_97FC
dc.l byte_981C
off_92EA:
dc.l byte_983E
dc.l byte_984E
dc.l byte_Fixed
dc.l byte_None
off_92F2:
dc.l byte_9870
Now find the menu text for the options bytes again and add the new entry.
; options screen menu text
byte_97CA: dc.b $10,"* PLAYER SELECT *"
byte_97DC: dc.b $E,"SONIC AND MILES"
byte_97EC: dc.b $E,"SONIC AND TAILS"
byte_97FC: dc.b $E,"SONIC ALONE "
byte_980C: dc.b $E,"MILES ALONE "
byte_981C: dc.b $E,"TAILS ALONE "
byte_982C: dc.b $10,"* VS MODE ITEMS *"
byte_983E: dc.b $E,"ALL KINDS ITEMS"
byte_984E: dc.b $E,"TELEPORT ONLY "
byte_Fixed: dc.b $E," NORMAL ITEMS "
byte_None: dc.b $E," NO ITEMS "
byte_985E: dc.b $10,"* SOUND TEST *"
byte_9870: dc.b $E," 0"
dc.b $10," "
Add Function
Now this one is more simple, we just go to the start of the monitor routine, and make a branch to skip over all of it if the "No Items" flag is set:
; Obj_Monitor:
Obj26:
tst.w (Two_player_mode).w
beq.s Obj26_1P
cmp.w #3,(Two_player_items).w
bne.s Obj26_1P
rts
Obj26_1P:
moveq #0,d0
move.b routine(a0),d0
move.w obj_26_subtbl(pc,d0.w),d1
jmp obj_26_subtbl(pc,d1.w)
And there you go, no items load at all.
|Add Extra Item Options For 2 Player VS Mode]]