From be37772b29f9d8c0505617c0aa582f58d1501ea2 Mon Sep 17 00:00:00 2001 From: Pecusx Date: Fri, 5 May 2023 11:29:34 +0200 Subject: [PATCH] Prepare for C64 port --- C64/lib/C64SYS.ASM | 47 ++++ C64/lib/MACRO.ASM | 213 ++++++++++++++++++ scorchC64.asm | 546 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 806 insertions(+) create mode 100644 C64/lib/C64SYS.ASM create mode 100644 C64/lib/MACRO.ASM create mode 100644 scorchC64.asm diff --git a/C64/lib/C64SYS.ASM b/C64/lib/C64SYS.ASM new file mode 100644 index 0000000..9b3f0b6 --- /dev/null +++ b/C64/lib/C64SYS.ASM @@ -0,0 +1,47 @@ +vic_spr0_x = $D000 +vic_spr0_y = $D001 +vic_spr1_x = $D002 +vic_spr1_y = $D003 +vic_spr2_x = $D004 +vic_spr2_y = $D005 +vic_spr3_x = $D006 +vic_spr3_y = $D007 +vic_spr4_x = $D008 +vic_spr4_y = $D009 +vic_spr5_x = $D00A +vic_spr5_y = $D00B +vic_spr6_x = $D00C +vic_spr6_y = $D00D +vic_spr7_x = $D00E +vic_spr7_y = $D00F +vic_spr_hi_x = $D010 +vic_cr1 = $D011 +vic_raster = $D012 +vic_lp_x = $D013 +vic_lp_y = $D014 +vic_spr_ena = $D015 +vic_cr2 = $D016 +vic_spr_exp_y = $D017 +vic_mem = $D018 +vic_irq = $D019 +vic_irq_ena = $D01A +vic_spr_dp = $D01B +vic_spr_mcolor = $D01C +vic_spr_exp_x = $D01D +vic_spr_ss_col = $D01E +vic_spr_sd_col = $D01F +vic_border = $D020 +vic_bg_color0 = $D021 +vic_bg_color1 = $D022 +vic_bg_color2 = $D023 +vic_bg_color3 = $D024 +vic_spr_color1 = $D025 +vic_spr_color2 = $D026 +vic_spr0_color = $D027 +vic_spr1_color = $D028 +vic_spr2_color = $D029 +vic_spr3_color = $D02A +vic_spr4_color = $D02B +vic_spr5_color = $D02C +vic_spr6_color = $D02D +vic_spr7_color = $D02E diff --git a/C64/lib/MACRO.ASM b/C64/lib/MACRO.ASM new file mode 100644 index 0000000..9ff9cae --- /dev/null +++ b/C64/lib/MACRO.ASM @@ -0,0 +1,213 @@ + + + +.macro basic_start(addr) + + .word upstartEnd // link address + .word 10 // line num + .byte $9e // sys + + ?a=0 + ?b=0 + ?c=0 + ?d=0 + ?e=0 + + ?v = %%addr + + ift ?v>=10000 + ?a=?v/10000 + ?v=?v-(?a*10000) + eif + + ift ?v>=1000 + ?b=?v/1000 + ?v=?v-(?b*1000) + eif + + ift ?v>=100 + ?c=?v/100 + ?v=?v-(?c*100) + eif + + ift ?v>=10 + ?d=?v/10 + ?v=?v-(?d*10) + eif + + ?e=?v%10 + + dta ?a+$30,?b+$30,?c+$30,?d+$30,?e+$30 + + .byte 0 +upstartEnd + .word 0 // empty link signals the end of the program + +.endm + + +// +// Switch bank in VIC-II +// +// Args: +// bank: bank number to switch to. Valid values: 0-3. +// +.macro SwitchVICBank(bank) + // + // The VIC-II chip can only access 16K bytes at a time. In order to + // have it access all of the 64K available, we have to tell it to look + // at one of four banks. + // + // This is controller by bits 0 and 1 in $dd00 (PORT A of CIA #2). + // + // +------+-------+----------+-------------------------------------+ + // | BITS | BANK | STARTING | VIC-II CHIP RANGE | + // | | | LOCATION | | + // +------+-------+----------+-------------------------------------+ + // | 00 | 3 | 49152 | ($C000-$FFFF)* | + // | 01 | 2 | 32768 | ($8000-$BFFF) | + // | 10 | 1 | 16384 | ($4000-$7FFF)* | + // | 11 | 0 | 0 | ($0000-$3FFF) (DEFAULT VALUE) | + // +------+-------+----------+-------------------------------------+ + ?bits=%11 + + ift (%%bank==0) + ?bits=%11 + eli (%%bank==1) + ?bits=%10 + eli (%%bank==2) + ?bits=%01 + eli (%%bank==3) + ?bits=%00 + eif + + // + // Set Data Direction for CIA #2, Port A to output + // + lda $dd02 + and #%11111100 // Mask the bits we're interested in. + ora #$03 // Set bits 0 and 1. + sta $dd02 + + // + // Tell VIC-II to switch to bank + // + lda $dd00 + and #%11111100 + ora #?bits + sta $dd00 +.endm + + +// +// Enter hires bitmap mode (a.k.a. standard bitmap mode) +// +.macro SetHiresBitmapMode + // + // Clear extended color mode (bit 6) and set bitmap mode (bit 5) + // + lda $d011 + and #%10111111 + ora #%00100000 + sta $d011 + + // + // Clear multi color mode (bit 4) + // + lda $d016 + and #%11101111 + sta $d016 +.endm + + +// +// Enter hires bitmap mode (a.k.a. standard bitmap mode) +// +.macro SetMulticolorBitmapMode + // + // Clear extended color mode (bit 6) and set bitmap mode (bit 5) + // + lda $d011 + and #%10111111 + ora #%00100000 + sta $d011 + + // + // Clear multi color mode (bit 4) + // + lda $d016 + ora #%00010000 + sta $d016 +.endm + + +// +// Switch location of screen memory. +// +// Args: +// address: Address relative to current VIC-II bank base address. +// Valid values: $0000-$3c00. Must be a multiple of $0400. +// +.macro SetScreenMemory(address) + // + // The most significant nibble of $D018 selects where the screen is + // located in the current VIC-II bank. + // + // +------------+-----------------------------+ + // | | LOCATION* | + // | BITS +---------+-------------------+ + // | | DECIMAL | HEX | + // +------------+---------+-------------------+ + // | 0000XXXX | 0 | $0000 | + // | 0001XXXX | 1024 | $0400 (DEFAULT) | + // | 0010XXXX | 2048 | $0800 | + // | 0011XXXX | 3072 | $0C00 | + // | 0100XXXX | 4096 | $1000 | + // | 0101XXXX | 5120 | $1400 | + // | 0110XXXX | 6144 | $1800 | + // | 0111XXXX | 7168 | $1C00 | + // | 1000XXXX | 8192 | $2000 | + // | 1001XXXX | 9216 | $2400 | + // | 1010XXXX | 10240 | $2800 | + // | 1011XXXX | 11264 | $2C00 | + // | 1100XXXX | 12288 | $3000 | + // | 1101XXXX | 13312 | $3400 | + // | 1110XXXX | 14336 | $3800 | + // | 1111XXXX | 15360 | $3C00 | + // +------------+---------+-------------------+ + // + ?bits = (%%address / $0400) << 4 + + lda $d018 + and #%00001111 + ora #?bits + sta $d018 +.endm + + +// +// Set location of bitmap. +// +// Args: +// address: Address relative to VIC-II bank address. +// Valid values: $0000 (bitmap at $0000-$1FFF) +// $2000 (bitmap at $2000-$3FFF) +// +.macro SetBitmapAddress(address) + // + // In standard bitmap mode the location of the bitmap area can + // be set to either BANK address + $0000 or BANK address + $2000 + // + // By setting bit 3, we can configure which of the locations to use. + // + + lda $d018 + + ift %%address == $0000 + and #%11110111 + eli %%address == $2000 + ora #%00001000 + eif + + sta $d018 +.end \ No newline at end of file diff --git a/scorchC64.asm b/scorchC64.asm new file mode 100644 index 0000000..854b222 --- /dev/null +++ b/scorchC64.asm @@ -0,0 +1,546 @@ +; @com.wudsn.ide.asm.mainsourcefile=scorch.asm +;C64 8-bit Scorched Earth source code +;--------------------------------------------------- +;by Tomasz 'pecus' Pecko and Pawel 'pirx' Kalinowski +;Warsaw 2000, 2001, 2002, 2003, 2009, 2012, 2013 +;Miami & Warsaw 2022, 2023 + +;--------------------------------------------------- +.def TARGET = C64 ; :) +;--------------------------------------------------- +.def XCORRECTION_FOR_PM = 0 +; if 1 - active x position of tanks correction fo PMG +.def FASTER_GRAF_PROCS = 0 +; if 1 - activates faster graphics routines +; (direct writes to screen memory - atari only :) ) +;--------------------------------------------------- + + + opt h-f+ + org $801 + org [a($801)],$801 + basic_start(START) + + +;--------------------------------------------------- +.macro build + dta d"1.28" ; number of this build (4 bytes) +.endm + +.macro RMTSong + lda #:1 + rts ; do nothing in C64 +.endm + +;--------------------------------------------------- + icl 'definitions.asm' +;--------------------------------------------------- + +FirstZpageVariable = $57 + .zpvar DliColorBack .byte = FirstZpageVariable + .zpvar GradientNr .byte + .zpvar GradientColors .word + .zpvar WindChangeInRound .byte ; wind change after each turn (not round only) flag - (0 - round only, >0 - each turn) + .zpvar JoystickNumber .byte + .zpvar LazyFlag .byte ; 7 bit - run Lazy Darwin, 6 bit - run Lazy Boy or Darwin (!) after inventory, 0 - nothing + .zpvar SpyHardFlag .byte ; >$7f - run SpyHard after inventory + .zpvar Vdebug .byte ; "visual debug" flag ($00 - off, $ff - on) + .zpvar xdraw .word ;= $64 ;variable X for plot + .zpvar ydraw .word ;variable Y for plot (like in Atari Basic - Y=0 in upper right corner of the screen) + .zpvar xbyte .word + .zpvar ybyte .word + .zpvar CharCode .byte + .zpvar fontind .word + .zpvar tanknr .byte + .zpvar TankSequencePointer .byte + .zpvar oldplot .word + .zpvar xc .word + .zpvar temp .word ;temporary word for the most embeded loops only + .zpvar temp2 .word ;same as above + .zpvar modify .word ;origially used to replace self-modyfying code + .zpvar tempXROLLER .word ;same as above for XROLLER routine (used also in result display routine) + .zpvar xtempDRAW .word ;same as above for XDRAW routine + .zpvar ytempDRAW .word ;same as above for XDRAW routine + .zpvar tempor2 .word + .zpvar CreditsVScrol .byte + ;--------------temps used in circle routine + .zpvar xi .word ;X (word) in draw routine + .zpvar fx .byte + .zpvar yi .word ;Y (word) in draw routine + .zpvar fy .byte + .zpvar xk .word + .zpvar fs .byte + .zpvar yc .byte ;ycircle - temporary for circle + .zpvar dx .word + .zpvar dy .word + .zpvar dd .word + .zpvar di .word + .zpvar dp .word + ;---------------------------- + .zpvar UnderTank1 .byte + .zpvar UnderTank2 .byte + ;---------------------------- + .zpvar TestFlightFlag .byte ; For AI test flights ($ff - test, $00 - standard shoot flight) + .zpvar weaponPointer .word + .zpvar dliCounter .byte + .zpvar pressTimer .byte + .zpvar NTSCcounter .byte + .zpvar IsEndOfTheFallFlag .byte ; for small speedup ground falling + .zpvar sfx_effect .byte + .zpvar RMT_blocked .byte + .zpvar ScrollFlag .byte + .zpvar SkStatSimulator .byte + .zpvar FloatingAlt .byte ; floating tank altitude + .zpvar OverTankDir .byte ; (0 go right, $ff go left) direction of bypassing tanks on screen + + ; --------------OPTIMIZATION VARIABLES-------------- + .zpvar Force .word + .zpvar Force_ .byte ; Force is 3 bytes long + .zpvar Angle .byte + .zpvar Parachute .byte ; are you insured with parachute? + .zpvar color .byte + .zpvar Erase .byte ; if 1 only mask of the character is printed + ; on the graphics screen. if 0 character is printed normally + .zpvar radius .byte + .zpvar decimal .word + .zpvar NumberOfPlayers .byte ;current number of players (counted from 1) + .zpvar Counter .byte ;temporary Counter for outside loops + .zpvar ExplosionRadius .byte + .zpvar FunkyBombCounter .byte + .zpvar ResultY .byte + .zpvar xcircle .word + .zpvar ycircle .word + .zpvar vy .word + .zpvar vy_ .word ; 4 bytes + .zpvar vx .word + .zpvar vx_ .word ; 4 bytes + .zpvar HitFlag .byte ;$ff when missile hit ground, $00 when no hit, $01-$06 tank index+1 when hit tank + .zpvar PositionOnTheList .byte ; pointer position on the list being displayed + .zpvar XHit .word + .zpvar delta .word + .zpvar HowMuchToFall .byte + .zpvar magic .word + .zpvar xtraj .word + .zpvar xtraj_ .byte ; 3 bytes + .zpvar ytraj .word + .zpvar ytraj_ .byte ; 3 bytes + .zpvar Wind .word + .zpvar Wind_ .word ; 4 bytes + .zpvar RangeLeft .word + .zpvar RangeRight .word + .zpvar NewAngle .byte + .zpvar escFlag .byte + .zpvar LineYdraw .byte + .zpvar LineXdraw .word + .zpvar plot4x4color .byte ; $00 / $ff + .zpvar Multiplier .word + .zpvar Multiplier_ .byte ; 3 bytes + .zpvar HowToDraw .byte + .zpvar gravity .byte + .zpvar LineLength .word + .zpvar tracerflag .byte + .zpvar isInventory .byte + .zpvar DifficultyLevel .byte + .zpvar goleft .byte + .zpvar OffsetDL1 .byte + .zpvar L1 .byte + HotNapalmFlag = FunkyBombCounter ; reuse variable! + ;* RMT ZeroPage addresses in artwork/sfx/rmtplayr.a65 + + displayposition = modify + LineAddress4x4 = xcircle + +;----------------------------------------------- +; libraries +;----------------------------------------------- + icl 'C64/lib/C64SYS.ASM' + icl 'C64/lib/MACRO.ASM' + +;----------------------------------------------- +; variable declarations in RAM (no code) +;----------------------------------------------- + ORG PMGraph + $0300 - (variablesEnd - OneTimeZeroVariables + 1) + icl 'variables.asm' + + ; Game loading address + ORG $4000 + +WeaponFont + ins 'artwork/weapons_AW6_mod.fnt' ; 'artwork/weapons.fnt' + + +;-------------------------------------------------- +; Game Code +;-------------------------------------------------- +FirstSTART + jsr MakeDarkScreen + + ; one time zero variables in RAM (non zero page) + lda #0 + ldy #OneTimeZeroVariablesCount-1 +@ sta OneTimeZeroVariables,y + dey + bpl @- + + ; one time zero variables in RAM (zero page) + ldy #FirstZpageVariable +@ sta $0000,y + iny + bne @- + + ; initialize variables in RAM (non zero page) + ldy #initialvaluesCount-1 +@ lda initialvaluesStart,y + sta variablesToInitialize,y + dey + bpl @- + + ; set gradient to the full LGBTIQQAAPP+ flag on start + mva #0 GradientNr ; #1 to set gradient number 2 :) (next one) + jsr SelectNextGradient.NotWind + + ; generate linetables + jsr GenerateLineTable + + + ; RMT INIT + lda #$f0 ;initial value + sta RMTSFXVOLUME ;sfx note volume * 16 (0,16,32,...,240) + + lda #$ff ;initial value + sta sfx_effect + + RMTSong 0 + + VMAIN VBLinterrupt,7 ;jsr SetVBL + + mva #2 chactl ; necessary for 5200 + +;-------------------------------------------------- +; Main program of the game + icl 'game.asm' +;-------------------------------------------------- + + +;-------------------------------------------------- +.proc GetKey +; waits for pressing a key and returns pressed value in A +; when [ESC] is pressed, escFlag is set +; result: A=keycode +;-------------------------------------------------- + jsr WaitForKeyRelease +@ + .IF TARGET = 800 + lda SKSTAT + cmp #$ff + beq checkJoyGetKey ; key not pressed, check Joy + cmp #$f7 ; SHIFT + beq checkJoyGetKey + .ELSE + lda SkStatSimulator + and #%11111110 + bne checkJoyGetKey ; key not pressed, check Joy + .ENDIF + lda kbcode + cmp #@kbcode._none + beq checkJoyGetKey + and #$3f ;CTRL and SHIFT ellimination + cmp #@kbcode._esc ; 28 ; ESC + bne getkeyend + mvy #$80 escFlag + bne getkeyend + +checkJoyGetKey + ;------------JOY------------- + ;happy happy joy joy + ;check for joystick now + lda STICK0 + and #$0f + cmp #$0f + beq notpressedJoyGetKey + tay + lda joyToKeyTable,y + bne getkeyend + +notpressedJoyGetKey + ;fire + lda STRIG0 + beq JoyButton + .IF TARGET = 800 ; Select and Option key only on A800 + bne checkSelectKey +checkSelectKey + lda CONSOL + and #%00000010 ; Select + beq SelectPressed + lda CONSOL + and #%00000100 ; Option + .ENDIF + bne @- +OptionPressed + lda #@kbcode._atari ; Option key + bne getkeyend +SelectPressed + lda #@kbcode._tab ; Select key + bne getkeyend +JoyButton + lda #@kbcode._ret ;Return key +getkeyend + ldy #0 + sty ATRACT ; reset atract mode + mvy #sfx_keyclick sfx_effect + rts +.endp + +;-------------------------------------------------- +.proc getkeynowait +;-------------------------------------------------- + jsr WaitForKeyRelease + lda kbcode + and #$3f ;CTRL and SHIFT ellimination + rts +.endp + +;-------------------------------------------------- +.proc WaitForKeyRelease +;-------------------------------------------------- + mva #128-KeyRepeatSpeed pressTimer ; tricky +StillWait + bit pressTimer + bmi KeyReleased + lda STICK0 + and #$0f + cmp #$0f + bne StillWait + lda STRIG0 + beq StillWait + .IF TARGET = 800 + lda SKSTAT + cmp #$ff + bne StillWait + lda CONSOL + and #%00000110 ; Select and Option only + cmp #%00000110 + bne StillWait + .ELSE + lda SkStatSimulator + and #%11111110 + beq StillWait + .ENDIF +KeyReleased + rts +.endp +;-------------------------------------------------- +.proc IsKeyPressed +; result: A=0 - yes , A>0 - no +;-------------------------------------------------- + lda SKSTAT + and #%00000100 + beq @+ + lda #1 +@ and STRIG0 + rts +.endp +;-------------------------------------------------- +.proc DemoModeOrKey +; Waits for the key pressed if at least one human is playing. +; Otherwise, waits 3 seconds (demo mode). +;-------------------------------------------------- + ;check demo mode + ldx numberOfPlayers + dex +checkForHuman ; if all in skillTable other than 0 then switch to DEMO MODE + lda skillTable,x + beq peopleAreHere + dex + bpl checkForHuman + ; no people, just wait a bit + ;pause 150 + ldy #75 + jsr PauseYFrames + rts +peopleAreHere + jmp getkey ; jsr:rts +.endp + +;-------------------------------------------------- +MakeDarkScreen +;-------------------------------------------------- + jsr PMoutofScreen ; hide P/M + mva #0 dmactls ; dark screen + ; and wait one frame :) +;-------------------------------------------------- +.proc WaitOneFrame +;-------------------------------------------------- + lda CONSOL + and #%00000101 ; Start + Option + sne:mva #$40 escFlag + and #%00000001 ; START KEY + seq:wait ; or waitRTC ? + rts +.endp + +;-------------------------------------------------- +.proc PauseYFrames +; Y - number of frames to wait (divided by 2) +; pauses for maximally 510 frames (255 * 2) +;-------------------------------------------------- +@ jsr WaitOneFrame + jsr WaitOneFrame + dey + bne @- + rts +.endp + +;-------------------------------------------------- +.proc RmtSongSelect +; starting song line 0-255 to A reg +;-------------------------------------------------- + cmp #song_ingame + bne noingame ; noMusic blocks only ingame song + bit noMusic + spl:lda #song_silencio +noingame + mvx #$ff RMT_blocked + ldx #MODUL ;hi byte of RMT module to Y reg + jsr RASTERMUSICTRACKER ;Init + mva #0 RMT_blocked + rts +.endp +;------------------------------------------------- +.proc CopyFromROM +;------------------------------------------------- +;copy from CART to RAM +; trashes: Y +; temp: source +; temp2: destination +; modify: destination-end +;usage: +; mwa #DisplayCopyRom temp +; mwa #display temp2 +; mwa #DisplayCopyEnd+1 modify +; jsr CopyFromROM + + ldy #0 +@ lda (temp),y + sta (temp2),y + inw temp + inw temp2 + cpw temp2 modify + bne @- + rts +.endp +;-------------------------------------------------- + icl 'C64/interrupts.asm' +;---------------------------------------------- + icl 'constants.asm' +;---------------------------------------------- + icl 'C64/textproc.asm' +;---------------------------------------------- + icl 'grafproc.asm' +;---------------------------------------------- + icl 'weapons.asm' +;---------------------------------------------- + icl 'ai.asm' +;---------------------------------------------- + icl 'artwork/talk.asm' +;---------------------------------------------- +TankFont + ins 'artwork/tanksv4.fnt',+0,384 ; 48 characters only +;---------------------------------------------- +font4x4 + ins 'artwork/font4x4s.bmp',+62 +;---------------------------------------------- +;RMT PLAYER loading shenaningans + icl 'artwork/sfx/rmtplayr_modified.asm' +;------------------------------------------------- +.proc CheckTankCheat + ldy #$07 + lda TankNr + asl + asl + asl ; 8 chars per name + tax +@ + lda CheatName,y + sec + sbc tanksnames,x + cmp #$27 + bne NoCheat + inx + dey + bpl @- +YesCheat + ldx TankNr + lda TanksWeaponsTableL,x + sta temp + lda TanksWeaponsTableH,x + sta temp+1 + lda #99 +@ iny + sta (temp),y + cpy #(number_of_weapons - 1) + bne @- +NoCheat + rts +.endp +CheatName + dta d" 008.T"+$27 +;---------------------------------------------- +.proc DLIinterruptBFG + pha + lda dliCounter + bne EndofBFGDLI + lda dliColorsFore + bit random + bmi @+ + lda DliColorBack +@ sta COLPF2 + lda dliColorsFore + bit random + bmi @+ + lda DliColorBack +@ sta COLPF1 +EndofBFGDLI + inc dliCounter + pla + rti +.endp +; ------------------------ +.proc BFGblink + SetDLI DLIinterruptBFG ; blinking on + ldy #50 + jsr PauseYFrames + SetDLI DLIinterruptGraph ; blinking off + rts +.endp +;-------------------------------------------------- + .IF * > MODUL-1 + .ECHO * + .ERROR 'Code and data too long' + .ENDIF + .ECHO "Bytes left: ",$b000-* + + + org $b000 ;address of RMT module +MODUL + ;RMT module is standard Atari binary file already + ins "artwork/sfx/scorch_str9-NTSC.rmt",+6 ;include music RMT module +MODULEND +;---------------------------------------------- + icl 'constants_top.asm' +;---------------------------------------------- + + .ECHO "Bytes on top left: ",$bfe8-* ;ROM_SETTINGS-* + .IF target = 5200 + .IF * > ROM_SETTINGS-1 + .ERROR 'Code and RMT song too long to fit in 5200' + .ENDIF + org ROM_SETTINGS ; 5200 ROM settings address $bfe8 + ; "01234567890123456789" + .byte " scorch supersystem " ;20 characters title + .byte " ", $ff ;$BFFD == $ff means diagnostic cart, no splash screen + .word FirstSTART + .ELSE + run FirstSTART + .ENDIF