lorom ; Custom addresses. Most are arbitrary. Feel free to make sure they're okay or moving them elsewhere within ZP CreditsPtr = $7C ; 3 bytes Temp = $B3 ; 2 bytes StatsBottom = $B5 ; 2 bytes StatsPtr = $B7 ; 3 bytes ValueLow = $BA ; 2 bytes ValueHigh = $BC ; 2 bytes Hours = $72 ; 2 bytes Minutes = $74 ; 2 bytes Seconds = $76 ; 2 bytes RemoveZero = $78 ; 2 bytes ; Original addresses LineNumber = $CA ; 2 bytes PreparePointer: LDA.w #$2300 STA.b CreditsPtr+1 LDA.w #CreditsLineTable STA.b CreditsPtr LDA.b [CreditsPtr],Y STA.b CreditsPtr LDY.w #$0000 RTL ; Regular stat: XXXX X00L LLLL LLLL BBBB SSSS CCC- ---- ---- ---- AAAA AAAA AAAA AAAA AAAA AAAA ; Time stat: XXXX X01L LLLL LLLL ---- ---- ---- ---- ---- ---- AAAA AAAA AAAA AAAA AAAA AAAA ; End of data: 1111 1111 1111 1111 ; X X offset (measured in 8x8 tiles) ; L Line number ; B Amount of bits to keep after shifting (0000 = 16 bits, 0001 = 1 bit, 1111 = 15 bits) ; S Amount of bits to right shift the value by (0000 = 0 bits, 1111 = 15 bits) ; C Value cap ; 000 No cap ; 001 9 ; 010 99 ; 011 999 ; 100 9999 ; A Memory Address ValueCaps: dw 0 dw 9 dw 99 dw 999 dw 9999 dw 9999 ; TODO - 5 digits need to be fixed at a later date BitMasks: dw $FFFF dw $0001 dw $0003 dw $0007 dw $000F dw $001F dw $003F dw $007F dw $00FF dw $01FF dw $03FF dw $07FF dw $0FFF dw $1FFF dw $3FFF dw $7FFF macro StripeStart(xPos, length) LDA.b $C8 CLC ADC.w # XBA STA.w $1002,x LDA.w #*2-1 XBA LDA.w #$0500 STA.w $1004,x endmacro macro StripeTile() STA.w $1006,x INX INX endmacro macro StripeEnd() INX INX INX INX endmacro HexToDecStats: PHA PHA LDA.w #$0000 STA.l HexToDecDigit1 : STA.l HexToDecDigit3 : STA.l HexToDecDigit4 ; clear digit storage PLA - CMP.w #10000 : !BLT + PHA : SEP #$20 : LDA.l HexToDecDigit1 : INC : STA.l HexToDecDigit1 : REP #$20 : PLA !SUB.w #10000 : BRA - + - CMP.w #1000 : !BLT + PHA : SEP #$20 : LDA.l HexToDecDigit2 : INC : STA.l HexToDecDigit2 : REP #$20 : PLA !SUB.w #1000 : BRA - + - CMP.w #100 : !BLT + PHA : SEP #$20 : LDA.l HexToDecDigit3 : INC : STA.l HexToDecDigit3 : REP #$20 : PLA !SUB.w #100 : BRA - + - CMP.w #10 : !BLT + PHA : SEP #$20 : LDA.l HexToDecDigit4 : INC : STA.l HexToDecDigit4 : REP #$20 : PLA !SUB.w #10 : BRA - + - CMP.w #1 : !BLT + PHA : SEP #$20 : LDA.l HexToDecDigit5 : INC : STA.l HexToDecDigit5 : REP #$20 : PLA !SUB.w #1 : BRA - + PLA RTL LastHexDigit: TYA AND.w #$000F PHA TYA LSR #4 TAY CLC LDA.b StatsBottom BNE + ; Upper half PLA ADC.w #$3D40 RTS + ; Lower half PLA ADC.w #$3D50 RTS FindLine: LDY.w #$0000 - LDA.w CreditsStats,y STZ.b StatsBottom CMP.w #$FFFF BEQ .noLine XBA AND.w #$01FF CMP.b LineNumber BEQ .lineFound INC INC.b StatsBottom CMP.b LineNumber BEQ .lineFound INY #8 BRA - .lineFound SEC RTS .noLine CLC RTS !FRAMES_PER_SECOND = 60 !FRAMES_PER_MINUTE = 60*60 !FRAMES_PER_HOUR = 60*60*60 !MAX_FRAME_COUNT = 59*60+59*60+59*60+99 macro CountUnits(framesPerUnit, unitCounter) STZ.b ?loop: LDA.b ValueLow SEC SBC.w # STA.b Temp LDA.b ValueHigh SBC.w #>>16 BCC ?end STA.b ValueHigh LDA.b Temp STA.b ValueLow INC.b BRA ?loop ?end: endmacro !ColonOffset = $8A !PeriodOffset = $4D BlankCreditsTile = $883D RenderCreditsStatCounter: PHB PHK PLB JSR FindLine BCS + JMP .endStats + ; XXXX X00L LLLL LLLL BBBB SSSS CCC- ---- ---- ---- AAAA AAAA AAAA AAAA AAAA AAAA ; == Determine stat type == LDA.w CreditsStats,y ; LLLL LLLL XXXX XTTL LSR AND.w #$0003 ; TT CMP.w #$0000 BEQ .normalStat JMP .timeStat .normalStat ; == Write Stripe header (VRAM address, i.e. tile coordinates) == LDA.w CreditsStats,y ; LLLL LLLL XXXX XTTL LSR #3 AND.w #$001F ; X XXXX CLC ADC.w $C8 XBA STA.w $1002,x ; == Write Stripe header (Length of data) == LDA.w #4*2-1 ; 4 tiles = 8 bytes XBA STA.w $1004,x PHX ; == Load tile base (upper or lower half of white two-line zero) == LDA.b StatsBottom BNE + LDA.w #$3D40 BRA ++ + LDA.w #$3D50 ++ STA.b Temp ; == Load the actual stat word == LDA.w CreditsStats+5,y STA.b StatsPtr LDA.w CreditsStats+6,y STA.b StatsPtr+1 LDA.b [StatsPtr] STA.b ValueLow ; == Shift value == LDA.w CreditsStats+2,y; CCC- ---- BBBB SSSS AND.w #$000F ; SSSS BEQ + TAX LDA.b ValueLow - LSR DEX BNE - STA.b ValueLow + ; == Mask value == LDA.w CreditsStats+2,y; CCC- ---- BBBB SSSS ;LSR #4 ;AND.w #$000F ; BBBB LSR #3 AND.w #$001E TAX LDA.l BitMasks,x AND.b ValueLow STA.b ValueLow ; == Cap value == LDA.w CreditsStats+3,y; ---- ---- CCC- ---- LSR #5 AND.w #$0007 ; CCC BEQ + ASL : TAX LDA.l ValueCaps,x CMP.b ValueLow !BGE + STA.b ValueLow + ; == Display value == LDA.b ValueLow JSL HexToDecStats PLX STZ.b RemoveZero LDA.l HexToDecDigit2 AND.w #$00FF CMP.b RemoveZero BNE + LDA.w #BlankCreditsTile BRA ++ + DEC.b RemoveZero CLC ADC.b Temp ++ %StripeTile() LDA.l HexToDecDigit3 AND.w #$00FF CMP.b RemoveZero BNE + LDA.w #BlankCreditsTile BRA ++ + DEC.b RemoveZero CLC ADC.b Temp ++ %StripeTile() LDA.l HexToDecDigit4 AND.w #$00FF CMP.b RemoveZero BNE + LDA.w #BlankCreditsTile BRA ++ + DEC.b RemoveZero CLC ADC.b Temp ++ %StripeTile() LDA.l HexToDecDigit5 AND.w #$00FF CLC ADC.b Temp %StripeTile() %StripeEnd() .endStats PLB RTL .timeStat ; Output format: HH:MM:SS.FF ; == Write Stripe header (VRAM address, i.e. tile coordinates) == LDA.w CreditsStats,y ; LLLL LLLL XXXX XTTL LSR #3 AND.w #$001F ; X XXXX CLC ADC.b $C8 XBA STA.w $1002,x ; == Write Stripe header (Length of data) == LDA.w #11*2-1 ; 11 tiles = 22 bytes XBA STA.w $1004,x PHX ; == Load the actual stat words == LDA.w CreditsStats+5,y STA.b StatsPtr LDA.w CreditsStats+6,y STA.b StatsPtr+1 LDA.b [StatsPtr] STA.b ValueLow INC.b StatsPtr INC.b StatsPtr LDA.b [StatsPtr] STA.b ValueHigh CMP.w #!MAX_FRAME_COUNT>>16+1 !BGE ++ ; == Convert total frames into hours, minutes, seconds and frames == %CountUnits(!FRAMES_PER_HOUR, Hours) %CountUnits(!FRAMES_PER_MINUTE, Minutes) %CountUnits(!FRAMES_PER_SECOND, Seconds) ; == Cap at 99:59:59.59 == LDA.b Hours CMP.w #100 !BLT + ++ LDA.w #99 STA.b Hours LDA.w #59 STA.b Minutes STA.b Seconds STA.b ValueLow + ; == Load tile base (upper or lower half of white two-line zero) == LDA.b StatsBottom BNE + LDA.w #$3D40 BRA ++ + LDA.w #$3D50 ++ STA.b Temp PLX ; == Display value == LDA.b Hours JSL HexToDecStats LDA.l HexToDecDigit4 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.l HexToDecDigit5 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.w #!ColonOffset CLC ADC.b Temp %StripeTile() LDA.b Minutes JSL HexToDecStats LDA.l HexToDecDigit4 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.l HexToDecDigit5 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.w #!ColonOffset CLC ADC.b Temp %StripeTile() LDA.b Seconds JSL HexToDecStats LDA.l HexToDecDigit4 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.l HexToDecDigit5 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.w #!PeriodOffset CLC ADC.b Temp %StripeTile() LDA.b ValueLow JSL HexToDecStats LDA.l HexToDecDigit4 AND.w #$00FF CLC ADC.b Temp %StripeTile() LDA.l HexToDecDigit5 AND.w #$00FF CLC ADC.b Temp %StripeTile() %StripeEnd() JMP .endStats RenderLineNumber: %StripeStart(0, 3) STZ.b StatsBottom LDA.b $CA TAY AND.w #$0001 BEQ + DEY INC.b StatsBottom + JSR LastHexDigit PHA JSR LastHexDigit PHA JSR LastHexDigit %StripeTile() PLA %StripeTile() PLA %StripeTile() %StripeEnd() RTS LoadCreditsTiles: JSL CopyFontToVRAM ; What we wrote over REP #$10 LDA.b #$80 : STA.w VMAIN LDA.b #$01 : STA.w DMAP0 LDA.b #$18 : STA.w BBAD0 ; Item tiles LDX.w #$8200 : STX.w VMADDL LDA.b #FileSelectNewGraphics>>16 : STA.w A1B0 LDX.w #FileSelectNewGraphics : STX.w A1T0L LDX.w #$0C00 : STX.w DAS0L LDA.b #$01 : STA.w DMAENABLE ; Small characters A-Z LDX.w #$7F00 : STX.w VMADDL LDA.b #SmallCharacters>>16 : STA.w A1B0 LDX.w #SmallCharacters : STX.w A1T0L LDX.w #$0200 : STX.w DAS0L LDA.b #$01 : STA.w DMAENABLE SEP #$10 RTL LoadOverworldCreditsTiles: JSL CopyFontToVRAM ; What we wrote over REP #$10 ; Small characters A-Z LDA.b #$80 : STA.w VMAIN LDA.b #$01 : STA.w DMAP0 LDA.b #$18 : STA.w BBAD0 LDA.b #SmallCharacters>>16 : STA.w A1B0 LDX.w #SmallCharacters : STX.w A1T0L LDX.w #$0200 : STX.w DAS0L LDX.w #$7F00 : STX.w VMADDL LDA.b #$01 : STA.w DMAENABLE SEP #$10 RTL CheckFontTable: TAY PHB PHK PLB LDA.w FontTable,Y PLB RTL NearEnding: STZ.w $012A ; disable triforce helper thread JSL LoadCustomHudPalette REP #$10 JSL AltBufferTable_credits JSR DrawEndingItems JML PaletteFilter_TheEndSprite EndingItems: ; This function is not strictly needed, simply updating the tracker ; every frame, but it is useful for debuging, so should be left in. REP #$10 JSR DrawEndingItems REP #$20 LDX.b #$0E RTL DrawEndingItems: JSL DrawPlayerFile_credits JSL SetItemLayoutPriority SEP #$30 LDA.b #$01 : STA.b NMISTRIPES RTS ;================================================================================ ; Dialog Pointer Override ;-------------------------------------------------------------------------------- EndingSequenceTableOverride: PHY PHX TYX LDA.l EndingSequenceText, X PLX STA.w $1008, X PLY RTL ;-------------------------------------------------------------------------------- EndingSequenceTableLookupOverride: PHX : PHB PHK : PLB TYX LDA.l EndingSequenceText, X : AND.w #$00FF ASL TAY LDA.w FontTable,Y PLB : PLX RTL ;--------------------------------------------------------------------------------