norom !headersize = 16 !controller_mirror = $23 !controller_flip = $27 ; only on first frame of input, used by crash man, etc !current_stage = $2A !received_stages = $8A !completed_stages = $8B !received_item_checks = $8C !last_wily = $8D !deathlink = $8F !energylink_packet = $90 !rbm_strobe = $91 !received_weapons = $9A !received_items = $9B !current_weapon = $A9 !stage_completion = $0F70 !consumable_checks = $0F80 !CONTROLLER_SELECT = #$04 !CONTROLLER_SELECT_START = #$0C !CONTROLLER_ALL_BUTTON = #$0F !PpuControl_2000 = $2000 !PpuMask_2001 = $2001 !PpuAddr_2006 = $2006 !PpuData_2007 = $2007 !LOAD_BANK = $C000 macro org(address,bank) if == $0F org
-$C000+($4000*)+!headersize ; org sets the position in the output file to write to (in norom, at least) base
; base sets the position that all labels are relative to - this is necessary so labels will still start from $8000, instead of $0000 or somewhere else org
-$8000+($4000*)+!headersize base
endif endmacro %org($8400, $08) incbin "mm2font.dat" %org($A900, $09) incbin "mm2titlefont.dat" %org($807E, $0B) FlashFixes: CMP #$FF BEQ FlashFixTarget1 CMP #$FF BNE FlashFixTarget2 %org($8086, $0B) FlashFixTarget1: %org($808D, $0B) FlashFixTarget2: %org($8015, $0D) ClearRefreshHook: ; if we're already doing a fresh load of the stage select ; we don't need to immediately refresh it JSR ClearRefresh NOP %org($802B, $0D) PatchFaceTiles: LDA !received_stages %org($8072, $0D) PatchFaceSprites: LDA !received_stages %org($80CC, $0D) CheckItemsForWily: LDA !received_items CMP #$07 %org($80D2, $0D) LoadWily: JSR GoToMostRecentWily NOP %org($80DC, $0D) CheckAccessCodes: LDA !received_stages %org($8312, $0D) HookStageSelect: JSR RefreshRBMTiles NOP %org($A315, $0D) RemoveWeaponClear: NOP NOP NOP NOP ;Adjust Password select flasher %org($A32A, $0D) LDX #$68 ;Block password input %org($A346, $0D) EOR #$00 ;Remove password text %org($AF3A, $0D) StartHeight: db $AC ; set Start to center %org($AF49, $0D) PasswordText: db $40, $40, $40, $40, $40, $40, $40, $40 %org($AF6C, $0D) ContinueHeight: db $AB ; split height between 2 remaining options %org($AF77, $0D) StageSelectHeight: db $EB ; split between 2 remaining options %org($AF88, $0D) GameOverPasswordText: db $40, $40, $40, $40, $40, $40, $40, $40 %org($AFA5, $0D) GetEquippedPasswordText: db $40, $40, $40, $40, $40, $40, $40, $40 %org($AFAE, $0D) GetEquippedStageSelect: db $26, $EA %org($B195, $0D) GameOverPasswordUp: LDA #$01 ; originally 02, removing last option %org($B19F, $0D) GameOverPassword: CMP #$02 ; originally 03, remove the last option %org($B1ED, $0D) FixupGameOverArrows: db $68, $78 %org($BB74, $0D) GetEquippedStage: JSR StageGetEquipped NOP #13 %org($BBD9, $0D) GetEquippedDefault: LDA #$01 %org($BC01, $0D) GetEquippedPasswordRemove: ORA #$01 ; originally EOR #$01, we always want 1 here %org($BCF1, $0D) GetEquippedItem: ADC #$07 JSR ItemGetEquipped JSR LoadItemsColor NOP ; !!!! This is a load-bearing NOP. It gets branched to later in the function LDX $FF %org($BB08, $0D) WilyProgress: JSR StoreWilyProgress NOP %org($BF6F, $0D) GetEquippedStageSelectHeight: db $B8 %org($805B, $0E) InitalizeStartingRBM: LDA #$FF ; this does two things STA !received_stages ; we're overwriting clearing e-tanks and setting RBM available to none %org($8066, $0E) BlockStartupAutoWily: ; presumably this would be called from password? LDA #$00 %org($80A7, $0E) StageLoad: JMP CleanWily5 NOP %org($8178, $0E) Main1: JSR MainLoopHook NOP %org($81DE, $0E) Wily5Teleporter: LDA $99 CMP #$01 BCC SkipSpawn %org($81F9, $0E) SkipSpawn: ; just present to fix the branch, if we try to branch raw it'll get confused %org($822D, $0E) Main2: ; believe used in the wily 5 refights? JSR MainLoopHook NOP %org($842F, $0E) Wily5Hook: JMP Wily5Requirement NOP %org($C10D, $0F) Deathlink: JSR KillMegaMan %org($C1BC, $0F) RemoveETankLoss: NOP NOP %org($C23C, $0F) WriteStageComplete: ORA !completed_stages STA !completed_stages %org($C243, $0F) WriteReceiveItem: ORA !received_item_checks STA !received_item_checks %org($C254, $0F) BlockAutoWily: ; and this one is on return from stage? LDA #$00 %org($C261, $0F) WilyStageCompletion: JSR StoreWilyStageCompletion NOP %org($E5AC, $0F) NullDeathlink: STA $8F ; we null his HP later in the process NOP %org($E5D1, $0F) EnergylinkHook: JSR Energylink NOP #2 ; comment this out to enable item giving their usual reward alongside EL %org($E5E8, $0F) ConsumableHook: JSR CheckConsumable %org($F2E3, $0F) CheckConsumable: STA $0140, Y TXA PHA LDA $AD ; the consumable value CMP #$7C BPL .Store print "Consumables (replace 7a): ", hex(realbase()) CMP #$76 BMI .Store LDA #$00 .Store: STA $AD LDA $2A ASL ASL TAX TYA .LoopHead: CMP #$08 BMI .GetFlag INX SBC #$08 BNE .LoopHead .GetFlag: TAY LDA #$01 .Loop2Head: CPY #$00 BEQ .Apply ASL DEY BNE .Loop2Head .Apply: ORA !consumable_checks, X STA !consumable_checks, X PLA TAX RTS GoToMostRecentWily: LDA !controller_mirror CMP !CONTROLLER_SELECT_START BEQ .Default LDA !last_wily BNE .Store .Default: LDA #$08 ; wily stage 1 .Store: STA !current_stage RTS StoreWilyStageCompletion: LDA #$01 STA !stage_completion, X INC !current_stage LDA !current_stage STA !last_wily RTS ReturnToGameOver: LDA #$10 STA !PpuControl_2000 LDA #$06 STA !PpuMask_2001 JMP $C1BE ; specific code that loads game over MainLoopHook: LDA !controller_mirror CMP !CONTROLLER_ALL_BUTTON BNE .Next JMP ReturnToGameOver .Next: LDA !deathlink CMP #$01 BNE .Next2 JMP $E5A8 ; this kills the Mega Man .Next2: print "Quickswap:", hex(realbase()) LDA #$00 ; slot data, write in enable for quickswap CMP #$01 BNE .Finally LDA !controller_flip AND !CONTROLLER_SELECT BEQ .Finally JMP Quickswap .Finally: LDA !controller_flip AND #$08 ; this is checking for menu RTS StoreWilyProgress: STA !current_stage TXA PHA LDX !current_stage LDA #$01 STA !stage_completion, X PLA TAX print "Get Equipped Music: ", hex(realbase()) LDA #$17 RTS KillMegaMan: JSR $C051 ; this kills the mega man LDA #$00 STA $06C0 ; set HP to zero so client can actually detect he died RTS Wily5Requirement: LDA #$01 LDX #$08 LDY #$00 .LoopHead: BIT $BC BEQ .Skip INY .Skip: DEX ASL CPX #$00 BNE .LoopHead print "Wily 5 Requirement:", hex(realbase()) CPY #$08 BCS .SpawnTeleporter JMP $8450 .SpawnTeleporter: LDA #$FF STA $BC LDA #$01 STA $99 JMP $8433 CleanWily5: LDA #$00 STA $BC STA $99 JMP $80AB LoadString: STY $00 ASL ASL ASL ASL TAY LDA $DB ADC #$00 STA $C8 LDA #$40 STA $C9 LDA #$F6 CLC ADC $C8 STA $CA LDA ($C9), Y STA $03B6 TYA CLC ADC #$01 TAY LDA $CA ADC #$00 STA $CA LDA ($C9), Y STA $03B7 TYA CLC ADC #$01 TAY LDA $CA ADC #$00 STA $CA STY $FE LDA #$0E STA $FD .LoopHead: JSR $BD34 LDY $FE CPY #$40 BNE .NotEqual LDA $0420 BNE .Skip .NotEqual: LDA ($C9), Y .Skip: STA $03B8 INC $47 INC $03B7 LDA $FE CLC ADC #$01 STA $FE LDA $CA ADC #$00 STA $CA DEC $FD BNE .LoopHead LDY $00 JSR $C0AB RTS StageGetEquipped: LDA !current_stage LDX #$00 BCS LoadGetEquipped ItemGetEquipped: LDX #$02 LoadGetEquipped: STX $DB ASL ASL PHA SEC JSR LoadString PLA ADC #$00 PHA SEC JSR LoadString PLA ADC #$00 PHA SEC JSR LoadString LDA #$00 SEC JSR $BD3E PLA ADC #$00 SEC JSR LoadString RTS LoadItemsColor: LDA #$7D STA $FD LDA $0420 AND #$0F ASL SEC ADC #$1A STA $FF RTS Energylink: LSR $0420, X print "Energylink: ", hex(realbase()) LDA #$00 BEQ .ApplyDrop LDA $04E0, X BEQ .ApplyDrop ; This is a stage pickup, and not an enemy drop STY !energylink_packet SEC BCS .Return .ApplyDrop: STY $AD .Return: RTS Quickswap: LDX #$0F .LoopHead: LDA $0420, X BMI .Return1 ; return if we have any weapon entities spawned DEX CPX #$01 BNE .LoopHead LDX !current_weapon BNE .DoQuickswap LDX #$00 .DoQuickswap: TYA PHA LDX !current_weapon INX CPX #$09 BPL .Items LDA #$01 .Loop2Head: DEX BEQ .FoundTarget ASL CPX #$00 BNE .Loop2Head .FoundTarget: LDX !current_weapon INX .Loop3Head: PHA AND !received_weapons BNE .CanSwap PLA INX CPX #$09 BPL .Items ASL BNE .Loop3Head .CanSwap: PLA SEC BCS .ApplySwap .Items: TXA PHA SEC SBC #$08 TAX LDA #$01 .Loop4Head: DEX BEQ .CheckItem ASL CPX #$00 BNE .Loop4Head .CheckItem: TAY PLA TAX TYA .Loop5Head: PHA AND !received_items BNE .CanSwap PLA INX ASL BNE .Loop5Head LDX #$00 SEC BCS .ApplySwap .Return1: RTS .ApplySwap: ; $F408 on old rom LDA #$0D JSR !LOAD_BANK ; this is a bunch of boiler plate to make the swap work LDA $B5 PHA LDA $B6 PHA LDA $B7 PHA LDA $B8 PHA LDA $B9 PHA LDA $20 PHA LDA $1F PHA ;but wait, there's more STX !current_weapon JSR $CC6C LDA $1A PHA LDX #$00 .Loop6Head: STX $FD CLC LDA $52 ADC $957F, X STA $08 LDA $53 ADC #$00 STA $09 LDA $08 LSR $09 ROR LSR $09 ROR STA $08 AND #$3F STA $1A CLC LDA $09 ADC #$85 STA $09 LDA #$00 STA $1B LDA $FD CMP #$08 BCS .Past8 LDX $A9 LDA $9664, X TAY CPX #$09 BCC .LessThanNine LDX #$00 BEQ .Apply .LessThanNine: LDX #$05 BNE .Apply .Past8: LDY #$90 LDX #$00 .Apply: JSR $C760 JSR $C0AB ; iirc this is loading graphics? LDX $FD INX CPX #$0F BNE .Loop6Head STX $FD LDY #$90 LDX #$00 JSR $C760 JSR $D2ED ; two sections redacted here, might need to look at what they actually do? PLA STA $1A PLA STA $1F PLA STA $20 PLA STA $B9 PLA STA $B8 PLA STA $B7 PLA STA $B6 PLA STA $B5 LDA #$00 STA $AC STA $2C STA $0680 STA $06A0 LDA #$1A STA $0400 LDA #$03 STA $AA LDA #$30 JSR $C051 .Finally: LDA #$0E JSR !LOAD_BANK PLA TAY .Return: RTS RefreshRBMTiles: ; primarily just a copy of the startup RBM setup, we just do it again ; can't jump to it as it leads into the main loop LDA !rbm_strobe BNE .Update JMP .NoUpdate .Update: LDA #$00 STA !rbm_strobe LDA #$10 STA $F7 STA !PpuControl_2000 LDA #$06 STA $F8 STA !PpuMask_2001 JSR $847E JSR $843C LDX #$00 LDA $8A STA $01 .TileLoop: STX $00 LSR $01 BCC .SkipTile LDA $8531,X STA $09 LDA $8539,X STA $08 LDX #$04 LDA #$00 .ClearBody: LDA $09 STA !PpuAddr_2006 LDA $08 STA !PpuAddr_2006 LDY #$04 LDA #$00 .ClearLine: STA !PpuData_2007 DEY BNE .ClearLine CLC LDA $08 ADC #$20 STA $08 DEX BNE .ClearBody .SkipTile: LDX $00 INX CPX #$08 BNE .TileLoop LDX #$1F JSR $829E JSR $8473 LDX #$00 LDA $8A STA $02 LDY #$00 .SpriteLoop: STX $01 LSR $02 BCS .SkipRBM LDA $8605,X STA $00 LDA $85FD,X TAX .WriteSprite: LDA $8541,X STA $0200,Y INY INX DEC $00 BNE .WriteSprite .SkipRBM: LDX $01 INX CPX #$08 BNE .SpriteLoop JSR $A51D LDA #$0C JSR $C051 LDA #$00 STA $2A STA $FD JSR $C0AB .NoUpdate: LDA $1C AND #$08 RTS ClearRefresh: LDA #$00 STA !rbm_strobe LDA #$10 STA $F7 RTS assert realbase() <= $03F650 ; This is the start of our text data, and we absolutely cannot go past this point (text takes too much room). %org($F640, $0F) db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" db $25, $4B, "PLACEHOLDER_L1" db $25, $6B, "PLACEHOLDER_L2" db $25, $8B, "PLACEHOLDER_L3" db $25, $EB, "PLACEHOLDER_PL" %org($FFB0, $0F) db "MM2_BASEPATCH_ARCHI "