change CHR bank

This commit is contained in:
Tyrel Souza 2023-01-24 23:45:50 -05:00
parent 35e4e72c00
commit 3999c5d6c5
No known key found for this signature in database
GPG Key ID: F3614B02ACBE438E
9 changed files with 307 additions and 298 deletions

7
atlantico/actor.inc Normal file → Executable file
View File

@ -1,3 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Enumeration with the different types of actors of our game
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.enum ActorType
NULL = 0
PLAYER = 1
@ -6,8 +9,12 @@
MISSILE = 4
BOMB = 5
SPRITE0 = 6
PARACHUTE = 7
.endenum
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Struct to hold the data for one actor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.struct Actor
Type .byte
XPos .byte

View File

@ -8,9 +8,9 @@
;; Variables declared in RAM zero-page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "ZEROPAGE"
Score: .res 4 ; 4 bytes for 1s, 10s, 100s, 1000s, For score
Score: .res 4 ; Score (1s, 10s, 100s, and 1000s digits in decimal)
Collision: .res 1 ; 0 or 1, if 0 no collision, if 1, collisison
Collision: .res 1 ; Flag if a collision happened or not
Buttons: .res 1 ; Pressed buttons (A|B|Sel|Start|Up|Dwn|Lft|Rgt)
PrevButtons: .res 1 ; Stores the previous buttons from the last frame
@ -21,8 +21,8 @@ YPos: .res 1 ; Player Y 16-bit position (8.8 fixed-point): hi+lo
XVel: .res 1 ; Player X (signed) velocity (in pixels per 256 frames)
YVel: .res 1 ; Player Y (signed) velocity (in pixels per 256 frames)
PrevSubmarine: .res 1 ; Stores the value in seconds that the last submarine was added
PrevAirplane: .res 1 ; Stores the value in seconds that the last airplane was added
PrevSubmarine: .res 1 ; Stores the seconds that the last submarine was added
PrevAirplane: .res 1 ; Stores the seconds that the last airplane was added
Frame: .res 1 ; Counts frames (0 to 255 and repeats)
IsDrawComplete: .res 1 ; Flag to indicate when VBlank is done drawing
@ -30,7 +30,7 @@ Clock60: .res 1 ; Counter that increments per second (60 frames)
BgPtr: .res 2 ; Pointer to background address - 16bits (lo,hi)
SprPtr: .res 2 ; Pointer to the sprite address - 16bits (lo,hi)
BufPtr: .res 2 ; Pointer to the Buffer Address - 16bite (lo,hi)
BufPtr: .res 2 ; Pointer to the buffer address - 16bits (lo,hi)
XScroll: .res 1 ; Store the horizontal scroll position
CurrNametable: .res 1 ; Store the current starting nametable (0 or 1)
@ -44,20 +44,17 @@ ParamYPos: .res 1 ; Used as parameter to subroutine
ParamTileNum: .res 1 ; Used as parameter to subroutine
ParamNumTiles: .res 1 ; Used as parameter to subroutine
ParamAttribs: .res 1 ; Used as parameter to subroutine
ParamRectX1: .res 1 ; Used as parameter to subroutine
ParamRectY1: .res 1 ; Used as parameter to subroutine
ParamRectX2: .res 1 ; Used as parameter to subroutine
ParamRectY2: .res 1 ; Used as parameter to subroutine
ParamRectX1: .res 1 ; Used as parameter to subroutine
ParamRectY1: .res 1 ; Used as parameter to subroutine
ParamRectX2: .res 1 ; Used as parameter to subroutine
ParamRectY2: .res 1 ; Used as parameter to subroutine
PrevOAMCount: .res 1 ; Store the previous number of bytes that were sent to the OAM
Seed: .res 2 ; Initialize the 16-bit seed to any value except 0
Seed: .res 2 ; Initialize 16-bit seed to any value except 0
ActorsArray: .res MAX_ACTORS * .sizeof(Actor)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PRG-ROM code located at $8000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -81,135 +78,129 @@ LoopButtons:
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Increment the score, simulating BCD mode
;; Returns a random 8-bit number inside A (0-255), clobbers Y (0).
;; Requires a 2-byte value on the zero page called "Seed".
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc IncrementScore ; LittleEndian
Increment1stDigit:
lda Score+0
clc
adc #1
sta Score+0
cmp #$A
bne DoneIncrementing
Increment10sDigit:
lda #0
sta Score+0
lda Score+1
clc
adc #1
sta Score+1
cmp #$A
bne DoneIncrementing
Increment100sDigit:
lda #0
sta Score+1
lda Score+2
clc
adc #1
sta Score+2
cmp #$A
bne DoneIncrementing
Increment1000sDigit:
lda #0
sta Score+2
lda Score+3
clc
adc #1
sta Score+3
cmp #$A
bne DoneIncrementing
DoneIncrementing:
rts
; This is a 16-bit Galois linear feedback shift register with polynomial $0039.
; The sequence of numbers it generates will repeat after 65535 calls.
; Execution time is an average of 125 cycles (excluding jsr and rts)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc GetRandomNumber
ldy #8 ; Loop counter (generates 8 bits)
lda Seed+0
: asl ; Shift the register
rol Seed+1
bcc :+
eor #$39 ; Apply XOR feedback when a 1 bit is shifted out
:
dey
bne :--
sta Seed+0 ; Saves the value in A into the Seed
cmp #0 ; Set flags
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Increment the Score value simulating BCD mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc IncrementScore
Increment1sDigit:
lda Score+0 ; Load the lowest digit of the number
clc
adc #1 ; Add 1
sta Score+0
cmp #$A ; Check for overflow (equals 10)
bne DoneIncrementing ; If no overflow happened, we're done!
Increment10sDigit:
lda #0
sta Score+0 ; Reset one's digit from 9 to 0
lda Score+1 ; Load second digit
clc
adc #1 ; Add 1 (the carry from the previous digit)
sta Score+1
cmp #$A ; Check for overflow
bne DoneIncrementing ; If no overflow happened, we're done!
Increment100sDigit:
lda #0
sta Score+1 ; Reset ten's digit from 9 to 0
lda Score+2 ; Load the third digit
clc
adc #1 ; Add 1 (the carry from the previous digit)
sta Score+2
cmp #$A ; Check for overflow
bne DoneIncrementing ; If no overflow happened, we're done!
Increment1000sDigit:
lda #0
sta Score+2 ; Reset hundred's digit from 9 to 0
lda Score+3 ; Load the last digit
clc
adc #1 ; Add 1 (the carry from the previous digit)
sta Score+3 ; Store the final addition in the last digit
DoneIncrementing:
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Draw the score in ther nametable/background using buffering
;; Draw the score in the nametable/background using buffering
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Buffer format starting at Ram Address $7000
;; Buffer format starting at memory address $7000:
;;
;; 03 20 52 00 00 02 01 20 78 00 00
;; | \___/ \______/ | \___/ | |
;; | | | | | | |
;; | | | | | | Length=0 (End of buffering)
;; | | | | | byte to copy
;; | | | | PPU Address $2078
;; | | | Length=1
;; | | bytes to copy
;; | PPU address $2052
;; Length =
;; | | | | | | Length=0 (end of buffering)
;; | | | | | byte to copy
;; | | | | PPU Address $2078
;; | | | Length=1
;; | | bytes to copy
;; | PPU Address $2052
;; Length=3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc DrawScore
lda #$70
sta BufPtr+1
lda #$00
sta BufPtr+0
lda #$70
sta BufPtr+1
lda #$00
sta BufPtr+0
ldy #0
ldy #0
lda #3 ; Length = 3 (how many bytes we will send)
sta (BufPtr),y
iny
lda #3 ; send 3 bytes
sta (BufPtr),y
iny
lda #$20
sta (BufPtr),y ; Hi-Byte of the PPU address to be updated
iny
lda #$52
sta (BufPtr),y ; Lo-Byte of the PPU address to be updated
iny
lda #$20
sta (BufPtr),y ; hi byte
iny
lda #$52
sta (BufPtr),y ; lo byte
iny
;; Send the 3 digits of the score (from MSB to LSB) 100s, 10s, 1s
;; Send the 3 digits of the score from MSB to LSB
;; Offset by #$60 to point to numbers
lda Score+2 ; 100s
clc
adc #$60
sta (BufPtr),y
iny
lda Score+2 ; 100s digit of the Score
clc
adc #$60 ; Offset by $60 to point to the correct tile
sta (BufPtr),y
iny
lda Score+1 ; 10s
clc
adc #$60
sta (BufPtr),y
iny
lda Score+0 ; 1s
clc
adc #$60
sta (BufPtr),y
iny
lda Score+1 ; 10s digit of the Score
clc
adc #$60 ; Offset by $60 to point to the correct tile
sta (BufPtr),y
iny
lda #0
sta (BufPtr),y ; Length=0, to signal the end of the buffer
iny
lda Score+0 ; 1s digit of the Score
clc
adc #$60 ; Offset by $60 to point to the correct tile
sta (BufPtr),y
iny
rts
.endproc
lda #0
sta (BufPtr),y ; Length=0 to signal the end of the buffer
iny
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Returns a random 8-bit number inside A (0-255), clobbers Y (0).
;; Requires a 2-byte value on the Zero page called "Seed"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This is a 16-bit Galois Linerar Feedback Shift register with polynomial $0039
;; The sequence of numbers it generates will repeat after 65535 calls.
;; Execution time is an average of 125 cycles (excluding jsr and rts)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc GetRandomNumber
ldy #8 ; Loop counter (generates 8 bits)
lda Seed+0
: asl ; Shift the register
rol Seed+1
bcc :+
eor #$39 ; Apply XOR feedback when a 1 bit is shifted out
:
dey
bne :--
sta Seed+0 ; Saves the value in A into the Seed
cmp #0 ; Set flags
rts
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -398,73 +389,67 @@ EndRoutine:
cmp #3 ; Only add a new submarine if the difference in time from the previous one is equal to 3
bne :+
lda #ActorType::SUBMARINE
sta ParamType ; Load parameter for the actor type
sta ParamType ; Load parameter for the actor type
lda #223
sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber ; load random number into A
lsr ; Divide by 8 (right shift thrice)
lsr
lsr
clc
adc #180 ; add 180 to lower it
sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber ; Fetch a new random number for the Y position of the submarine
lsr
lsr
lsr ; Divide the random number by 8 to get a healthy Y position range
clc
adc #180 ; And then add 180 to to it to move the submarine to the bottom part of the screen
sta ParamYPos
jsr AddNewActor ; Call the subroutine to add the new missile actor
sta ParamYPos ; Load parameter for actor position Y
jsr AddNewActor ; Call the subroutine to add the new submarine actor
lda Clock60
sta PrevSubmarine ; Save the current Clock60 time as the submarine last spawn time
sta PrevSubmarine ; Save the current Clock60 time as the submarine last spawn time
:
SpawnAirplane:
lda Clock60 ; Submarines are added in intervals of 3 seconds
lda Clock60 ; Submarines are added in intervals of 2 seconds
sec
sbc PrevAirplane
cmp #2 ; Only add a new airplane if the difference in time from the previous one is equal to 2
cmp #2 ; Only add a new airplane if the difference in time from the previous one is equal to 2
bne :+
lda #ActorType::AIRPLANE
sta ParamType ; Load parameter for the actor type
sta ParamType ; Load parameter for the actor type
lda #235
sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber ; load random number into A
sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber
lsr
lsr ; Divide the random number (0-255) by 4 to adjust for the correct Y position range
clc
adc #35 ; And then add 35 to to it to place the airplane in the correct place in the sky
lsr ; Divide by 4 (right shift twice)
lsr
clc
adc #35 ; add 35 to lower it, so its not in the status bar
sta ParamYPos ; Load parameter for actor position Y
;Adjust the random Y to be between top and bottom
sta ParamYPos
jsr AddNewActor ; Call the subroutine to add the new missile actor
jsr AddNewActor ; Call the subroutine to add the new airplane actor
lda Clock60
sta PrevAirplane ; Save the current Clock60 time as the submarine last spawn time
:
sta PrevAirplane ; Save the current Clock60 time as the airplane last spawn time
:
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to check collisions
;; PARAMS: ParamXPos, ParamYPos (x and y of missile)
;; Subroutine to loop all enemy actors checking for collision with missile
;; Params = ParamXPos, ParamYPos (are the X and Y position of the missile)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc CheckEnemyCollision
txa
pha ; Push and save the X register in the stack
ldx #0
stx Collision ; Collision = 0
txa
pha ; Push and save X register in the stack
EnemiesCollisionLoop:
cpx #MAX_ACTORS * .sizeof(Actor)
beq FinishCollisionCheck
lda ActorsArray+Actor::Type,x
cmp #ActorType::AIRPLANE
bne NextEnemy ; If not an airplane - skip to next enemy type
ldx #0
stx Collision ; Collision = 0
lda ActorsArray+Actor::Type,x ; Load the type of the actor we are looping
EnemiesCollisionLoop:
cpx #MAX_ACTORS * .sizeof(Actor) ; We loop all entities, looking for enemies (airplanes)
beq FinishCollisionCheck
lda ActorsArray+Actor::Type,x ; Load the type of the actor we are looping
cmp #ActorType::AIRPLANE
bne NextEnemy ; If it's NOT Airplane, bypass this enemy and move check the next one
@ -484,69 +469,68 @@ EndRoutine:
adc #8 ; Get the bottom of the airplane bounding box by adding 8
sta ParamRectY2 ; Bouding Box Y2
jsr IsPointInsideBoundingBox
jsr IsPointInsideBoundingBox ; Proceed to test if point is inside bounding box
lda Collision
beq NextEnemy
lda #ActorType::NULL ; Set actor to null - TODO: maybe make an explosion
sta ActorsArray+Actor::Type,x
jmp FinishCollisionCheck
lda Collision
beq NextEnemy ; If no collision, don't do anything
lda #ActorType::NULL ; Else, destroy airplane
sta ActorsArray+Actor::Type,x ; If collision happened, destroy airplane entity
jmp FinishCollisionCheck ; Also, if collision happened we stop looping other enemies and leave the subroutine
NextEnemy:
txa
clc
adc #.sizeof(Actor) ; X += sizeof(Actor)
tax
jmp EnemiesCollisionLoop ; Loop to check the next actor to see if it's an enemy (airplane)
NextEnemy:
txa
clc
adc #.sizeof(Actor)
tax
jmp EnemiesCollisionLoop
FinishCollisionCheck:
pla
tax
pla
tax ; Pull and restore the old value of X
rts
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to check if a point is inside a bounding box.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Params:
;; (ParamXPos, ParamYPos) - coords to be tested
;; (ParamRectX1,ParamRectY1,ParamRectX2,ParamRectY2) Are rectangle coords)
;; Output:
;; Collision flag is either 1 or 0
;; Params:
;; (ParamXPos,ParamYPos) are the coords of the point to be tested
;; (ParamRectX1,ParamRectY1,ParamRectX2,ParamRectY2) are rectangle coords
;; Output:
;; Collision flag is either 1 or 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc IsPointInsideBoundingBox
lda ParamXPos
cmp ParamRectX1
bcc PointIsOutside
lda ParamXPos ; Fetch the point X coordinate
cmp ParamRectX1 ; Compare it with the enemy rectangle X
bcc PointIsOutside ; If it's less, we stop checking because there is no collision
lda ParamYPos
cmp ParamRectY1
bcc PointIsOutside
lda ParamYPos ; Fetch the point Y coordinate
cmp ParamRectY1 ; Compare it with the enemy bounding box Y value
bcc PointIsOutside ; If it's less, we stop checking because there is no collision
lda ParamXPos
cmp ParamRectX2
bcs PointIsOutside
lda ParamXPos ; Fetch the point X coorrinate
cmp ParamRectX2 ; Compare it with the enemy bounding box right
bcs PointIsOutside ; If it's greater than, we stop checking because there is no collision
lda ParamYPos
cmp ParamRectY2
bcs PointIsOutside
lda ParamYPos ; Fetch the point X coorrinate
cmp ParamRectY2 ; Compare it with the enemy bounding box right
bcs PointIsOutside ; If it's greater than, we stop checking because there is no collision
PointIsInside:
lda #1
sta Collision
jmp EndCollisionCheck
PointIsInside:
lda #1 ; If we reach here, the point is inside the bounding box!
sta Collision ; Collision detected!
jmp EndCollisionCheck
PointIsOutside:
lda #0
sta Collision
EndCollisionCheck:
rts
PointIsOutside:
lda #0 ; If we branch here, the point was outside the bounding box
sta Collision ; No collision detected!
EndCollisionCheck:
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to loop all actors and update them (position, velocity, etc.)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -566,32 +550,31 @@ FinishCollisionCheck:
sta ActorsArray+Actor::Type,x ; Remove the missile from the array
SkipMissile:
CheckCollision:
lda ActorsArray+Actor::XPos,x
clc
adc #3
sta ParamXPos ; Missile position to be checked X += 3
CheckCollision:
lda ActorsArray+Actor::XPos,x
clc
adc #3
sta ParamXPos ; Missile position to be checked X += 3 (plus 3 pixels from the left)
lda ActorsArray+Actor::YPos,x
clc
adc #1
sta ParamYPos ; Missile position to be checked Y += 1
lda ActorsArray+Actor::YPos,x
clc
adc #1
sta ParamYPos ; Missile position to be checked Y += 1 (plus 1 pixels from the top)
jsr CheckEnemyCollision ; Perform collision check between the missile and other enemy actor
jsr CheckEnemyCollision ; Perform collision check between the missile and other enemy actor
lda Collision
beq NoCollisionFound
lda #ActorType::NULL ; Delete missile Actor
sta ActorsArray+Actor::Type,x
lda Collision ; If collision happened, delete the missile
beq NoCollisionFound
lda #ActorType::NULL ; Delete missile actor
sta ActorsArray+Actor::Type,x
jsr IncrementScore
jsr DrawScore
NoCollisionFound:
jsr IncrementScore ; Increment the Score variable using BCD-ish mode
jsr DrawScore ; Send the score bytes to the background buffer at $7000
NoCollisionFound:
jmp NextActor
:
cmp #ActorType::SUBMARINE
bne :+
lda ActorsArray+Actor::XPos,x
@ -604,20 +587,18 @@ FinishCollisionCheck:
SkipSubmarine:
jmp NextActor
:
cmp #ActorType::AIRPLANE
bne :+
lda ActorsArray+Actor::XPos,x
sec
sbc #1 ; Decrement Y position of submarine by 1
sbc #1 ; Decrement Y position of airplane by 1
sta ActorsArray+Actor::XPos,x
bcs SkipAirplane
lda #ActorType::NULL
sta ActorsArray+Actor::Type,x ; Remove the submarine from the array
sta ActorsArray+Actor::Type,x ; Remove the airplane from the array
SkipAirplane:
jmp NextActor
:
NextActor:
txa
clc
@ -672,7 +653,6 @@ FinishCollisionCheck:
jsr DrawSprite ; Call routine to draw 4 PLAYER tiles to the OAM
jmp NextActor
:
cmp #ActorType::SUBMARINE
bne :+
lda ActorsArray+Actor::XPos,x
@ -685,10 +665,9 @@ FinishCollisionCheck:
sta ParamAttribs
lda #4
sta ParamNumTiles
jsr DrawSprite ; Call routine to draw 4 SUBMARINE tile to the OAM
jsr DrawSprite ; Call routine to draw 4 SUBMARINE tiles to the OAM
jmp NextActor
:
cmp #ActorType::AIRPLANE
bne :+
lda ActorsArray+Actor::XPos,x
@ -701,10 +680,9 @@ FinishCollisionCheck:
sta ParamAttribs
lda #3
sta ParamNumTiles
jsr DrawSprite ; Call routine to draw 4 SUBMARINE tile to the OAM
jsr DrawSprite ; Call routine to draw 3 AIRPLANE tiles to the OAM
jmp NextActor
:
cmp #ActorType::MISSILE
bne :+
lda ActorsArray+Actor::XPos,x
@ -720,7 +698,6 @@ FinishCollisionCheck:
jsr DrawSprite ; Call routine to draw 1 MISSILE tile to the OAM
jmp NextActor
:
NextActor:
txa
clc
@ -797,6 +774,14 @@ FinishCollisionCheck:
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to switch CHR banks
;; Params = A has the bank number
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc SwitchCHRBank
sta $8000 ; $8000 is the bank switch register of mapper 3
rts
.endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reset handler (called when the NES resets or powers on)
@ -816,9 +801,9 @@ InitVariables:
lda #165
sta YPos
lda #$10
sta Seed+1
sta Seed+0 ; Initialize the seed with any value not zero
lda #$10
sta Seed+1
sta Seed+0 ; Initialize the Seed with any value different than zero
Main:
jsr LoadPalette ; Call LoadPalette subroutine to load 32 colors into our palette
@ -932,6 +917,14 @@ GameLoop:
jsr AddNewActor ; Call the subroutine to add a new missile actor
:
CheckSelectButton:
lda Buttons
and #BUTTON_SELECT
beq :+
lda #1
jsr SwitchCHRBank
:
jsr SpawnActors
jsr UpdateActors
jsr RenderActors
@ -957,40 +950,36 @@ OAMStartDMACopy: ; DMA copy of OAM data from RAM to PPU
lda #$02 ; Every frame, we copy spite data starting at $02**
sta PPU_OAM_DMA ; The OAM-DMA copy starts when we write to $4014
;; TODO
;; Loop all bytes of the background buffer at $7000 until we find length=0
;; Sending the tiles to the PPU nametable in VRAM
BackgroundCopy:
lda #$70
sta BufPtr+1
lda #$00
sta BufPtr
BackgroundCopy: ; Here is where we copy/draw the background buffer from $7000 to the PPU
lda #$70
sta BufPtr+1
lda #$00
sta BufPtr+0 ; Set BufPtr pointer to start at address $7000
ldy #$00
BufferLoop:
lda (BufPtr),y ; Fetch the length
beq EndBackgroundCopy ; if len is 0, stop reading from bg buffer
ldy #$00
BufferLoop:
lda (BufPtr),y ; Fetch the Length
beq EndBackgroundCopy ; If Length is 0, stop reading from background buffer
tax ; x = length
tax ; X = Length
iny
lda (BufPtr),y ; hi byte
sta PPU_ADDR
iny
lda (BufPtr),y ; low byte
sta PPU_ADDR
iny
DataLoop:
lda (BufPtr),y
sta PPU_DATA
iny
dex ; X--
bne DataLoop
iny
lda (BufPtr),y ; Fetch hi-byte of PPU address to be updated
sta PPU_ADDR
iny
lda (BufPtr),y ; Fetch lo-byte of PPU address to be updated
sta PPU_ADDR
iny
DataLoop:
lda (BufPtr),y
sta PPU_DATA
iny
dex ; X--
bne DataLoop
jmp BufferLoop
jmp BufferLoop ; Loop back until we finish the buffer (find an entry with Length=0)
EndBackgroundCopy:
NewColumnCheck:
lda XScroll
and #%00000111 ; Check if the scroll a multiple of 8
@ -1258,8 +1247,11 @@ AttributeData:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Here we add the CHR-ROM data, included from an external .CHR file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "CHARS"
.incbin "atlantico.chr"
.segment "CHARS1"
.incbin "atlantico.chr" ; This is the 1st bank of CHR-ROM tiles
.segment "CHARS2"
.incbin "titlescreen.chr" ; This is the 2nd bank of CHR-ROM tiles
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Vectors with the addresses of the handlers that we always add at $FFFA

