Files
scorch_src/Atari/textproc.asm
T
2025-12-22 11:22:09 +01:00

2308 lines
54 KiB
NASM

; @com.wudsn.ide.asm.mainsourcefile=scorch.asm
.IF *>0
;----------------------------------------
; this module contains routines used in text mode
; like shop and start-up options
;----------------------------------------
;--------------------------------------------------
.proc Options
;--------------------------------------------------
; start-up screen - options, etc.
; this function returns:
; - 9 values in 'OptionTable' denoting options selected in menu.
; According to contents of this table, corresponding variables are then set.
; Setting of these variables is handled by procedure 'SetVariablesFromOptions'.
; This function also returns additional options by setting variables:
; - 'RandomMountains' - mountains type change after each (0 - round only, >0 - each turn)
; - 'WindChangeInRound' - wind change after each turn (0 - round only, >0 - each turn)
; - 'GradientNr'
; - 'BlackHole' - 0 - standard, >0 - fast
; - 'FastSoilDown' - 0 - no, >0 - yes
; -----------------------------------------------------
; we only need to clear last 60 lines (faster)
ldy #<(display+40*140)
lda #0
sta temp
lda #>(display+40*140)
sta temp+1
jsr clearscreen.Go ;let the screen be clean
; jsr clearscreen ;let the screen be clean
mwa #DisplayCopyRom temp
mwa #display temp2
mwa #DisplayCopyEnd+1 modify
jsr CopyFromROM
jsr OptionsInversion ; to prevent flashing of options
mwa #OptionsDL dlptrs
lda #%00111110 ; normal screen width, DL on, P/M on
sta dmactls
jsr SetPMWidthAndColors
mva #TextBackgroundColor COLOR2
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
dex
bpl @-
jsr drawtanks ;finally draw tanks
pla
sta NumberOfPlayers
mva #0 OptionsY
OptionsMainLoop
bit TeamGame
bvc NoTeamMoreRounds
lda OptionsTable+4 ; In Team game only 10 or 20 rounds available
and #%00000001
sta OptionsTable+4
NoTeamMoreRounds
jsr OptionsInversion
jsr GetKey
bit escFlag
spl:rts
and #$3f ;CTRL and SHIFT ellimination
cmp #@kbcode._down ; $f ;cursor down
bne OptionsNoDown
ldx OptionsY
inx
cpx #maxoptions
beq OptionsMainLoop
stx OptionsY
bne OptionsMainLoop ; allways not 0
OptionsNoDown
cmp #@kbcode._up ; $e ;cursor up
bne OptionsNoUp
dec OptionsY
bpl OptionsMainLoop
inc OptionsY
beq OptionsMainLoop ; allways 0
OptionsNoUp
cmp #@kbcode._left ; $6 ;cursor left
bne OptionsNoLeft
ldx OptionsY
bne NoPlayersOptL
jsr SelectNextGradient.TeamOff
NoPlayersOptL
dec OptionsTable,X
lda OptionsTable,X
bpl OptionsMainLoop
inc OptionsTable,X
beq OptionsMainLoop ; allways 0
OptionsNoLeft
cmp #@kbcode._right ; $7 ;cursor right
bne OptionsNoRight
ldx OptionsY
bne NoPlayersOptR
jsr SelectNextGradient.TeamOff
NoPlayersOptR
inc OptionsTable,X
lda OptionsTable,X
cmp #5 ; number of columns in options
bne OptionsMainLoop
dec OptionsTable,X
bne OptionsMainLoop ; allways not 0
OptionsNoRight
cmp #@kbcode._ret ; $c ;Return key
bne OptionsNoReturn
; wait for long press
jsr WaitForLongPress
bcs TabPressed ; if long press (fire or Return)
EndOfOptions
rts ; options selected
OptionsNoReturn
.IF TARGET = 800
cmp #@kbcode._G ; $61 ; G
bne OptionsNoG
jsr SelectNextGradient.NextGradient
OptionsNoG
.ENDIF
cmp #@kbcode._tab ; Tab key
bne OptionsNoTab
TabPressed
jsr SelectNextGradient
OptionsNoTab
jmp OptionsMainLoop
.endp
.proc SelectNextGradient
lda OptionsY
bne NoTeamGame
lda OptionsTable ; OptionsY=0
cmp #$02 ; 4 players
beq TeamCorrect
cmp #$04 ; 6 players
beq TeamCorrect
TeamOff
lda #0
beq NoTeam
TeamCorrect
lda TeamGame
eor #$74 ; 't' character
NoTeam
sta TeamGame
rts
NoTeamGame
cmp #$03 ; if "Wind" option selected
bne NotWind
lda WindChangeInRound ; wind change after each turn (not round only) flag
eor #$1f ; '?' character
sta WindChangeInRound
rts
NotWind
cmp #$02
bne NotGravity
lda FastSoilDown
eor #$66 ; 'f' character
sta FastSoilDown
rts
NotGravity
cmp #$07
bne NoMountains
lda RandomMountains
eor #$1f ; '?' character
sta RandomMountains
rts
NoMountains
cmp #$08
bne NoBlackHole
lda BlackHole
eor #$5d ; cursor down character
sta BlackHole
rts
NoBlackHole
NextGradient
ldy GradientNr
iny
cpy #$03
bne NoGradientLoop
ldy #$00
NoGradientLoop
sty GradientNr
lda GradientAddrL,y
sta GradientColors
lda GradientAddrH,y
sta GradientColors+1
rts
.endp
;--------
; inversing selected option (cursor)
;--------
.proc OptionsInversion
; Additional option symbols
lda BlackHole
sta OptionsHere+328
lda RandomMountains
sta OptionsHere+288
lda WindChangeInRound
sta OptionsHere+128
lda FastSoilDown
sta OptionsHere+88
lda TeamGame
sta OptionsHere+8
YPos = temp2
XPos = temp2+1
optionWidth = 6
nameWidth = 10
mwa #OptionsHere temp ; offset of the first option=11
mva #0 YPos ;option number pointer
sta 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
bpl @+ ; JMP
invertme
lda (temp),y
ora #$80 ; set the top bit
@ sta (temp),y
; next character in an option
iny
rts
.endp
.proc CallPurchaseForEveryTank
;-------------------------------------------
; call of the purchase (and activate) screens for each tank
;-------------------------------------------
mva #0 TankNr
sta isInventory
@
ldx TankNr
lda SkillTable,x
beq ManualPurchase
jsr PurchaseAI ; skill of the TankNr in A, TankNr in X
jmp AfterManualPurchase
ManualPurchase
lda JoyNumber,x
jsr SetJoystickPort ; set joystick port for player
mva #0 isInventory
jsr Purchase ; purchase weapons
bit escFlag
spl:rts
jsr DefensivesActivate ; activate weapons
bit escFlag
spl:rts
AfterManualPurchase
inc:lda TankNr
cmp NumberOfPlayers
bne @-
rts
.endp
;--------------------------------------------------
.proc DefensivesActivate
;--------------------------------------------------
; This proc call Inventory and set Defensives activation first
mwa #ListOfDefensiveWeapons WeaponsListDL ;switch to the list of offensive weapons
mva #$ff IsInventory
mva #%10000000 WhichList
; offensive weapon - 0, defensive - %10000000
jmp Purchase.GoToActivation
.endp
;--------------------------------------------------
.proc CopyFromPurchaseAndGameOver
mwa #DisplayCopyPurchaseDlROM temp
mwa #DisplayCopyPurchase temp2
mwa #DisplayCopyPurchaseEnd+1 modify
jmp CopyFromROM ; jsr:rts
.endp
;--------------------------------------------------
.proc Purchase ;
;--------------------------------------------------
; In tanknr there is a number of the tank (player)
; that is buying weapons now (from 0).
; 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
mva #$00 WhichList
; offensive weapon - 0, deffensive - %10000000
GoToActivation
mva #$ff LastWeapon
ldx TankNr
jsr SetTeamsOrPlayerHeaders
; we are clearing list of the weapons
jsr ClearLists ; fast lists clear
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
bit TeamGame
bvc NoTeamColors
lda TankStatusColoursTableT,x
NoTeamColors
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
txa ; 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
jsr calcPosOffensive
jmp ?weaponFound
PositionDefensive
jsr calcPosDefensive
?weaponFound
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
and #$3f ;CTRL and SHIFT ellimination
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
bne NoReturn
jsr WaitForLongPress
bcc exitthismenu ; short press
jmp PurchaseWeaponNow ; long press
exitthismenu
rts
NoReturn
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
bmi 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
@weapon_index = temp
stx @weapon_index ; 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 @weapon_index
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 special chars
; (it's easier this way)
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 @weapon_index ;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 @weapon_index
; Y contains TankNr
lda TanksWeaponsTableL,y
sta weaponPointer
lda TanksWeaponsTableH,y
sta weaponPointer+1
ldy @weapon_index
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
adw xbyte #1 displayposition
lda @weapon_index ; weapon index again
jsr HowManyBullets
;sta decimal
jsr displaybyte
ldx @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 !!!!
adw xbyte #6 weaponPointer ; from 6th char on screen
txa
jsr DisplayWeaponName
; 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
ldy #$05 ; 2^5
@ asl xbyte
rol xbyte+1
dey
bne @-
; Y = 0 now
; add to the address of the list
adw xbyte #ListOfWeapons
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
ldy #$05 ; 2^5
@ asl xbyte
rol xbyte+1
dey
bne @-
; Y = 0 now
; add to the address of the list
adw xbyte #ListOfDefensiveWeapons
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
tay
bne NoSuprise ; Y always <> 0
GetRandomDefensive
randomize ind_Battery last_defensive
tay
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 ; and we added appropriate number of bullets
cmp #100 ; but there should be no more than 99 bullets
bcc LessThan100
lda #99
LessThan100
sta (weaponPointer),y
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
lda #$00 ; if try to activate activated White Flag then deactivate Defence
NoDeactivateWhiteFlag
; Activate White Flag (or deactivate if A=0)
sta ActiveDefenceWeapon,x
sta ShieldEnergy,x
mva #sfx_white_flag sfx_effect
bne DefActivationEnd
NotWhiteFlag
; 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 #number_of_defensives ; maxDefensiveWeapon
@
cmp IndexesOfWeaponsL2,y
beq ?weaponfound
dey
bne @-
; Y = 0
?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 #number_of_offensives ; maxOffensiveWeapon
@
cmp IndexesOfWeaponsL1,y
beq ?weaponfound
dey
bne @-
; Y = 0
?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
@
adw xbyte #32 ; narrow screen
dex
bne @-
SelectList2
lda #char_TAB ; 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
ldy #>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
@
adw xbyte #32 ; narrow screen
dex
bne @-
SelectList1
lda #char_TAB ; 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
@
adw xbyte #32 ; narrow screen
dex
bne @-
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
ldy #>EmptyLine
lda OffsetDL1
beq NoArrowUp
ldx #<MoreUp
ldy #>MoreUp
NoArrowUp
stx MoreUpdl
sty MoreUpdl+1
; the same, bu scrolling down
lda HowManyOnTheListOff
ldx #<EmptyLine
ldy #>EmptyLine
sec
sbc #17 ; ????
bmi NoArrowDown
cmp OffsetDL1
bcc NoArrowDown
ldx #<MoreDown
ldy #>MoreDown
NoArrowDown
stx MoreDowndl
sty MoreDowndl+1
rts
.endp
;--------------------------------------------------
.proc ClearLists
;--------------------------------------------------
ldy #<ListOfWeapons
lda #0
sta temp2
lda #>ListOfWeapons
sta temp2+1
Go lda #$0
loop sta (temp2),y
iny
bne @+
inc temp2+1
@ cpy #<ListOfDefensiveWeaponsEnd
bne loop
ldx temp2+1
cpx #>ListOfDefensiveWeaponsEnd
bne loop
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
@ tax
lda TankStatusColoursTable,x
bit TeamGame
bvc NoTeamColors
lda TankStatusColoursTableT,x
NoTeamColors
sta COLOR2 ; set color of player name line
jsr EnterPlayerName
bit escFlag
spl:rts
jsr CheckTankCheat
inc TankNr
lda TankNr
cmp NumberOfPlayers
bne @-
rts
.endp
; -----------------------------------------------------
.proc EnterPlayerName
; this little thing is for choosing Player's skill (if computer)
; and entering his name
; If no name entered, there should be default.
; Default tank names are taken from difficulty level names on the screen.
;
; in: TankNr
; this function returns:
; - 'skilltable' (in array) for this tank
; - 'TankShape' (in array) for this tank
; - 'TanksNames' (in array) for this tank
; -----------------------------------------------------
jsr PMoutofScreen
; display tank number
ldx TankNr
lda skillTable,x
sta difficultyLevel
lda digits+1,x
sta NameScreen2+7
; copy existing name and place cursor at end
txa ; TankNr
:3 asl
tax
ldy #0
@ lda TanksNames,x
sta NameAdr,y
inx
iny
cpy #8
bne @-
endOfTankName
@ lda NameAdr,y
and #$7f
bne LastNameChar
dey
bpl @-
LastNameChar
cpy #7
seq:iny
sty PositionInName
CheckKeys
jsr HighlightLevel ; setting choosen level of the opponent (Moron, etc)
ldx TankNr
ldy JoyNumber,x
lda digits+1,y
sta NameScreen2+11 ; display joystick port number
ldy TankShape,x
lda digits+1,y
sta NameScreen2+15 ; display tank shape number
jsr CursorDisplay
jsr getkey
and #$3f ;CTRL and SHIFT ellimination
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?
sne: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
sne:mva #$0 DifficultyLevel ; DoNotLoopLevelUp
jmp CheckKeys
;----
ChangeOfLevelDown
dec:lda DifficultyLevel
spl:mva #$8 DifficultyLevel ; DoNotLoopLevelDown
jmp CheckKeys
;----
ChangeOfLevel3Up
adb DifficultyLevel #3
cmp #9
scc:sbb DifficultyLevel #9 ; DoNotLoopLevel3Up
jmp CheckKeys
;----
ChangeOfLevel3Down
sbb DifficultyLevel #3
spl: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
sta skilltable,x
beq NotRobot
lda #$03 ; shape for robotanks
sta TankShape,x
NotRobot
; storing name of the tank in the right space
; (without cursor!)
ldy #$00
txa ; ldx TankNr
asl
asl
asl ; 8 chars per name
tax ; in X where to put new name
mva #sfx_next_player sfx_effect
ldy #0
stx temp+1 ; remember start position in tanksnames
sty temp ; 0 if name is empty
@
lda NameAdr,y
and #$7f ; remove inverse (Cursor)
sta tanksnames,x
ora temp
sta temp
inx
iny
cpy #$08
bne @-
lda temp ; check if all chars are empty (" ")
beq MakeDefaultName
rts
MakeDefaultName
ldy difficultyLevel
lda LevelNameBeginL,y ; address on the screen
sta temp2
lda LevelNameBeginH,y
sta temp2+1
ldx temp+1
ldy #1 ; after first char (space)
@ lda (temp2),y
and #$7f ; remove inverse
sta tanksnames,x
beq MakeNumber ; first space found :)
inx
iny
cpy #8
bne @-
MakeNumber
ldy tanknr
lda digits+1,y
sta tanksnames,x
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-KeyRepeatSpeed 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)
;--------------------------------------------------
; displays decimal number as in parameters (in text mode)
; leading zeroes are removed
; the range is (00000..65565 - two bytes)
ldy #4 ; there will be 5 digits
NextDigit
ldx #16 ; 16-bit dividee so Rotate 16 times
lda #$00
Rotate000
aslw decimal
rol ; scroll dividee
; (as highest byte - additional - byte is A)
cmp #10 ; divider
bcc TooLittle000 ; if A is smaller than divider
; there is nothing to substract
sbc #10 ; divider
inc decimal ; lowest bit set to 1
; because it is 0 and this is the fastest way
TooLittle000 dex
bne Rotate000 ; and Rotate 16 times, Result will be in decimal
tax ; and the rest in A
; (and it goes to X because
; it is our decimal digit)
lda digits,x
sta decimalresult,y
dey
bpl NextDigit ; Result again /10 and we have next digit
;rightnumber
; displaying without leading zeroes (if zeroes exist then display space at this position)
ldy #0
ldx #0 ; digit flag (cut leading zeroes)
displayloop
lda decimalresult,y
cpx #0
bne noleading0
cpy #4
beq noleading0 ; if 00000 - last 0 must stay
cmp zero
bne noleading0
lda #space
beq displaychar ; space = 0 !
noleading0
inx ; set flag (no leading zeroes to cut)
displaychar
sta (displayposition),y
nexdigit
iny
cpy #5
bne displayloop
rts
.endp
;--------------------------------------------------
.proc displaybyte ;decimal (byte), displayposition (word)
;--------------------------------------------------
; displays decimal number as in parameters (in text mode)
; leading zeores are removed
; the range is (00..99 - one byte)
sta decimal
ldy #1 ; there will be 2 digits
NextDigit2
ldx #8 ; 8-bit dividee so Rotate 8 times
lda #$00
Rotate001
asl decimal
rol ; scroll dividee
; (as highest byte - additional - byte is A)
cmp #10 ; divider
bcc TooLittle001 ; if A is smaller than divider
; there is nothing to substract
sbc #10 ; divider
inc decimal ; because it is 0 and this is the fastest way
TooLittle001 dex
bne Rotate001 ; and Rotate 8 times, Result will be in decimal
tax ; and the rest in A
; (and it goes to X because
; it is our decimal digit)
lda digits,x
sta decimalresult,y
dey
bpl NextDigit2 ; Result again /10 and we have next digit
; now cut leading zeroes (02 goes 2)
lda decimalresult
cmp zero
bne decimalend1
lda #space
sta decimalresult
decimalend1
; displaying
ldy #1
displayloop1
lda decimalresult,y
sta (displayposition),y
dey
bpl displayloop1
rts
.endp
;--------------------------------------------------
.proc GameOverScreen
;--------------------------------------------------
jsr MakeDarkScreen
jsr WaitForKeyRelease
jsr ClearScreen
jsr ClearPMmemory
jsr PrepareCredits
jsr GameOverResultsClear
jsr CopyFromPurchaseAndGameOver
mwa #GameOverDL dlptrs
mva #$ff ScrollFlag ; credits scroll on
lda #%00111110 ; normal screen width, DL on, P/M on
sta dmactls
lda #%00100100 ; playfield before P/M
sta GPRIOR
jsr SetPMWidthAndColors
mva #0 COLOR1
sta COLBAKS ; set color of background
sta CreditsVScrol
jsr SetJoystickPort ; set joystick port for player
mva #TextForegroundColor COLOR2
SetDLI DLIinterruptGameOver ; jsr SetDLI for Game Over screen
; make text and color lines for each tank
ldx NumberOfPlayers ;we start from the highest (best) tank
bit TeamGame
bvc NoTeamsResults
ldx #MaxPlayers+2 ; set pointer to teams results
NoTeamsResults
dex ;and it is the last one
stx ResultOfTankNr ;in TankSequence table
ldy #0 ;witch line we are coloring
FinalResultOfTheNextPlayer
ldx ResultOfTankNr ;we are after a round, so we can use TankNr
lda TankSequence,x ;and we keep here real number if the tank
tax
stx TankNr ;for which we are displaying results
lda TankStatusColoursTable,x
sta GameOverColoursTable,y
; Y - line number (from 0 to 5)
; X - TanNr
; let's make texts
phy
; first calculate adres first byte of line
mwa #GameOverResults temp
@ dey
bmi LineAdresReady
adw temp #40
jmp @-
LineAdresReady
; put position of tank on the screen
pla
pha ; now we have line number in A register
ldy #1
tax
lda zero+1,x
sta (temp),y
; puts name of the tank on the screen
ldy #$03
lda TankNr
:3 asl ; 8 chars per name
tax
NextChar
lda tanksnames,x
sta (temp),y
inx
iny
cpy #$08+3
bne NextChar
; put big points on the screen
ldx TankNr
lda ResultsTable,x
sta decimal
mva #0 decimal+1
adw temp #12 displayposition
jsr displaydec5
mva #0 displayposition ; overwrite first digit
; put hits points on the screen
sta decimal+1 ; pozor!!! A=0
ldx TankNr
lda DirectHits,x
sta decimal
; lda DirectHitsH,x ; one byte enough
adw temp #19 displayposition
jsr displaydec5
mva #0 displayposition ; overwrite first digit
bit TeamGame
bvs TeamsNoJoy
; put AI symbol or joystick only if no Teams
ldx TankNr
ldy SkillTable,x
bne ThisIsAI
ldy JoyNumber,x
iny ; tricky
ThisIsAI
lda digits,y
ldy #39
sta (temp),y ; AI level or joy number
ldy #char_joy ; Joystick symbol
lda SkillTable,x
beq NotAItank
ldy #char_computer ; Computer symbol
NotAItank
tya
ldy #38
sta (temp),y
TeamsNoJoy
; put earned money on the screen
lda EarnedMoneyL,x
sta decimal
lda EarnedMoneyH,x
sta decimal+1
adw temp #30 displayposition
jsr displaydec5
ldy #35
lda zero
sta (temp),y ; and last zero
ply
iny
dec ResultOfTankNr
lda ResultOfTankNr
bmi MakeBlackLines
cmp #MaxPlayers-1 ; check for last team
beq MakeBlackLines
jmp FinalResultOfTheNextPlayer
MakeBlackLines
cpy #$06
beq AllLinesReady
lda #0 ; black line color for rest of tanks
sta GameOverColoursTable,y
iny
bne MakeBlackLines
AllLinesReady
ldx #(MaxPlayers-1)
MakeAllTanksVisible
lda #99
sta eXistenZ,x
lda #0
sta ActiveDefenceWeapon,x
dex
bpl MakeAllTanksVisible
jsr SetStandardBarrels
; start music and animations
RmtSong song_ending_looped
; initial tank positions randomization
ldx #(MaxPlayers-1) ;maxNumberOfPlayers-1
@
jsr RandomizeTankPos
dex
bpl @-
MainTanksFloatingLoop
; main tanks floating loop
ldx #(MaxPlayers-1) ;maxNumberOfPlayers-1
AllTanksFloatingDown
stx TankNr
lda Ytankstable,x
cmp #(72-7) ; tank under screen - no erase
bcs NoEraseTank
jsr ClearTankNr
sta ATRACT ; reset atract mode
NoEraseTank
ldx TankNr
inc Ytankstable,x
lda ActiveDefenceWeapon,x
beq NotFastTank
:3 inc Ytankstable,x
NotFastTank
lda Ytankstable,x
; cmp #32 ; tank over screen - not visible
cmp #(80-7) ; tank under screen - new tank randomize
bcs TankUnderScreen
cmp #(72-7) ; tank under screen but.... parachute
bcs DrawOnlyParachute
bcc TankOnScreen
TankUnderScreen
jsr RandomizeTankPos
TankOnScreen
jsr PutTankNr
DrawOnlyParachute
lda ActiveDefenceWeapon,x
bne FastTank
jsr DrawTankParachute
FastTank
; ldx TankNr
dex
bpl AllTanksFloatingDown
jsr GetKeyFast
cmp #@kbcode._none
beq MainTanksFloatingLoop ; neverending loop
mva #$00 ScrollFlag ; credits scroll off
jmp MakeDarkScreen
; jsr GameOverResultsClear
; rts
RandomizeTankPos
randomize 10 (32-7) ; 10 not 8 - barrel !! :)
sta Ytankstable,x
randomize 0 180
sta AngleTable,x
randomize 0 (49-8)
; x correction for P/M
; --
.IF XCORRECTION_FOR_PM = 1
and #%11111110
.ENDIF
; --
clc
adc XtankOffsetGO_L,x
sta XtankstableL,x
lda XtankOffsetGO_H,x
adc #0
sta XtankstableH,x
ldy #0
lda random
cmp #32 ; like 1:8
bcs NowNotFastTank
iny
NowNotFastTank
tya
sta ActiveDefenceWeapon,x
rts
GameOverResultsClear
lda #$00
tax
@ sta GameOverResults,x
inx
cpx #(6*40)+1
bne @-
rts
PrepareCredits
; Rewrites credits and places it in the middle of each line.
mwa #CreditsStart temp ; from
mwa #Credits temp2 ; to
MainRewriteLoop
ldy #0
cpw temp #CreditsEnd
beq EndOfCredits
; count characters in this line
@ lda (temp),y
bmi LastCharFound
iny
bne @-
LastCharFound
; in Y number of characters reduced by 1
; let's count how many spaces add before the text
sec
sty magic
lda #40
sbc magic
lsr ; now in A we have number of spaces in front
sta magic
ldy #0
tya
tax
FirstSpaces
sta (temp2),y ; fill the area in front of the text with spaces
iny
cpy magic
bne FirstSpaces
MainText
lda (temp,x)
sta (temp2),y ; rewrite the text to a new place
bmi LastCharWritten
inw temp
iny
bne MainText
LastCharWritten
inw temp
and #%01111111 ; remove inverse
sta (temp2),y
iny
txa ; space to A (0)
LastSpaces
sta (temp2),y ; fill the area behind the text with spaces
iny
cpy #40
bne LastSpaces
NextLine
adw temp2 #40
jmp MainRewriteLoop
EndOfCredits
mwa #Credits DLCreditsAddr ; set address in DL to first line
rts
.endp
;-------------------------------------------------
.proc PutTankNameOnScreen
;-------------------------------------------------
jsr SetTeamsOrPlayerHeaders
; puts name of the tank on the screen
ldy #$00
; lda TankNr
txa ; TankNr in X !
asl
asl
asl ; 8 chars per name
tax
NextChar02
lda tanksnames,x
sta statusBuffer+7,y
inx
iny
cpy #$08
bne NextChar02
;=========================
; displaying number of active controller port or AI level
;=========================
ldx TankNr
ldy #char_computer ; Computer symbol
lda SkillTable,x
tax
bne ThisIsAI
ldy #char_joy ; Joystick symbol
ldx JoystickNumber
inx ; tricky
ThisIsAI
sty statusBuffer+16
lda digits,x
sta statusBuffer+17
; rts
.endp
;-------------------------------------------------
.proc DisplayStatus
;-------------------------------------------------
ldx TankNr
;=========================
;displaying symbol of the weapon
;=========================
ldy ActiveWeapon,x
lda WeaponSymbols,y
sta statusBuffer+19
;=========================
;displaying quantity of the given weapon
;=========================
lda ActiveWeapon,x
jsr HowManyBullets
;sta decimal
mwx #statusBuffer+21 displayposition
jsr displaybyte
;=========================
;displaying name of the weapon
;=========================
mwa #statusBuffer+24 weaponPointer ; from 24th char on screen
ldx TankNr
lda ActiveWeapon,x
jsr DisplayWeaponName
;=========================
;displaying name of the defence weapon (if active)
;=========================
mwa #statusBuffer+40+40+23 weaponPointer ; where to display the
lda AutoDefenseFlag,x ; Auto Defense symbol (space or "A" in inverse)
bpl @+
lda #char_computer ; Auto Defense symbol
@
sta statusBuffer+80+21
lda ActiveDefenceWeapon,x
bne ActiveDefence
; clear brackets
lda #space
sta statusBuffer+80+22
sta statusBuffer+80+39
; lda #0 ; #space == #0
tay
jsr DisplayWeaponName.ClearingOnly
beq NoDefenceName ; like JMP
ActiveDefence
jsr DisplayWeaponName
lda #char_bracketO ; (
sta statusBuffer+80+22
lda #char_bracketC ; )
sta statusBuffer+80+39
NoDefenceName
DisplayEnergy
;=========================
;displaying the energy of a tank
;=========================
lda Energy,x
;sta decimal
mwx #statusBuffer+48 displayposition
jsr displaybyte
;=========================
;displaying the energy of a tank shield (if exist)
;=========================
; clear (if no shield)
lda #space
sta statusBuffer+40+10
sta statusBuffer+40+11
sta statusBuffer+40+12
sta statusBuffer+40+13
; check shield energy and display it
ldx TankNr
lda ActiveDefenceWeapon,x
beq NoDefenceWeapon
lda ShieldEnergy,x
beq NoShieldEnergy
;sta decimal ; displayed value
mvx #char_bracketO statusBuffer+40+10 ; (
mwx #statusBuffer+40+11 displayposition
jsr displaybyte
lda #char_bracketC ; )
sta statusBuffer+40+13
NoDefenceWeapon
NoShieldEnergy
;=========================
; display Wind
;=========================
mwa Wind temp
lda #space
sta statusBuffer+80+17 ; (space) char
sta statusBuffer+80+20 ; (space) char
:4 lsrw temp ;divide by 16 to have a nice value on a screen
lda temp
beq DisplayWindValuex
bit Wind+3 ; highest byte of 4 byte wind
bmi DisplayLeftWindx
ldx #char_TAB ; (tab) char
stx statusBuffer+80+20
bne DisplayWindValuex
DisplayLeftWindx
lda #char_DEL ;(del) char
sta statusBuffer+80+17
sec ; Wind = -Wind
lda #$00
sbc temp
sta temp
DisplayWindValuex
mwx #statusBuffer+80+18 displayposition
jsr displaybyte
;=========================
;display round number
;=========================
lda CurrentRoundNr
;sta decimal
mwx #statusBuffer+80+7 displayposition
jsr displaybyte ;decimal (byte), displayposition (word)
;=========================
;display Force
;=========================
ldx TankNr
lda ForceTableL,x
sta decimal
lda ForceTableH,x
sta decimal+1
mwa #statusBuffer+40+35 displayposition
jsr displaydec5
;=========================
;display Angle
;=========================
displayAngle
ldy #space
ldx TankNr
lda AngleTable,x
cmp #90
beq VerticallyUp
bcs AngleToLeft
AngleToRight
; now we have values from 0 to 89 and right angle
;sta decimal
sty statusBuffer+40+22 ; (space) character
mvx #char_TAB statusBuffer+40+25 ; (tab) character
bne AngleDisplay
AngleToLeft
sec
lda #180
sbc AngleTable,x
; angles 180 - 91 converted to 0 - 89
;sta decimal
sty statusBuffer+40+25 ; (space) character
mvx #char_DEL statusBuffer+40+22 ;(del) char
bne AngleDisplay
VerticallyUp
; now we have value 90
;sta decimal
sty statusBuffer+40+25 ; (space) character
sty statusBuffer+40+22 ; (space) character
AngleDisplay
mwx #statusBuffer+40+23 displayposition
jsr displaybyte
ldx TankNr
rts
.endp
;-------------------------------------------------
.proc RoundOverSprites
; fill sprites with bytes
ldy numberOfPlayers
bit TeamGame
bvc NoTeamSprites
ldy #2 ; 2 teams
NoTeamSprites
dey
lda gameOverSpritesTop,y
sta temp
; clean the whole sprite
lda #0
tax
@ sta PMGraph+$400,x
sta PMGraph+$500,x
dex
bne @-
lda #$01
sta sizep0 ; P0-P1 widths
sta sizep0+1
; set background
lda #$ff
ldx #100+7 ; top of the sprites
@ sta PMGraph+$400,x
sta PMGraph+$500,x
inx
cpx temp
bne @-
GOSbeg = 112
mva #GOSbeg hposp0
mva #GOSbeg+12 hposp0+1
mva #15 PCOLR0
sta PCOLR1
rts
.endp
;-------------------------------------------------
.proc SetTeamsOrPlayerHeaders
; TankNr in X register
mwa #Player_Header temp
ldy #$05 ; 6 characters
bit TeamGame
bvc no_teams
mwa #Team_Header temp
no_teams
lda (temp),y
sta statusBuffer,y
sta purchaseTextBuffer,y
dey
bpl no_teams
bit TeamGame
bvc no_teams2
txa
ror
bcc A_Team
B_Team
inc statusBuffer
inc purchaseTextBuffer
A_Team
no_teams2
rts
.endp
;-------------------------------------------------
.proc DisplayWeaponName
; nr of weapon in A, address to put in weaponPointer
@weapon_index = TextNumberOff
sta @weapon_index ;get back number of the weapon
mwa #NamesOfWeapons LineAddress4x4
jsr _calc_inverse_display
; now copy text to screen
dey ; ldy #-1
@
iny
lda (LineAddress4x4),y
sta (weaponPointer),y
bpl @-
and #%01111111 ; remove reverse
clearingOnly
sta (weaponPointer),y
lda #0 ; clean the rest
iny:cpy #16 ; weapon name is max 16 chars
bne clearingonly
rts
.endp
;-------------------------------------------------
.proc _calc_inverse_display
; optymalization station. not a real function
; or is it?
@weapon_index = TextNumberOff
@inverse_counter = temp+1
mva #0 @inverse_counter
ldy LineAddress4x4 ; lower byte to Y
sta LineAddress4x4 ; #0
loop
lda (LineAddress4x4),y
spl:inc @inverse_counter
lda @weapon_index
beq zeroth_talk ; special treatment of talk #0
cmp @inverse_counter
beq lets_talk
iny
bne loop
inc LineAddress4x4+1
bne loop
lets_talk
iny
bne @+
inc LineAddress4x4+1
@
zeroth_talk
sty LineAddress4x4
ldy #0
rts
.endp
;-------------------------------------------------
.proc _calc_packed_display
; Find Nth packed string inside a [len][packed-bytes] stream.
;
; in:
; TextNumberOff = index (0..)
; LineAddress4x4 = base address of the packed stream (points to first len byte)
; out:
; LineAddress4x4 = address of selected record (points to its len byte)
; trashes: A, X, Y, temp, temp2
;
; Record size in bytes = 1 + ceil(len*5/8)
; where `len` is the 1-byte character count (max 63).
;-------------------------------------------------
@idx = temp+1
lda TextNumberOff
sta @idx
beq done
next_record
ldy #0
lda (LineAddress4x4),y
sta temp ; len (low byte)
; advance past len byte
inw LineAddress4x4
; temp2 = len*5 + 7
lda temp
sta temp2
lda #0
sta temp2+1
; temp2 = len*4
asl temp2
rol temp2+1
asl temp2
rol temp2+1
; temp2 = len*5
clc
lda temp2
adc temp
sta temp2
lda temp2+1
adc #0
sta temp2+1
; +7 for ceil
clc
lda temp2
adc #7
sta temp2
bcc @+
inc temp2+1
@
; >>3 (divide by 8)
lsr temp2+1
ror temp2
lsr temp2+1
ror temp2
lsr temp2+1
ror temp2
; LineAddress4x4 += temp2
clc
lda LineAddress4x4
adc temp2
sta LineAddress4x4
lda LineAddress4x4+1
adc temp2+1
sta LineAddress4x4+1
dec @idx
bne next_record
done
rts
.endp
.endif