From 3999c5d6c591979107c76e839190d3969695c892 Mon Sep 17 00:00:00 2001 From: Tyrel Souza Date: Tue, 24 Jan 2023 23:45:50 -0500 Subject: [PATCH] change CHR bank --- atlantico/actor.inc | 7 + atlantico/atlantico.asm | 532 +++++++++++++++++++------------------- atlantico/atlantico.nes | Bin 40976 -> 49168 bytes atlantico/atlantico.o | Bin 56551 -> 69980 bytes atlantico/consts.inc | 3 + atlantico/header.inc | 6 +- atlantico/nes.cfg | 26 +- atlantico/titlescreen.chr | Bin 0 -> 8192 bytes atlantico/utils.inc | 31 ++- 9 files changed, 307 insertions(+), 298 deletions(-) mode change 100644 => 100755 atlantico/actor.inc create mode 100755 atlantico/titlescreen.chr diff --git a/atlantico/actor.inc b/atlantico/actor.inc old mode 100644 new mode 100755 index c9139b0..5761a12 --- a/atlantico/actor.inc +++ b/atlantico/actor.inc @@ -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 diff --git a/atlantico/atlantico.asm b/atlantico/atlantico.asm index ca21cf9..61d90bd 100755 --- a/atlantico/atlantico.asm +++ b/atlantico/atlantico.asm @@ -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 diff --git a/atlantico/atlantico.nes b/atlantico/atlantico.nes index a4f6eb7edc1709a93b03991a596176e8620eead0..cbf190d351fa719267d9909fb66ce25d97a2851f 100644 GIT binary patch delta 652 zcmX|8&ubGw6rP#g{2&QUTQ!}eO)@sMZGIeLq7pCWRIFhULE0kZkfZC(OA!yrX445$ zEF=tpcq^4TOp#DX19~f1#GKs!KraeKgq);@)Hs_OVP@X@=KJ{Gn|X~B)G!p+!?njD zgl;xn;rsh;zUo#D>_gHZODB#eBP{NRekRux+3B3{`uGmm% z7IQNxL_~hiNd%C`KKQWNe4mEf&9e=-&GIlF$W==R;9F!6>LvPM;NHc$a;QCFWf-U| z2t>o;D~*t=Mxju^`Z0~tDA}rVKlO5d?z^v#te{Y&=;uEX)?*Weue7^<0P3pr&PZ>? zTIwZfte2uPVm&}_^io)N(`7QMa&_Pmpq0>u)yw*ys!tC~Yz~FtBD;+evnRI1V@t@2 zL5hZEvghc^HPe)~)4gQw47QR->e#|$Z%{_vs%dHV1%)n?Uz5bEgw|}T)>o~NY$qby ziHb**2uK&@zD~yMxQTvbplEHgy?(lKG$TgM+0Xx%c8@(%Qpz4MSW79Um?50<4*-pb z`SI(eQ<%GGgu5qjPO<@tNr#2iV4!3Cz;YhIE<0f^45q2`NCsWKWB;)uP6iGENx4Q| zR7uPvuT4HR7)qllO=rjIt?u~&e>3Fwe);79+ o1CqDXhSN7pXS1V99t?-s3|pu#`N|mM;rTfzm)q^GRzD5?1(A5?3;+NC delta 709 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 literal 56551 zcmeHw34E00wf=XKkOUMVGnqEpR%g_@Q0*196)ZInf&v#2S;iq(Z$V6JS`6F}THErM zHEaR`0t(0~Q5ZoM!4;K7WmAa)3d)WwE^SqOpH!~TXivI8acP~+%obNg3 zJ@0wXd%pKuXVT>##oekUI^o~x_??37y7+xZ zj^q4si{tdqaGd?yja_Eg?m&1uB_*Z#@tv!tr)S9D7FP6FzbG|zc8gIx-p$B)c-T*R ztV=)lk5k9@cwH{N?(G$(PcMfP?ch6AAnJUiFDA9Jxdm zrbL}A1V2{((~;u}-Q?>GN6KYq1})Hw1KE)rnOVn4DH6FtgBWdspmsF6Usq2Cq2mgf z3inqkrp$9>H#W*-Xlm5cPy|#iFQk*v+(K60&!^G%yHJiRXbE0Y1nH$4rY z?+;DXsp|VfM!g}O&V$$}lef}1D5~FrC!}OGJXOd>s2yTA8H=fy*IVw-)E3Vn9G%K+ zcpS(oc@IM_m-o@NX7VykG&A`=jOxik;3b0oBTCK!`W-7T zK$oJJ(x$0=j7W#eJD@6L3DjQ_%cP;zlztmx-W_=khTY@@!nq=4fxLt)q3SYKqL?$;l)mO- z$IFq2Fx(;;oLRTE=Cc=<(!ty%>qSlLY1<`;qo&U#h^9zpNZmHkwlfe*nfyN1^!J$5 zG}#U1X!(_s;&_2rj$dRw=r43I3c+ay(R__UAfsh8vYqbLUocvUq=s!EtJ-LRv(LxO zvqZ|_Z?P;lGseL#N8{1*0QQ6oul|B%1)^UsqoAmeO$h8OVmBGiOdT`3BB%QpqHH7b z08&*?-hpo{XTThJ6=ha*k*r|J3=Zc!8vbB<+G!$Ywe3XDZRJhyZRJ(;+*Y=t=eF_$ z`G2U-e}~HzG7EH>yltkQRrofiez;jVIQPTR`{h+K07i4?mBV z(9gByTXALi76K@e5vk!4V$%`mrA&fxss% zE9Euxd>(O`RE4Lak?zm<=YZkz`Y8IWlmYORNgOEwEuww84yDQ`a1oRRz;<#I7tA}f zobhNUI}lX4d}1umSIbXm`Iv3V!#K=oOCjJm!fUOAP*3=C1Hr{Jfpd=8&&RHTE zsYDcIGQvd1(TqTJUOACU7yqG2Ji&coxaplE7!F5e@}XfE`-fo4Wq~=|&}IQVH<72& z*?u{0__H;j+mbap3tg7UgJw(@X;=?pOv_|Uc=d?Z z=okcACbNv?#cDZ=mh){(`kW6-BvyB~pGY%pwa)A>ajOtPC;E)z|W(fdU3 zugWGQesJ1ACUp~HTqGyK*C&?CW@FD%-c0+i%_K0JUt^eyV zOktUWhBf*m0?CmFwc1kUBQ(b4mX+b>kc?$G)3%zi=h4V>j{F_1ME0;opRw}%3|e{R z4O645v{c?eH|1g`mPtj-mGS}ltEZ@u??9u8GQ*CLkI3;;N9hFz|-NWwOB@2Zz4_<7k3Q7H0V=_?;+A?w?>oxGG5jpZe?TAf4~74jj*(vY}JD(#Unm`Z4y$m=GUD>atI zaW;!#vq&Z&S80kG%K;{CMO>+^K#c8ViAfyuvINXX`3CkmGRo}Q+du{7eRy3b4?{km zSRt=~nL_L)8?>}ilO5soxG-LGI<-TOxQ;xHES1R|QwFMq%+s(hu>#FT2|&M0 zw#8NEHeI9BWhOeWz<+uSS6n7f*!u(%^aLwyohc)(0PARZ$ac#5Jj8wTb+e~)-+x`J zthYSGC}$gmSEHP*3a>QL=*J-6gVP3HsQegRI7R-f{1OZryifTh@PMPeIbrw%Zeu{! zL=QJ>XcJ|IXJSkudpV{F9FyWQX<_Y198wE)|FH>&Bl;K>v`h{ojgcLdBRb6NA2DO+ zh>qyAbdş*K{do{pMOj&GZvgViu9MK$YkS3RCgTG<9 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 BepLVf literal 0 HcmV?d00001 diff --git a/atlantico/utils.inc b/atlantico/utils.inc index b21f1f6..2320f11 100755 --- a/atlantico/utils.inc +++ b/atlantico/utils.inc @@ -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