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 .enum ActorType
NULL = 0 NULL = 0
PLAYER = 1 PLAYER = 1
@ -6,8 +9,12 @@
MISSILE = 4 MISSILE = 4
BOMB = 5 BOMB = 5
SPRITE0 = 6 SPRITE0 = 6
PARACHUTE = 7
.endenum .endenum
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Struct to hold the data for one actor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.struct Actor .struct Actor
Type .byte Type .byte
XPos .byte XPos .byte

View File

@ -8,9 +8,9 @@
;; Variables declared in RAM zero-page ;; Variables declared in RAM zero-page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "ZEROPAGE" .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) Buttons: .res 1 ; Pressed buttons (A|B|Sel|Start|Up|Dwn|Lft|Rgt)
PrevButtons: .res 1 ; Stores the previous buttons from the last frame 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) XVel: .res 1 ; Player X (signed) velocity (in pixels per 256 frames)
YVel: .res 1 ; Player Y (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 PrevSubmarine: .res 1 ; Stores the seconds that the last submarine was added
PrevAirplane: .res 1 ; Stores the value in seconds that the last airplane was added PrevAirplane: .res 1 ; Stores the seconds that the last airplane was added
Frame: .res 1 ; Counts frames (0 to 255 and repeats) Frame: .res 1 ; Counts frames (0 to 255 and repeats)
IsDrawComplete: .res 1 ; Flag to indicate when VBlank is done drawing 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) BgPtr: .res 2 ; Pointer to background address - 16bits (lo,hi)
SprPtr: .res 2 ; Pointer to the sprite 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 XScroll: .res 1 ; Store the horizontal scroll position
CurrNametable: .res 1 ; Store the current starting nametable (0 or 1) 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 ParamTileNum: .res 1 ; Used as parameter to subroutine
ParamNumTiles: .res 1 ; Used as parameter to subroutine ParamNumTiles: .res 1 ; Used as parameter to subroutine
ParamAttribs: .res 1 ; Used as parameter to subroutine ParamAttribs: .res 1 ; Used as parameter to subroutine
ParamRectX1: .res 1 ; Used as parameter to subroutine ParamRectX1: .res 1 ; Used as parameter to subroutine
ParamRectY1: .res 1 ; Used as parameter to subroutine ParamRectY1: .res 1 ; Used as parameter to subroutine
ParamRectX2: .res 1 ; Used as parameter to subroutine ParamRectX2: .res 1 ; Used as parameter to subroutine
ParamRectY2: .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 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) ActorsArray: .res MAX_ACTORS * .sizeof(Actor)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PRG-ROM code located at $8000 ;; PRG-ROM code located at $8000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -81,135 +78,129 @@ LoopButtons:
rts rts
.endproc .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 ; This is a 16-bit Galois linear feedback shift register with polynomial $0039.
Increment1stDigit: ; The sequence of numbers it generates will repeat after 65535 calls.
lda Score+0 ; Execution time is an average of 125 cycles (excluding jsr and rts)
clc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
adc #1 .proc GetRandomNumber
sta Score+0 ldy #8 ; Loop counter (generates 8 bits)
cmp #$A lda Seed+0
bne DoneIncrementing : asl ; Shift the register
Increment10sDigit: rol Seed+1
lda #0 bcc :+
sta Score+0 eor #$39 ; Apply XOR feedback when a 1 bit is shifted out
lda Score+1 :
clc dey
adc #1 bne :--
sta Score+1 sta Seed+0 ; Saves the value in A into the Seed
cmp #$A cmp #0 ; Set flags
bne DoneIncrementing rts
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
.endproc .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 ;; 03 20 52 00 00 02 01 20 78 00 00
;; | \___/ \______/ | \___/ | | ;; | \___/ \______/ | \___/ | |
;; | | | | | | | ;; | | | | | | |
;; | | | | | | Length=0 (End of buffering) ;; | | | | | | Length=0 (end of buffering)
;; | | | | | byte to copy ;; | | | | | byte to copy
;; | | | | PPU Address $2078 ;; | | | | PPU Address $2078
;; | | | Length=1 ;; | | | Length=1
;; | | bytes to copy ;; | | bytes to copy
;; | PPU address $2052 ;; | PPU Address $2052
;; Length = ;; Length=3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc DrawScore .proc DrawScore
lda #$70 lda #$70
sta BufPtr+1 sta BufPtr+1
lda #$00 lda #$00
sta BufPtr+0 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 lda #$20
sta (BufPtr),y sta (BufPtr),y ; Hi-Byte of the PPU address to be updated
iny iny
lda #$52
sta (BufPtr),y ; Lo-Byte of the PPU address to be updated
iny
lda #$20 ;; Send the 3 digits of the score (from MSB to LSB) 100s, 10s, 1s
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 lda Score+2 ; 100s digit of the Score
;; Offset by #$60 to point to numbers clc
lda Score+2 ; 100s adc #$60 ; Offset by $60 to point to the correct tile
clc sta (BufPtr),y
adc #$60 iny
sta (BufPtr),y
iny
lda Score+1 ; 10s lda Score+1 ; 10s digit of the Score
clc clc
adc #$60 adc #$60 ; Offset by $60 to point to the correct tile
sta (BufPtr),y sta (BufPtr),y
iny iny
lda Score+0 ; 1s
clc
adc #$60
sta (BufPtr),y
iny
lda #0 lda Score+0 ; 1s digit of the Score
sta (BufPtr),y ; Length=0, to signal the end of the buffer clc
iny adc #$60 ; Offset by $60 to point to the correct tile
sta (BufPtr),y
iny
rts lda #0
.endproc sta (BufPtr),y ; Length=0 to signal the end of the buffer
iny
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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
.endproc .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 cmp #3 ; Only add a new submarine if the difference in time from the previous one is equal to 3
bne :+ bne :+
lda #ActorType::SUBMARINE lda #ActorType::SUBMARINE
sta ParamType ; Load parameter for the actor type sta ParamType ; Load parameter for the actor type
lda #223 lda #223
sta ParamXPos ; Load parameter for actor position X sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber ; load random number into A
jsr GetRandomNumber ; Fetch a new random number for the Y position of the submarine
lsr ; Divide by 8 (right shift thrice) lsr
lsr lsr
lsr lsr ; Divide the random number by 8 to get a healthy Y position range
clc clc
adc #180 ; add 180 to lower it adc #180 ; And then add 180 to to it to move the submarine to the bottom part of the screen
sta ParamYPos 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 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: SpawnAirplane:
lda Clock60 ; Submarines are added in intervals of 3 seconds lda Clock60 ; Submarines are added in intervals of 2 seconds
sec sec
sbc PrevAirplane 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 :+ bne :+
lda #ActorType::AIRPLANE lda #ActorType::AIRPLANE
sta ParamType ; Load parameter for the actor type sta ParamType ; Load parameter for the actor type
lda #235 lda #235
sta ParamXPos ; Load parameter for actor position X sta ParamXPos ; Load parameter for actor position X
jsr GetRandomNumber ; load random number into A
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) sta ParamYPos ; Load parameter for actor position Y
lsr
clc
adc #35 ; add 35 to lower it, so its not in the status bar
;Adjust the random Y to be between top and bottom jsr AddNewActor ; Call the subroutine to add the new airplane actor
sta ParamYPos
jsr AddNewActor ; Call the subroutine to add the new missile actor
lda Clock60 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 rts
.endproc .endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to check collisions ;; Subroutine to loop all enemy actors checking for collision with missile
;; PARAMS: ParamXPos, ParamYPos (x and y of missile) ;; Params = ParamXPos, ParamYPos (are the X and Y position of the missile)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc CheckEnemyCollision .proc CheckEnemyCollision
txa txa
pha ; Push and save the X register in the stack pha ; Push and save X register in the stack
ldx #0
stx Collision ; Collision = 0
EnemiesCollisionLoop: ldx #0
cpx #MAX_ACTORS * .sizeof(Actor) stx Collision ; Collision = 0
beq FinishCollisionCheck
lda ActorsArray+Actor::Type,x
cmp #ActorType::AIRPLANE
bne NextEnemy ; If not an airplane - skip to next enemy type
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 cmp #ActorType::AIRPLANE
bne NextEnemy ; If it's NOT Airplane, bypass this enemy and move check the next one 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 adc #8 ; Get the bottom of the airplane bounding box by adding 8
sta ParamRectY2 ; Bouding Box Y2 sta ParamRectY2 ; Bouding Box Y2
jsr IsPointInsideBoundingBox jsr IsPointInsideBoundingBox ; Proceed to test if point is inside bounding box
lda Collision lda Collision
beq NextEnemy beq NextEnemy ; If no collision, don't do anything
lda #ActorType::NULL ; Set actor to null - TODO: maybe make an explosion lda #ActorType::NULL ; Else, destroy airplane
sta ActorsArray+Actor::Type,x sta ActorsArray+Actor::Type,x ; If collision happened, destroy airplane entity
jmp FinishCollisionCheck 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: FinishCollisionCheck:
pla pla
tax tax ; Pull and restore the old value of X
rts rts
.endproc .endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to check if a point is inside a bounding box. ;; Subroutine to check if a point is inside a bounding box.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Params: ;; Params:
;; (ParamXPos, ParamYPos) - coords to be tested ;; (ParamXPos,ParamYPos) are the coords of the point to be tested
;; (ParamRectX1,ParamRectY1,ParamRectX2,ParamRectY2) Are rectangle coords) ;; (ParamRectX1,ParamRectY1,ParamRectX2,ParamRectY2) are rectangle coords
;; Output: ;; Output:
;; Collision flag is either 1 or 0 ;; Collision flag is either 1 or 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.proc IsPointInsideBoundingBox .proc IsPointInsideBoundingBox
lda ParamXPos lda ParamXPos ; Fetch the point X coordinate
cmp ParamRectX1 cmp ParamRectX1 ; Compare it with the enemy rectangle X
bcc PointIsOutside bcc PointIsOutside ; If it's less, we stop checking because there is no collision
lda ParamYPos lda ParamYPos ; Fetch the point Y coordinate
cmp ParamRectY1 cmp ParamRectY1 ; Compare it with the enemy bounding box Y value
bcc PointIsOutside bcc PointIsOutside ; If it's less, we stop checking because there is no collision
lda ParamXPos lda ParamXPos ; Fetch the point X coorrinate
cmp ParamRectX2 cmp ParamRectX2 ; Compare it with the enemy bounding box right
bcs PointIsOutside bcs PointIsOutside ; If it's greater than, we stop checking because there is no collision
lda ParamYPos lda ParamYPos ; Fetch the point X coorrinate
cmp ParamRectY2 cmp ParamRectY2 ; Compare it with the enemy bounding box right
bcs PointIsOutside bcs PointIsOutside ; If it's greater than, we stop checking because there is no collision
PointIsInside: PointIsInside:
lda #1 lda #1 ; If we reach here, the point is inside the bounding box!
sta Collision sta Collision ; Collision detected!
jmp EndCollisionCheck jmp EndCollisionCheck
PointIsOutside: PointIsOutside:
lda #0 lda #0 ; If we branch here, the point was outside the bounding box
sta Collision sta Collision ; No collision detected!
EndCollisionCheck:
rts
EndCollisionCheck:
rts
.endproc .endproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Subroutine to loop all actors and update them (position, velocity, etc.) ;; 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 sta ActorsArray+Actor::Type,x ; Remove the missile from the array
SkipMissile: SkipMissile:
CheckCollision: CheckCollision:
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
clc clc
adc #3 adc #3
sta ParamXPos ; Missile position to be checked X += 3 sta ParamXPos ; Missile position to be checked X += 3 (plus 3 pixels from the left)
lda ActorsArray+Actor::YPos,x lda ActorsArray+Actor::YPos,x
clc clc
adc #1 adc #1
sta ParamYPos ; Missile position to be checked Y += 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 lda Collision ; If collision happened, delete the missile
beq NoCollisionFound beq NoCollisionFound
lda #ActorType::NULL ; Delete missile Actor lda #ActorType::NULL ; Delete missile actor
sta ActorsArray+Actor::Type,x sta ActorsArray+Actor::Type,x
jsr IncrementScore jsr IncrementScore ; Increment the Score variable using BCD-ish mode
jsr DrawScore jsr DrawScore ; Send the score bytes to the background buffer at $7000
NoCollisionFound:
NoCollisionFound:
jmp NextActor jmp NextActor
: :
cmp #ActorType::SUBMARINE cmp #ActorType::SUBMARINE
bne :+ bne :+
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
@ -604,20 +587,18 @@ FinishCollisionCheck:
SkipSubmarine: SkipSubmarine:
jmp NextActor jmp NextActor
: :
cmp #ActorType::AIRPLANE cmp #ActorType::AIRPLANE
bne :+ bne :+
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
sec sec
sbc #1 ; Decrement Y position of submarine by 1 sbc #1 ; Decrement Y position of airplane by 1
sta ActorsArray+Actor::XPos,x sta ActorsArray+Actor::XPos,x
bcs SkipAirplane bcs SkipAirplane
lda #ActorType::NULL 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: SkipAirplane:
jmp NextActor jmp NextActor
: :
NextActor: NextActor:
txa txa
clc clc
@ -672,7 +653,6 @@ FinishCollisionCheck:
jsr DrawSprite ; Call routine to draw 4 PLAYER tiles to the OAM jsr DrawSprite ; Call routine to draw 4 PLAYER tiles to the OAM
jmp NextActor jmp NextActor
: :
cmp #ActorType::SUBMARINE cmp #ActorType::SUBMARINE
bne :+ bne :+
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
@ -685,10 +665,9 @@ FinishCollisionCheck:
sta ParamAttribs sta ParamAttribs
lda #4 lda #4
sta ParamNumTiles 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 jmp NextActor
: :
cmp #ActorType::AIRPLANE cmp #ActorType::AIRPLANE
bne :+ bne :+
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
@ -701,10 +680,9 @@ FinishCollisionCheck:
sta ParamAttribs sta ParamAttribs
lda #3 lda #3
sta ParamNumTiles 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 jmp NextActor
: :
cmp #ActorType::MISSILE cmp #ActorType::MISSILE
bne :+ bne :+
lda ActorsArray+Actor::XPos,x lda ActorsArray+Actor::XPos,x
@ -720,7 +698,6 @@ FinishCollisionCheck:
jsr DrawSprite ; Call routine to draw 1 MISSILE tile to the OAM jsr DrawSprite ; Call routine to draw 1 MISSILE tile to the OAM
jmp NextActor jmp NextActor
: :
NextActor: NextActor:
txa txa
clc clc
@ -797,6 +774,14 @@ FinishCollisionCheck:
rts rts
.endproc .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) ;; Reset handler (called when the NES resets or powers on)
@ -816,9 +801,9 @@ InitVariables:
lda #165 lda #165
sta YPos sta YPos
lda #$10 lda #$10
sta Seed+1 sta Seed+1
sta Seed+0 ; Initialize the seed with any value not zero sta Seed+0 ; Initialize the Seed with any value different than zero
Main: Main:
jsr LoadPalette ; Call LoadPalette subroutine to load 32 colors into our palette 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 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 SpawnActors
jsr UpdateActors jsr UpdateActors
jsr RenderActors 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** 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 sta PPU_OAM_DMA ; The OAM-DMA copy starts when we write to $4014
;; TODO BackgroundCopy: ; Here is where we copy/draw the background buffer from $7000 to the PPU
;; Loop all bytes of the background buffer at $7000 until we find length=0 lda #$70
;; Sending the tiles to the PPU nametable in VRAM sta BufPtr+1
BackgroundCopy: lda #$00
lda #$70 sta BufPtr+0 ; Set BufPtr pointer to start at address $7000
sta BufPtr+1
lda #$00
sta BufPtr
ldy #$00 ldy #$00
BufferLoop: BufferLoop:
lda (BufPtr),y ; Fetch the length lda (BufPtr),y ; Fetch the Length
beq EndBackgroundCopy ; if len is 0, stop reading from bg buffer beq EndBackgroundCopy ; If Length is 0, stop reading from background buffer
tax ; x = length tax ; X = Length
iny iny
lda (BufPtr),y ; hi byte lda (BufPtr),y ; Fetch hi-byte of PPU address to be updated
sta PPU_ADDR sta PPU_ADDR
iny iny
lda (BufPtr),y ; low byte lda (BufPtr),y ; Fetch lo-byte of PPU address to be updated
sta PPU_ADDR sta PPU_ADDR
iny iny
DataLoop: DataLoop:
lda (BufPtr),y lda (BufPtr),y
sta PPU_DATA sta PPU_DATA
iny iny
dex ; X-- dex ; X--
bne DataLoop bne DataLoop
jmp BufferLoop jmp BufferLoop ; Loop back until we finish the buffer (find an entry with Length=0)
EndBackgroundCopy: EndBackgroundCopy:
NewColumnCheck: NewColumnCheck:
lda XScroll lda XScroll
and #%00000111 ; Check if the scroll a multiple of 8 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 ;; Here we add the CHR-ROM data, included from an external .CHR file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "CHARS" .segment "CHARS1"
.incbin "atlantico.chr" .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 ;; 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_LEFT = $02 ; 00000010
BUTTON_RIGHT = $01 ; 00000001 BUTTON_RIGHT = $01 ; 00000001
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Maximum number of actors that we can have
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAX_ACTORS = 10 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" .segment "HEADER"
.byte $4E,$45,$53,$1A ; 4 bytes with the characters 'N','E','S','\n' .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 $02 ; How many 16KB of PRG-ROM we'll use (=32KB)
.byte $01 ; How many 8KB of CHR-ROM we'll use (=8KB) .byte $02 ; How many 8KB of CHR-ROM we'll use (=16KB)
.byte %00000001 ; Vertical mirroring, no battery, mapper 0 .byte %00110001 ; Mapper 003, Vertical mirroring, no battery
.byte %00000000 ; mapper 0, playchoice, NES 2.0 .byte %00000000 ; mapper 0, playchoice, NES 2.0
.byte $00 ; No PRG-RAM .byte $00 ; No PRG-RAM
.byte $00 ; NTSC TV format .byte $00 ; NTSC TV format