Binary file not shown.

Binary file not shown.

View File

@ -26,4 +26,7 @@ BUTTON_DOWN = $04 ; 00000100
BUTTON_LEFT = $02 ; 00000010
BUTTON_RIGHT = $01 ; 00000001
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Maximum number of actors that we can have
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAX_ACTORS = 10

View File

@ -1,11 +1,11 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The iNES header (contains a total of 16 bytes with the flags at $7FF0)
;; The iNES header (contains a total of 16 bytes with the flags at $7F00)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "HEADER"
.byte $4E,$45,$53,$1A ; 4 bytes with the characters 'N','E','S','\n'
.byte $02 ; How many 16KB of PRG-ROM we'll use (=32KB)
.byte $01 ; How many 8KB of CHR-ROM we'll use (=8KB)
.byte %00000001 ; Vertical mirroring, no battery, mapper 0
.byte $02 ; How many 8KB of CHR-ROM we'll use (=16KB)
.byte %00110001 ; Mapper 003, Vertical mirroring, no battery
.byte %00000000 ; mapper 0, playchoice, NES 2.0
.byte $00 ; No PRG-RAM
.byte $00 ; NTSC TV format

View File

@ -1,16 +1,18 @@
MEMORY {
ZP: start = $0000, size = $0100, type = rw, file = "";
OAM: start = $0200, size = $0100, type = rw, file = "";
RAM: start = $0300, size = $0500, type = rw, file = "";
HDR: start = $7FF0, size = $0010, type = ro, file = %O, fill = yes, fillval = $00;
PRG: start = $8000, size = $8000, type = ro, file = %O, fill = yes, fillval = $00;
CHR: start = $0000, size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
ZP: start = $0000, size = $0100, type = rw, file = "";
OAM: start = $0200, size = $0100, type = rw, file = "";
RAM: start = $0300, size = $0500, type = rw, file = "";
HDR: start = $7FF0, size = $0010, type = ro, file = %O, fill = yes, fillval = $00;
PRG: start = $8000, size = $8000, type = ro, file = %O, fill = yes, fillval = $00;
CHR1: start = $0000, size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
CHR2: start = $0000, size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
HEADER: load = HDR, type = ro;
CODE: load = PRG, type = ro, start = $8000;
CHARS: load = CHR, type = ro, optional = yes;
VECTORS: load = PRG, type = ro, start = $FFFA;
}
ZEROPAGE: load = ZP, type = zp;
HEADER: load = HDR, type = ro;
CODE: load = PRG, type = ro, start = $8000;
CHARS1: load = CHR1, type = ro, optional = yes;
CHARS2: load = CHR2, type = ro, optional = yes;
VECTORS: load = PRG, type = ro, start = $FFFA;
}

BIN
atlantico/titlescreen.chr Executable file

Binary file not shown.

View File

@ -17,21 +17,26 @@
sta PPU_DATA ; Send value to PPU register at $2007
.endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Macro to push and preserv registers A, X, Y, and status flags on the Stack.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.macro PUSH_REGS
pha ; Push A to the stack
txa ; transfer x to acc
pha ; Push X to the stack
tya ; transfer y to the acc
pha ; Push Y to the stack
php ; Push process status flags to the stack
pha ; Push A to the stack
txa
pha ; Push X to the stack
tya
pha ; Push Y to the stack
php ; Push Processor Status flags to the stack
.endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Macro to pull and restore registers A,X,Y, and status flags from the Stack.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.macro PULL_REGS
plp ; restore the status flags from the stack
pla ; restore the old value of Y from the stack into A
tay ; transfer
pla ; restore the old value of X from the stack into A
tax ; transfer
pla ; Pull a from the stack
plp ; Restore the the status flags from the stack
pla ; Restore the old value of X from the stack
tay
pla ; Restore the old value of X from the stack
tax
pla ; Pull A from the stack
.endmacro