From 56a756f0ba39d6509b91e064377db79ccbcba53c Mon Sep 17 00:00:00 2001 From: Pecusx Date: Mon, 8 May 2023 11:30:10 +0200 Subject: [PATCH] First C64 compilation --- C64/interrupts.asm | 2 +- C64/lib/MACRO.ASM | 61 ++- C64/textproc.asm | 1270 +------------------------------------------- scorchC64.asm | 27 +- scorchC64.prg | Bin 0 -> 35866 bytes 5 files changed, 90 insertions(+), 1270 deletions(-) create mode 100644 scorchC64.prg diff --git a/C64/interrupts.asm b/C64/interrupts.asm index e2bccab..9d9c188 100644 --- a/C64/interrupts.asm +++ b/C64/interrupts.asm @@ -2,7 +2,7 @@ .IF *>0 ;this is a trick that prevents compiling this file alone - +DLIinterruptGraph = 0 ;-------------------------------------------------- .macro SetDLI ; SetDLI #WORD diff --git a/C64/lib/MACRO.ASM b/C64/lib/MACRO.ASM index fcbb714..470397a 100644 --- a/C64/lib/MACRO.ASM +++ b/C64/lib/MACRO.ASM @@ -210,7 +210,7 @@ upstartEnd eif sta $d018 -.end +.endm // // Once this is done, random values appear in location $D41B (RANDOM) @@ -221,4 +221,63 @@ upstartEnd STA $D40F ; voice 3 frequency high byte LDA #$80 ; noise waveform, gate bit off STA $D412 ; voice 3 control register +.endm + +;------------------------------------- + .MACRO rolw + ROL :1 + ROL :1+1 + .ENDM +;------------------------------------- + .MACRO aslw + ASL :1 + ROL :1+1 + .ENDM +;------------------------------------- + .MACRO rorw + ROR :1+1 + ROR :1 + .ENDM +;------------------------------------- + .MACRO lsrw + LSR :1+1 + ROR :1 + .ENDM +;------------------------------------- + .macro randomize + ;usage: randomize floor ceiling + ;returns (in A) a random .byte between "floor" and "ceiling" + .if :2 < :1 + .error "floor higher than ceiling" + .endif +?rand + lda random + cmp #:1 ;floor + bcc ?rand + cmp #:2+1 ;ceiling + bcs ?rand + .endm +;------------------------------------- + .macro phx + txa + pha + .endm +;------------------------------------- + .macro phy + tya + pha + .endm +;------------------------------------- + .macro plx + pla + tax + .endm +;------------------------------------- + .macro ply + pla + tay + .endm +;------------------------------------- +.macro wait + nop .endm \ No newline at end of file diff --git a/C64/textproc.asm b/C64/textproc.asm index 0fd63d8..991f3aa 100644 --- a/C64/textproc.asm +++ b/C64/textproc.asm @@ -2,6 +2,9 @@ .IF *>0 + +WeaponsListDL = 0 +NamesOfLevels = 0 ;---------------------------------------- ; this module contains routines used in text mode ; like shop and start-up options @@ -16,112 +19,19 @@ ; - money each player has on the beginning of the game (moneyL i moneyH) ; - and I am sure maxwind, gravity, no_of_rounds in a game, speed of shell flight - jsr clearscreen ;let the screen be clean - mwa #DisplayCopyRom temp - mwa #display temp2 - mwa #DisplayCopyEnd+1 modify - jsr CopyFromROM - - mwa #OptionsDL dlptrs - - lda #%00111110 ; normal screen width, DL on, P/M on - sta dmactls - jsr SetPMWidth - mva #TextBackgroundColor COLOR2 - jsr ColorsOfSprites - mva #$ca COLOR1 - mva #$00 COLBAKS ; set color of background - - SetDLI DLIinterruptOptions ; jsr SetDLI for Options text screen - -; -------- setup bottom (tanks) line - lda NumberOfPlayers - pha - lda mountainsDeltaTableH - sta mountainDeltaH - lda mountainsDeltaTableL - sta mountainDeltaL - mva #6 NumberOfPlayers - jsr PMoutofScreen ;let P/M disappear - ;jsr clearscreen ;let the screen be clean (clean-ish already) - jsr ClearPMmemory - jsr placetanks ;let the tanks be evenly placed - jsr calculatemountains ;let mountains be easy for the eye - jsr drawmountains ;draw them - ldx NumberOfPlayers - dex -@ jsr RandomizeAngle - sta AngleTable,x + ldx #$08 +@ lda Autoplay_OptionsTable,x + sta OptionsTable,x dex bpl @- - jsr drawtanks ;finally draw tanks - pla - sta NumberOfPlayers -; -------- - mva #0 OptionsY + rts + +Autoplay_OptionsTable .by 4,4,2,2,4,1,3,2,4 -OptionsMainLoop - - lda WindChangeInRound - sta OptionsHere+126 - - jsr OptionsInversion - jsr getkey - bit escFlag - spl:rts - - cmp #@kbcode._down ; $f ;cursor down - bne OptionsNoDown - inc:lda OptionsY - cmp #maxoptions - bne OptionsMainLoop - mva #maxoptions-1 OptionsY - jmp OptionsMainLoop - -OptionsNoDown - cmp #@kbcode._up ; $e ;cursor up - bne OptionsNoUp - dec OptionsY - bpl OptionsMainLoop - mva #0 OptionsY - jmp OptionsMainLoop - -OptionsNoUp - cmp #@kbcode._left ; $6 ;cursor left - bne OptionsNoLeft - ldx OptionsY - dec OptionsTable,X - lda OptionsTable,X - bpl OptionsMainLoop - inc OptionsTable,X - jmp OptionsMainLoop - -OptionsNoLeft - cmp #@kbcode._right ; $7 ;cursor right - bne OptionsNoRight - - ldx OptionsY - inc OptionsTable,X - lda OptionsTable,X - cmp #5 ; number of columns in options - bne OptionsMainLoop - dec OptionsTable,X - jmp OptionsMainLoop - -OptionsNoRight - cmp #@kbcode._ret ; $c ;Return key - bne OptionsNoReturn - rts ; options selected - -OptionsNoReturn - cmp #@kbcode._tab ; Tab key - bne OptionsNoTab - jsr SelectNextGradient -OptionsNoTab - jmp OptionsMainLoop .endp + .proc SelectNextGradient lda OptionsY ; if "Wind" option selected cmp #$03 @@ -144,65 +54,6 @@ NoGradientLoop sta GradientColors+1 rts .endp -;-------- -; inversing selected option (cursor) -;-------- -.proc OptionsInversion -YPos = temp2 -XPos = temp2+1 -optionWidth = 6 -nameWidth = 10 - mwa #OptionsHere temp ; offset of the first option=11 - mva #0 YPos ;option number pointer - mva #0 Xpos ;X position in the menu - tay ; Y is zero here... -OptionsSetMainLoop - ldx YPos ; Y position in the menu -;inversing the first few chars of the selected line (OptionsY) - cpx OptionsY - jsr _inverter - cpy #nameWidth-1 - bne OptionsSetMainLoop - adw temp #nameWidth - ldy #0 - -OptionsLoop - lda XPos - cmp OptionsTable,x - jsr _inverter - cpy #optionWidth ; width of the option highlight - bne OptionsLoop - ldy #0 - ; next X position of the - adw temp #optionWidth ; width of the option highlight - inc:lda XPos - cmp #5 ; number of options in a row - bne OptionsLoop - ; next line - ;adw temp #nameWidth ; beginning of the next line - mva #0 Xpos - tay - inc:lda Ypos - cmp #maxOptions - bne OptionsSetMainLoop - rts - -_inverter - beq invertme - ; clean inversion otherwise - lda (temp),y - and #$7f ; clear the top bit - sta (temp),y - bpl @+ ; JMP -invertme - lda (temp),y - ora #$80 ; set the top bit - sta (temp),y -@ - ; next character in an option - iny - rts -.endp ; -------------------------------------- ; Sets the appropriate variables based on the options table @@ -304,13 +155,6 @@ AfterManualPurchase jmp Purchase.GoToActivation .endp -;-------------------------------------------------- -.proc CopyFromPurchaseAndGameOver - mwa #DisplayCopyPurchaseDlROM temp - mwa #DisplayCopyPurchase temp2 - mwa #DisplayCopyPurchaseEnd+1 modify - jmp CopyFromROM ; jsr:rts -.endp ;-------------------------------------------------- .proc Purchase ; @@ -320,786 +164,18 @@ AfterManualPurchase ; Rest of the data is taken from appropriate tables ; and during the purchase these tables are modified. - jsr CopyFromPurchaseAndGameOver - - mwa #ListOfWeapons WeaponsListDL ;switch to the list of offensive weapons ; we are clearing list of the weapons mva #$00 WhichList ; offensive weapon - 0, deffensive - %10000000 GoToActivation - mva #$ff LastWeapon - - SetDLI DLIinterruptText ; jsr SetDLI for text (purchase) screen - jsr PMoutofScreen - mwa #PurchaseDL dlptrs - lda #@dmactl(narrow|dma) ; narrow screen width, DL on, P/M off - sta dmactls - - lda #song_supermarket - bit IsInventory - bpl @+ - lda #song_inventory -@ jsr RmtSongSelect - - ldx tankNr - lda TankStatusColoursTable,x - sta COLOR2 - - ; there is a tank (player) number in tanknr - ; we are displaying name of the player - lda #$ca - sta COLOR1 ; set color of header text - ldy #0 - sty COLBAKS ; set color of background - lda tanknr - :3 asl ; 8 chars per name - tax -NextChar03 - lda tanksnames,x - sta purchaseTextBuffer+7,y - inx - iny - cpy #$08 - bne NextChar03 - ; displaying number of active controller port - ldy JoystickNumber - lda digits+1,y - sta purchaseTextBuffer+17 - - ; and we display cash of the given player - -; here we must jump in after each purchase -; to generate again list of available weapons -AfterPurchase - - ; current cash display - mva #sfx_purchase sfx_effect - ldx tanknr - lda moneyL,x - sta decimal - lda moneyH,x - sta decimal+1 - mwa #purchaseTextBuffer+26 displayposition - jsr displaydec5 - - ; in xbyte there is the address of the line that - ; is being processed now - mwa #ListOfWeapons xbyte - ldx #$00 ; index of the checked weapon - stx HowManyOnTheListOff ; amounts of weapons (shells, bullets) in both lists - stx HowManyOnTheListDef - - jsr CreateList - - bit isInventory ; - bpl ChoosingItemForPurchase - - lda whichList - bne PositionDefensive - -; calculate positionOnTheList from the activeWeapon (offensives) - ldx tankNr - lda activeWeapon,x - ldy #0 -@ - cmp IndexesOfWeaponsL1,y - beq ?weaponfound - iny - cpy #(last_offensive_____ - first_offensive____)+1 ; maxOffensiveWeapons - bne @- - ; not found apparently? - ; TODO: check border case (the last weapon) - ldy #0 - beq ?weaponFound ; jmp -PositionDefensive - jsr calcPosDefensive - - -?weaponFound - ; weapon index in Y - sty positionOnTheList - jsr _MakeOffsetDown ; set list screen offset - -; Here we have all we need -; So choose the weapon for purchase ...... -;-------------------------------------------------- -ChoosingItemForPurchase -;-------------------------------------------------- - - jsr PutLitteChar ; Places pointer at the right position - jsr getkey - bit escFlag - bpl @+ - mva #0 escFlag - jmp WaitForKeyRelease ; like jsr ... : rts -@ - cmp #@kbcode._tab ; $2c ; Tab - jeq ListChange - cmp #@kbcode._left ; $06 ; cursor left - jeq ListChange - cmp #@kbcode._ret ; $0c ; Return - sne:rts - cmp #@kbcode._up ; $e - beq PurchaseKeyUp - cmp #@kbcode._down ; $f - beq PurchaseKeyDown - cmp #@kbcode._space ; $21 ; Space - jeq PurchaseWeaponNow - cmp #@kbcode._right ; $07 ; cursor right - jeq PurchaseWeaponNow - bne ChoosingItemForPurchase - -PurchaseKeyUp - lda WhichList - bpl GoUpOffensive - dec PositionOnTheList - bpl EndUpX - ldy HowManyOnTheListDef - dey - sty PositionOnTheList - jmp MakeOffsetDown -GoUpOffensive - dec PositionOnTheList - bpl MakeOffsetUp - ldy HowManyOnTheListOff - dey - sty PositionOnTheList - jmp MakeOffsetDown -MakeOffsetUp - ; If offset is larger than pointer position, - ; it must be equal then. - lda PositionOnTheList - cmp OffsetDL1 - bcs EndUpX ; do not modify the offset - sta OffsetDL1 -EndUpX - jmp ChoosingItemForPurchase -PurchaseKeyDown - lda WhichList - bpl GoDownOffensive - inc:lda PositionOnTheList - cmp HowManyOnTheListDef - bne EndGoDownX - ldy #0 - sty PositionOnTheList - beq MakeOffsetUp -GoDownOffensive - inc:lda PositionOnTheList - cmp HowManyOnTheListOff - bne MakeOffsetDown - ldy #0 - sty PositionOnTheList - beq MakeOffsetUp -MakeOffsetDown - jsr _MakeOffsetDown -EndGoDownX - jmp ChoosingItemForPurchase - -_MakeOffsetDown - lda OffsetDL1 - clc - adc #15 - ;if offset+16 is lower than the position then it must =16 - cmp PositionOnTheList - bcs _EndGoDownX - sec - lda PositionOnTheList - sbc #15 - sta OffsetDL1 -_EndGoDownX rts - -; swapping the displayed list and setting pointer to position 0 -ListChange - mva #0 OffsetDL1 - - lda WhichList - eor #%10000000 ; flip WhichList - sta WhichList - bne DeffensiveSelected - - mwa #ListOfWeapons WeaponsListDL - lda isInventory - beq @+ - ; inventory - jsr calcPosOffensive - jsr _MakeOffsetDown ; set list screen offset - jmp ChoosingItemForPurchase -@ - mva #0 PositionOnTheList - jmp ChoosingItemForPurchase - -DeffensiveSelected - mwa #ListOfDefensiveWeapons WeaponsListDL - lda isInventory - beq @+ - jsr calcPosDefensive - jmp ChoosingItemForPurchase -@ - mva #0 positionOnTheList - jmp ChoosingItemForPurchase - -.endp -; -;-------------------------------------------------- -.proc CreateList -;-------------------------------------------------- -; Creating full list of the available weapons for displaying -; in X there is an index of the weapon to be checked, -; in 'Xbyte' address of the first char in filled screen line - -CreateList - stx temp ; index of a weapon will be necessary later - ; checking if the weapon of the given index is present - lda WeaponUnits,x - jeq NoWeapon - - ldy tanknr - - bit isInventory - jmi itIsInventory - - ; put "Purchase" on the screen - mwa #PurchaseDescription PurActDescAddr - ; and Title - mwa #PurchaseTitle DLPurTitleAddr - - ; checking if we can afford buying this weapon - ldx temp - lda moneyH,y - cmp WeaponPriceH,x - bne @+ - lda moneyL,y - cmp WeaponPriceL,x -@ - jcc TooLittleCash - - ; we have enough cash and the weapon can be - ; added to the list - - ; first parentheses and other special chars - ; (it's easier this way) - ;ldy #22 - ;lda #08 ; "(" - ;STA (XBYTE),y - ;ldy #32 - ;lda #09 ; ")" - ;sta (xbyte),y - ldy #24 - lda #15 ; "/" - sta (xbyte),y - ldy #30 - lda #16 ; "0" - sta (xbyte),y - - ;now number of units (shells) to be purchased - adw xbyte #22 displayposition ; 23 chars from the beginning of the line - lda WeaponUnits,x - sta decimal - jsr displaybyte - ldx temp ;getting back index of the weapon - - ; and now price of the weapon - adw xbyte #25 displayposition ; 26 chars from the beginning of the line - lda WeaponPriceL,x - sta decimal - lda WeaponPriceH,x - sta decimal+1 - jsr displaydec5 - ldy #25 ; overwrite first digit (allways space - no digit :) ) - lda #04 ; "$" - sta (xbyte),y - - jmp notInventory - -itIsInventory - ; put "Activate" on the screen - mwa #ActivateDescription PurActDescAddr - ; and Title - mwa #InventoryTitle DLPurTitleAddr - - ldx temp - lda TanksWeaponsTableL,y - sta weaponPointer - lda TanksWeaponsTableH,y - sta weaponPointer+1 - ldy temp - lda (weaponPointer),y - jeq noWeapon - - ; clear price area - ldy #21 ; beginning of the price area - lda #0 -@ sta (XBYTE),y - iny - cpy #32 ; end of price - bne @- - -notInventory - - ; number of posessed shells - lda temp ; weapon index again - jsr HowManyBullets - sta decimal - - adw xbyte #1 displayposition - jsr displaybyte - - ldx temp ;weapon index - ; now symbol of the weapon - lda WeaponSymbols,x - ldy #$4 ; 4 chars from the beginning of the line - sta (xbyte),y - - ; and now name of the weapon and finisheeeedd !!!! - mva #0 temp+1 ; this number is only in X - ; times 16 (it's length of the names of weapons) - ldy #3 ; Rotate 4 times -@ - asl temp - rol temp+1 - dey - bpl @- - - adw temp #NamesOfWeapons-6 weaponPointer - - ldy #6 ; from 6th char on screen - -@ - lda (weaponPointer),y - sta (xbyte),y - iny - cpy #(16+6) - bne @- - - - ; in X there is what we need (weapon index) - - ; If on screen after the purchase there is still - ; present the weapon purchased recently, - ; the pointer must point to it. - bit lastWeapon - bpl @+ ; if == $ff => first run, jump to top - mva #0 PositionOnTheList - beq NotTheSameAsLastTime -@ - cpx LastWeapon - bne NotTheSameAsLastTime - bit WhichList - bmi @+ - lda HowManyOnTheListOff - sta PositionOnTheList - jmp NotTheSameAsLastTime -@ - lda HowManyOnTheListDef - sta PositionOnTheList -NotTheSameAsLastTime - ; increase appropriate counter - txa - cpx #last_offensive_____+1 - bcs DefenceList - ldy HowManyOnTheListOff - sta IndexesOfWeaponsL1,y - inc HowManyOnTheListOff - bne NextLineOfTheList -DefenceList - ldy HowManyOnTheListDef - sta IndexesOfWeaponsL2,y - inc HowManyOnTheListDef - ; If everything is copied then next line -NextLineOfTheList - adw xbyte #32 -TooLittleCash -NoWeapon - - ; next weapon. If no more weapons then finish! - inx - cpx #last_offensive_____+1 - bne NoDefense - -; if we got to the defense weapons, -; we switch address to the second table. - mwa #ListOfDefensiveWeapons xbyte -NoDefense - cpx #last_defensive_____+1 - - jne CreateList - - ; offset may be only too big - ; (because after purchase list will never be longer) - ; check it and modify if necessary. - ; If offset is larger than position of the pointer, - ; it must be equal. - lda PositionOnTheList - cmp OffsetDL1 - bcs WeHaveOffset ; do not modify offset - sta OffsetDL1 -WeHaveOffset - - ; now we have to erase empty position of both lists. - - ; Multiply number on list 1 by 32 and set address - ; of the first erased char. - - lda HowManyOnTheListOff - sta xbyte ; multiplier (temporarily here, it will be erased anyway) - lda #$00 ; - sta xbyte+1 ; higher byte of the Result - ldx #$05 ; 2^5 -@ asl xbyte - rol xbyte+1 - dex - bne @- - - ; add to the address of the list - adw xbyte #ListOfWeapons - ldy #0 -ClearList1 - cpw xbyte #ListOfWeapons1End - beq ListCleared1 - tya ; now there is zero here - sta (xbyte),y - inw xbyte - jmp ClearList1 -ListCleared1 - ; And the same we do with the second list - - ; Multiply number on list 1 by 32 and set address - ; of the first erased char. - lda HowManyOnTheListDef - sta xbyte ; multiplier (temporarily here, it will be erased anyway) - lda #$00 ; - sta xbyte+1 ; higher byte of the Result - ldx #$05 ; 2^5 -@ asl xbyte - rol xbyte+1 - dex - bne @- - - ; add to the address of the list - adw xbyte #ListOfDefensiveWeapons - ldy #0 -ClearList2 - cpw xbyte #ListOfDefensiveWeaponsEnd - beq ListCleared2 - tya ; now there is zero here - sta (xbyte),y - inw xbyte - jmp ClearList2 -ListCleared2 - -; here we have pretty cool lists and there is no brute force -; screen clearing at each list refresh -; (it was very ugly - I checked it :) - rts -.endp - -;-------------------------------------------------- -.proc PurchaseWeaponNow -; weapon purchase routne increases number of possessed bullets -; decreases cash and jumps to screen refresh -;-------------------------------------------------- - bit isInventory - bmi inventorySelect - - bit WhichList - bmi PurchaseDeffensive - - ; here we purchase the offensive weapon - ldy PositionOnTheList - lda IndexesOfWeaponsL1,y - jmp PurchaseAll -PurchaseDeffensive - ldy PositionOnTheList - lda IndexesOfWeaponsL2,y -PurchaseAll - ; after getting weapon index the routine is common for all - ldx tanknr - tay ; weapon index is in Y - sec - lda moneyL,x ; substracting from posessed money - sbc WeaponPriceL,y ; of price of the given weapon - sta moneyL,x - lda moneyH,x - sbc WeaponPriceH,y - sta moneyH,x - -positiveMoney - ; now we have to get address of - ; the table of the weapon of the tank - ; and add appropriate number of shells - - sty LastWeapon ; store last purchased weapon - ; because we must put screen pointer next to it - - ; but if we purchasing "Buy me!" then we must draw the winning weapon. - cpy #ind_Buy_me_________ - bne NoSuprise - -Suprise ; get a random weapon - lda random - cmp #51 ; defensive weapons are less likely because they are more expensive - probability 255:51 (5:1) - bcc GetRandomDefensive -GetRandomOffensive - randomize ind_Missile________ last_offensive_____ - ;cmp #ind_Buy_me_________ ; buy me do not buy buy me :) - ;beq GetRandomOffensive - tay - bne NoSuprise ; Y always <> 0 -GetRandomDefensive - randomize ind_Battery________ last_defensive_____ - tay -; lda WeaponUnits,y ; check if weapon exist -; beq GetRandomDefensive - -NoSuprise - lda TanksWeaponsTableL,x - sta weaponPointer - lda TanksWeaponsTableH,x - sta weaponPointer+1 - - clc - lda (weaponPointer),y ; and we have number of posessed bullets of the weapon - adc WeaponUnits,y - sta (weaponPointer),y ; and we added appropriate number of bullets - cmp #100 ; but there should be no more than 99 bullets - bcc LessThan100 - lda #99 - sta (weaponPointer),y -LessThan100 - - mva #0 PositionOnTheList ; to move the pointer to the top when no more monies - jmp Purchase.AfterPurchase - -inventorySelect - bit whichList - bmi invSelectDef - - ldy PositionOnTheList - lda IndexesOfWeaponsL1,y - ldx tankNr - sta activeWeapon,x - jmp WaitForKeyRelease ; rts - -invSelectDef - ldy PositionOnTheList - lda IndexesOfWeaponsL2,y - tay - ldx tankNr - cmp #ind_Battery________ - bne NotBattery - ; if activate battery, we do it differently - mva #sfx_battery sfx_effect - phy - mva #99 Energy,x - jsr MaxForceCalculate - ply - jmp DecreaseDefensive ; bypass activation -NotBattery - cmp #ind_Auto_Defense___ - bne NoAutoDefense - ; Auto Defense - do it like battery - mva #sfx_auto_defense sfx_effect - mva #$A1 AutoDefenseFlag,x ; this is "A" in inverse - for status line :) - jmp DecreaseDefensive ; bypass activation -NoAutoDefense - cmp #ind_Lazy_Boy_______ - bne NoLazyBoy - ; Lazy Boy - do it like battery - mva #%01000000 LazyFlag - jmp DecreaseDefensive ; bypass activation -NoLazyBoy - cmp #ind_Lazy_Darwin____ - bne NoLazyDarwin - ; Lazy Darwin - do it like battery - mva #%11000000 LazyFlag - jmp DecreaseDefensive ; bypass activation -NoLazyDarwin - cmp #ind_Spy_Hard_______ - bne NotSpy - mva #$ff SpyHardFlag - jmp DecreaseDefensive ; bypass activation -NotSpy - cmp #ind_Long_Barrel____ - bne NotBarrel - ; if activate long barrel, we do it differently too - mva #sfx_long_barrel sfx_effect - mva #LongBarrel BarrelLength,x - bne DecreaseDefensive ; bypass activation -NotBarrel - cmp #ind_White_Flag_____ - bne NotWhiteFlag - cmp ActiveDefenceWeapon,x - bne NoDeactivateWhiteFlag - mva #sfx_white_flag sfx_effect - lda #$00 ; if try to activate activated White Flag then deactivate Defence - sta ActiveDefenceWeapon,x - sta ShieldEnergy,x - beq DefActivationEnd -NotWhiteFlag -NoDeactivateWhiteFlag - ; activate new defensive - sta ActiveDefenceWeapon,x - ; set defensive energy - lda DefensiveEnergy,y - sta ShieldEnergy,x -DecreaseDefensive - ; decrease number of defensives - lda TanksWeaponsTableL,x - sta weaponPointer - lda TanksWeaponsTableH,x - sta weaponPointer+1 - lda (weaponPointer),y - sec - sbc #1 - sta (weaponPointer),y - -DefActivationEnd - jmp WaitForKeyRelease ; rts - -.endp -; ----------------------------------------------------- -.proc calcPosDefensive -; calculate positionOnTheList from the activeWeapon (defensives) - ldx tankNr - lda ActiveDefenceWeapon,x - beq ?noWeaponActive - ldy #0 ; min defensive weapon -@ - cmp IndexesOfWeaponsL2,y - beq ?weaponfound - iny - cpy #(last_defensive_____ - first_defensive____)+1 ; maxDefensiveWeapon - bne @- - ; not found apparently? - ; TODO: check border case (the last weapon) -?noWeaponActive - ldy #0 -?weaponFound - cpy howManyOnTheListDef - bcs ?noWeaponActive - sty positionOnTheList - rts .endp -.proc calcPosOffensive -; calculate positionOnTheList from the activeWeapon (defensives) - ldx tankNr - lda ActiveWeapon,x - beq ?noWeaponActive - ldy #0 ; min defensive weapon -@ - cmp IndexesOfWeaponsL1,y - beq ?weaponfound - iny - cpy #(last_offensive_____ - first_offensive____) ; maxOffensiveWeapon - bne @- - ; not found apparently? - ; TODO: check border case (the last weapon) -?noWeaponActive - ldy #0 -?weaponFound - cpy howManyOnTheListOff - bcs ?noWeaponActive - sty positionOnTheList - rts -.endp -; ----------------------------------------------------- -.proc PutLitteChar - ; first let's clear both lists from little chars - mwa #ListOfWeapons xbyte - ldx #last_defensive_____ ; there are xx lines total - ldy #$00 -EraseLoop - tya ; lda #$00 - sta (xbyte),y - adw xbyte #32 ; narrow screen - dex - bpl EraseLoop - - ; now let's check which list is active now - bit WhichList - bpl CharToList1 - ; we are on the second list (deffensive) - ; so there is no problem with scrolling - mwa #ListOfDefensiveWeapons xbyte - ldx PositionOnTheList - beq SelectList2 ; if there is 0 we add nothing -AddLoop2 - adw xbyte #32 ; narrow screen - dex - bne AddLoop2 -SelectList2 - lda #$7f ; little char (tab) - this is the pointer - sta (xbyte),y - ; now we clear up and down arrows indicating more content below or above screen - ldx #EmptyLine - stx MoreUpdl - sty MoreUpdl+1 - stx MoreDowndl - sty MoreDowndl+1 - rts -CharToList1 - ; we putchar on list 1 - ; and later set-up list itself - mwa #ListOfWeapons xbyte - ldx PositionOnTheList - beq SelectList1 ; if there is 0 we add nothing -AddLoop1 - adw xbyte #32 ; narrow screen - dex - bne AddLoop1 -SelectList1 - lda #$7f ; pointer = little char = (tab) - sta (xbyte),y - ; now moving the window basing on given offset - mwa #ListOfWeapons xbyte - ldx OffsetDL1 - beq SetWindowList1 ; if zero then add nothing -LoopWindow1 - adw xbyte #32 ; narrow screen - dex - bne LoopWindow1 -SetWindowList1 - mwa xbyte WeaponsListDL ; and we change Display List - - ; we show screen line with arrows meaning that - ; you can scroll the list up - ldx #EmptyLine - lda OffsetDL1 - beq NoArrowUp - ldx #MoreUp -NoArrowUp - stx MoreUpdl - sty MoreUpdl+1 - ; the same, bu scrolling down - lda HowManyOnTheListOff - ldx #EmptyLine - sec - sbc #17 ; ???? - bmi NoArrowDown - cmp OffsetDL1 - bcc NoArrowDown - ldx #MoreDown -NoArrowDown - stx MoreDowndl - sty MoreDowndl+1 - rts -.endp ; ----------------------------------------------------- .proc EnterPlayerNames ;entering names of players - mwa #NameDL dlptrs - lda #%00110001 ; narrow screen width, DL on, P/M off - sta dmactls - SetDLI DLIinterruptText ; jsr SetDLI for text (names) screen mva #0 TankNr sta COLBAKS ; set color of background @@ -1127,191 +203,16 @@ NoArrowDown ; Default tanks names are in table TanksNamesDefault ; ----------------------------------------------------- - jsr PMoutofScreen - ; display tank number - ldx tanknr - lda skillTable,x - sta difficultyLevel - lda digits+1,x - sta NameScreen2+7 +; - ; clear tank name editor field - not necessary -; ldx #8 -; lda #0 -;@ sta NameAdr,x -; dex -; bpl @- - - ; copy existing name and place cursor at end - lda TankNr - :3 asl - tax - - ldy #0 -@ lda TanksNames,x -; beq endOfTankName - sta NameAdr,y - inx - iny - cpy #8 - bne @- -endOfTankName - -@ lda NameAdr,y - and #$7f - bne LastNameChar - dey - bpl @- -LastNameChar - cpy #7 - beq @+ - iny -@ sty PositionInName - -CheckKeys - jsr HighlightLevel ; setting choosen level of the opponent (Moron, etc) - ldx TankNr - lda JoyNumber,x - tay - lda digits+1,y - sta NameScreen2+11 ; display joystick port number - lda TankShape,x - tay - lda digits+1,y - sta NameScreen2+15 ; display tank shape number - jsr CursorDisplay - jsr getkey - bit escFlag - spl:rts - - .IF TARGET = 800 ; only the A800 has a keyboard - ; is the char to be recorded? - ldx #keycodesEnd-keycodes ;table was 38 chars long -IsLetter - cmp keycodes,x - beq YesLetter - dex - bpl IsLetter - bmi CheckFurtherX01 ; if not in the table - ; we check cursors and (Return) -YesLetter - lda scrcodes,x ; we have screen code of the char - ldx PositionInName - sta NameAdr,x - inx - cpx #$08 ; is there 8 characters? - bne @+ - dex -@ stx PositionInName ; if not, we store - jmp CheckKeys - .ENDIF -CheckFurtherX01 ; here we check Tab, Return and Del - cmp #@kbcode._ret ; $0c ; Return - jeq EndOfNick - cmp #@kbcode._tab ; $2c ; Tab - beq ChangeOfJoyUp - cmp #@kbcode._right ; $7 ;cursor right - beq ChangeOfLevelUp - cmp #@kbcode._left ; $6 ;cursor left - beq ChangeOfLevelDown - cmp #@kbcode._down ; $f ;cursor down - beq ChangeOfLevel3Up - cmp #@kbcode._up ; $e ;cursor up - beq ChangeOfLevel3Down - cmp #@kbcode._atari ; atari (inverse) key - jeq ChangeOfShapeUp - - cmp #@kbcode._del ; $34 ; Backspace (del) - bne CheckKeys - ; handling backing one char - ldx PositionInName - beq FirstChar ; ferst char - no go back - cpx #7 - bne NotLastChar - lda NameAdr,x - and #$7f - bne LastIsNotSpace ; last char not empty - first clear last char (no go back) -NotLastChar - dex -LastIsNotSpace -FirstChar - stx PositionInName - lda #0 - sta NameAdr,x - jmp CheckKeys -;---- -ChangeOfJoyUp - ldx TankNr - inc JoyNumber,x - lda JoyNumber,x - and #%00000011 ; max 4 joysticks - sta JoyNumber,x - .IF TARGET = 5200 - beq ChangeOfShapeUp ; change tank shape - .ENDIF - jmp CheckKeys -;---- -ChangeOfLevelUp ; change difficulty level of computer opponent - inc:lda DifficultyLevel - cmp #9 ; 9 levels are possible - bne DoNotLoopLevelUp - mva #$0 DifficultyLevel -DoNotLoopLevelUp - jmp CheckKeys -;---- -ChangeOfLevelDown - dec:lda DifficultyLevel - bpl DoNotLoopLevelDown - mva #$8 DifficultyLevel -DoNotLoopLevelDown - jmp CheckKeys -;---- -ChangeOfLevel3Up - adb DifficultyLevel #3 - - cmp #9 - bcc DoNotLoopLevel3Up - - sbb DifficultyLevel #9 - -DoNotLoopLevel3Up - jmp CheckKeys -;---- -ChangeOfLevel3Down - sbb DifficultyLevel #3 - bpl @+ - adb DifficultyLevel #9 -@ - jmp CheckKeys -;---- -ChangeOfShapeUp - ldx TankNr - inc TankShape,x - lda TankShape,x - cmp #$03 - bne @+ - lda #$00 - sta TankShape,x -@ jmp CheckKeys -;---- EndOfNick - ; now check long press joy button (or Return...) - mva #0 pressTimer ; reset -WaitForLongPress - lda STRIG0 ; wait only for joy long press - bne ShortJoyPress - lda pressTimer - cmp #25 ; 1/2s - bcc WaitForLongPress - jsr EnterNameByJoy - jmp CheckKeys -ShortJoyPress ; storing name of the player and its level ; level of the computer opponent goes to ; the table of levels (difficulties) ldx tanknr - lda DifficultyLevel + lda #6 ; Spoiler + sta DifficultyLevel sta skilltable,x beq NotRobot lda #$03 ; shape for robotanks @@ -1332,7 +233,7 @@ NotRobot ; check if all chars are empty (" ") ldy #7 lda #0 -@ ora NameAdr,y +@ ora #0 ; NameAdr,y and #$7F ; remove inverse (Cursor) dey bpl @- @@ -1341,7 +242,7 @@ NotRobot ldy #0 nextchar04 - lda NameAdr,y + lda #0 ; NameAdr,y and #$7f ; remove inverse (Cursor) sta tanksnames,x inx @@ -1359,145 +260,6 @@ nextchar05 bne nextchar05 rts .endp -;-------------------------------------------------- -.proc CursorDisplay - ldy #7 -CursorLoop - lda NameAdr,y - and #$7f - cpy #0 - bne NotFirstLetter - and #$3f ; First letter should be Capital letter - ; (nice trick does not affect digits) -NotFirstLetter - cpy PositionInName - bne @+ - ora #$80 ; place cursor -@ sta NameAdr,y - dey - bpl CursorLoop - rts -.endp -;-------------------------------------------------- -.proc EnterNameByJoy - mva #sfx_keyclick sfx_effect - jsr CursorDisplay - ldy PositionInName - ; now in Y we have PositionInName - ldx #(keycodesEnd-keycodes) -SearchCharacter - lda NameAdr,y - and #$7f - cmp #$20 - bcc CharOK ; digit or space - cmp #$60 - bcs CharOK ; not capital letter - ora #$40 -CharOK - cmp scrcodes,x - beq CharacterFound - dex - bpl SearchCharacter - inx -CharacterFound - ; now in X we have Character (index) on PositionInName - ; wait for centered joy - mva #128-15 pressTimer ; reset (trick) -@ lda STICK0 - and #$0f - cmp #$0f - beq checkjoy - bit pressTimer ; trick (no A change) - bpl @- -checkjoy - lda STICK0 - and #$0f - cmp #$0f - bne JoyNotCentered - -notpressedJoy - ;fire - lda STRIG0 - beq checkjoy ; fire still pressed - rts - -JoyNotCentered - ; this is a place for code :) - cmp #7 - bne NoRight - ; joy right - cpy #7 - beq GoToMainLoop ; the last character - iny - bne GoToMainLoop -NoRight - cmp #11 - bne NoLeft - ; joy left - lda #0 - sta NameAdr,y - dey - bpl GoToMainLoop - iny - beq GoToMainLoop -NoLeft - cmp #14 - bne NoUp - ; joy up - cpx #(keycodesEnd-keycodes-1) - bne @+ - ldx #$00 ; set to the first character index (loop) - beq CharAndMainLoop -@ inx - bne CharAndMainLoop -NoUp - cmp #13 - bne EnterNameByJoy ; not down - ; joy down - dex - bpl CharAndMainLoop - ldx #(keycodesEnd-keycodes-1) ; set to the last character index (loop) -CharAndMainLoop - lda scrcodes,x - sta NameAdr,y -GoToMainLoop - sty PositionInName - jmp EnterNameByJoy - -.endp -;-------------------------------------------------- -.proc HighlightLevel - ; this routine highlights the choosen - ; level of the computer opponent - ldx #8 ; 9 possible levels -CheckNextLevel01 - lda LevelNameBeginL,x ; address on the screen - sta temp - lda LevelNameBeginH,x - sta temp+1 - ldy #9 ; flip 10 chars to inverse video - cpx DifficultyLevel ; is it the choosen level? - bne NotThisLevel - ; change to inverse, because it is it! -InverseFurther - lda (temp),y - ora #$80 - sta (temp),y - dey - bpl InverseFurther - bmi CheckNextLevel ; Check Next Level -NotThisLevel - lda (temp),y - and #$7f - sta (temp),y - dey - bpl NotThisLevel -CheckNextLevel - dex - bpl CheckNextLevel01 - rts -.endp - ;-------------------------------------------------- .proc displaydec5 ;decimal (word), displayposition (word) ;-------------------------------------------------- @@ -1783,7 +545,7 @@ FinishResultDisplay ;------------------------------------------------- .proc DisplayStatus ;------------------------------------------------- - +DisplayAngle ldx TankNr rts .endp diff --git a/scorchC64.asm b/scorchC64.asm index 3afdfde..be0b0e1 100644 --- a/scorchC64.asm +++ b/scorchC64.asm @@ -6,7 +6,7 @@ ;Miami & Warsaw 2022, 2023 ;--------------------------------------------------- -.def TARGET = C64 ; :) +.def TARGET = 64 ; :) ;--------------------------------------------------- .def XCORRECTION_FOR_PM = 0 ; if 1 - active x position of tanks correction fo PMG @@ -174,7 +174,13 @@ WeaponFont ; Game Code ;-------------------------------------------------- FirstSTART - + DL = 0 + StatusBufferROM = 0 + ;StatusBufferCopy = 0 + StatusBufferCopyEnd = 0 + TRACKS = 4 + DisplayCopyPurchaseEnd = 0 + DisplayCopyPurchaseStart = 0 displayC64 = $2000 ; graphics screen memory start SwitchVICBank(0) SetScreenMemory(displayC64) @@ -392,16 +398,9 @@ MakeDarkScreen .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 rts .endp ;-------------------------------------------------- @@ -479,10 +478,10 @@ EndofBFGDLI .endp ; ------------------------ .proc BFGblink - SetDLI DLIinterruptBFG ; blinking on +; SetDLI DLIinterruptBFG ; blinking on ldy #50 jsr PauseYFrames - SetDLI DLIinterruptGraph ; blinking off +; SetDLI DLIinterruptGraph ; blinking off rts .endp ;---------------------------------------------- diff --git a/scorchC64.prg b/scorchC64.prg new file mode 100644 index 0000000000000000000000000000000000000000..1721170422f38098336b8f2f38de6d3acf00c1ff GIT binary patch literal 35866 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