View File

@ -1,16 +1,18 @@
MEMORY { MEMORY {
ZP: start = $0000, size = $0100, type = rw, file = ""; ZP: start = $0000, size = $0100, type = rw, file = "";
OAM: start = $0200, size = $0100, type = rw, file = ""; OAM: start = $0200, size = $0100, type = rw, file = "";
RAM: start = $0300, size = $0500, type = rw, file = ""; RAM: start = $0300, size = $0500, type = rw, file = "";
HDR: start = $7FF0, size = $0010, type = ro, file = %O, fill = yes, fillval = $00; 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; 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; 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 { SEGMENTS {
ZEROPAGE: load = ZP, type = zp; ZEROPAGE: load = ZP, type = zp;
HEADER: load = HDR, type = ro; HEADER: load = HDR, type = ro;
CODE: load = PRG, type = ro, start = $8000; CODE: load = PRG, type = ro, start = $8000;
CHARS: load = CHR, type = ro, optional = yes; CHARS1: load = CHR1, type = ro, optional = yes;
VECTORS: load = PRG, type = ro, start = $FFFA; 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 sta PPU_DATA ; Send value to PPU register at $2007
.endmacro .endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Macro to push and preserv registers A, X, Y, and status flags on the Stack.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.macro PUSH_REGS .macro PUSH_REGS
pha ; Push A to the stack pha ; Push A to the stack
txa ; transfer x to acc txa
pha ; Push X to the stack pha ; Push X to the stack
tya ; transfer y to the acc tya
pha ; Push Y to the stack pha ; Push Y to the stack
php ; Push process status flags to the stack php ; Push Processor Status flags to the stack
.endmacro .endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Macro to pull and restore registers A,X,Y, and status flags from the Stack.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.macro PULL_REGS .macro PULL_REGS
plp ; restore the status flags from the stack plp ; Restore the the status flags from the stack
pla ; restore the old value of Y from the stack into A pla ; Restore the old value of X from the stack
tay ; transfer tay
pla ; restore the old value of X from the stack into A pla ; Restore the old value of X from the stack
tax ; transfer tax
pla ; Pull a from the stack pla ; Pull A from the stack
.endmacro .endmacro