JOUST 7800 NTSC Source Code
From 8BitDev.org - Atari 7800 Development Wiki
Joust 7800 NTSC Source Code
This reverse engineered 7800 Joust code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.
;------------------------------------------------------------------------------ ; Disassembly of Joust NTSC for the Atari 7800 console ; ; 2025-08-20 - Mike Saarna ; * Initial public release. ; * Game logic and all routines identified and documented. ; ; "Our goal at GCC was to bring arcade-quality games home. With the 7800, ; we wanted it to feel as close as possible to what you remembered from ; the arcade." ; --Steve Golson, GCC ; ; Joust 7800 is a faithful recreation of the arcade classic. The brilliant ; minds at GCC reverse engineered the original game to craft this stellar ; port. To produce this disassembly I had to reverse engineer a cloaked ; machine-generated listing, revealing GCC’s masterful work. Reverseception. ; ; --Mike Saarna ;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------ ; NOTABLE GAME DESIGN FEATURES: ; ; 1. Game Object System: ; The game manages all on-screen entities (players, enemies, eggs, ; pterodactyls) through a powerful "Game Object" system. Instead of unique ; code for each entity, properties like position, velocity, and state are ; stored in parallel arrays in RAM. A single index represents a specific ; object. The game logic iterates through these objects, applying common ; routines for physics, rendering, and AI. ; ; 2. Event Scheduler (ES): ; The ESRoutineScheduler system manages timed and sequential game events ; without introducing purpose-specific code in the main game loop. It uses ; a list of timers and function pointers. When a timer expires, its ; corresponding routine is executed. This allows for complex, multi-frame ; sequences like the dissolving platforms, lava rising, and timed text ; messages to occur gracefully in the background while the main game action ; continues. ; ; 3. Sprites for the upcoming frame are added to render lists, in a format ; for eventual quick dumping to the DLs. This is a sort of pseudo double- ; buffer functionality. ; ; 4. 16-bit Sub-Pixel Physics: ; To achieve smooth, arcade-accurate movement, the game uses 16-bit values ; for object coordinates and velocities. This allows for fine-grained ; control over acceleration and movement. ; ;------------------------------------------------------------------------------ processor 6502 ;------------------------------------------------------------------------------ ; TIA/MARIA/RIOT Hardware Registers ;------------------------------------------------------------------------------ INPTCTRL = $01 INPT4 = $0C INPT5 = $0D AUDC0 = $15 AUDF0 = $17 AUDV0 = $19 AUDV1 = $1A BACKGRND = $20 P0C1 = $21 P0C2 = $22 P0C3 = $23 WSYNC = $24 P1C1 = $25 P1C2 = $26 P1C3 = $27 MSTAT = $28 P2C1 = $29 P2C2 = $2A P2C3 = $2B DPPH = $2C P3C1 = $2D P3C2 = $2E P3C3 = $2F DPPL = $30 P4C1 = $31 P4C2 = $32 P4C3 = $33 CHARBASE = $34 P5C1 = $35 P5C2 = $36 P5C3 = $37 OFFSET = $38 P6C1 = $39 P6C2 = $3A P6C3 = $3B CTRL = $3C P7C1 = $3D P7C2 = $3E P7C3 = $3F SWCHA = $0280 SWACNT = $0281 SWCHB = $0282 SWBCNT = $0283 ; ****************** VARIABLES P0Score = $40 ; to $42 P0ExtraLifeScore = $43 ; to $44 Score threshold for bonus life award P1Score = $45 ; to $47 P1ExtraLifeScore = $48 ; to $49 Score threshold for bonus life award PlayerCount = $4A DemoMode = $4B Difficulty = $4C TimerHi = $4D TimerLo = $4E IncrementingRandSeed = $4F P0LastFire = $50 P1LastFire = $51 P0CurrentFire = $52 P1CurrentFire = $53 MenuJoyDebounceTimer = $54 MenuSelectDebounceTimer = $55 MenuResetTimer = $56 PrevPausedState = $57 PrevResetState = $58 PrevSelectState = $59 TempPoint5ACurrentESRoutineLo = $5A TempPointLo5A = $5A TempPoint5ACurrentESRoutineHi = $5B TempPointHi5B = $5B TempPoint5CLo = $5C TempPoint5DHi = $5D ; Note that I've defined aliases for temps that are reused for ; various routines, to help maintain clarity in local routines. Temp5E = $5E Temp5EGfxDataLo = $5E TempPterryCoordY = $5E TempSavedYForHunterBirdSpawn = $5E Temp5F = $5F Temp5FGfxDataHi = $5F TempPterryCoordX = $5F Temp60 = $60 Temp60ScoreAdd = $60 Temp60PaletteAndWidth = $60 TempPterryScoreValue = $60 Temp60MinPhysicsXSpeedIndex = $60 Temp61 = $61 Temp61ScoreAdd = $61 Temp61SpriteXCoord = $61 Temp61MaxPhysicsXSpeedIndex = $61 Temp62 = $62 Temp62ScoreAdd = $62 Temp62MaxFallSpeed = $62 Temp63 = $63 Temp63SpriteYCoord = $63 Temp63MaxRiseSpeedNeg = $63 Temp64 = $64 Temp64SpriteYOffset = $64 Temp64WeightFactor = $64 Temp65 = $65 Temp66 = $66 TempCollisionOverlap = $67 ; the magnitude of overlap from collision checks Temp68 = $68 Temp69 = $69 Temp6ASFXIndex = $6A SFXChannel0Index = $6B ; Current sound effect playing on audio channel 0 SFXChannel1Index = $6C ; Current sound effect playing on audio channel 1 BridgeBurningWidth = $6D ESTemp6E = $6E ESTemp6ELavaRiseCounter = $6E ; ??? = $6F appears unused LeftFlameAnimationIndex = $70 RightFlameAnimationIndex = $71 TitleColorIndex = $70 TitleColorChangeCountdown = $71 EggsPresentCount = $72 ColorCycleIndex = $72 ; reused for title screen EnemyBirdCount = $73 ColorChangeTimer = $73 ; reused for title screen TrollState = $74 ; 0=hiding in lave, $FF=jumping out, $02=holding a bird TrollXCoord = $75 TrollYCoord = $76 TrollTargetIndex = $77 TrollGfxOffset = $78 PterryCountdownLo = $79 EasterEggJoyDownCount = $79 PterryCountdownHi = $7A EasterEggJoyLeftCount = $7A PterryAliveCount = $7B EnemyAITargetDelayBase = $7C TrollPullingVelocity = $7D TrollMinimumGrabYCoord = $7E TrollMinimumTargetYCoord = $7F BirdPhysicsIndexMinByType = $80 ; to $84 BirdPhysicsIndexMaxByType = $85 ; to $89 ; Eggs collected so far, to a max of 3. Used as an index to determine value ; of egg pickup. This gets reset on death or new wave. P0EggPointLevel = $8A P1EggPointLevel = $8B P0Lives = $8C P1Lives = $8D GamePacingTimer = $8E ; ensures game logic runs every other frame DemoTimer = $8F GameEndDelayTimer = $90 EnemyIsSpawning = $91 PlatformPresentBitmask = $92 Level = $93 LevelBCD = $94 GameActiveFlag = $95 ; 0=normal, 1=game is ending ; Game logic writes sprite data to a render list, and then the render list is ; used to update the DL in one shot. RenderListCount = $96 ; The number of sprites in the render list RenderListDirty = $97 ; A flag to indicate if the render list was ; updated since the last DL update. LevelWasSurvived = $98 ; keep track to award survival points PlayersWereATeam = $99 ; keep track to award team points PlayerWasGladiator = $9A ; keep track to award gladiator points PterryWave = $9B IsEggWave = $9C PlatformsInLevel = $9D ; The PlatformPresentBitmask from the previous wave... OldPlatformPresentBitmask = $9E MaxActiveEnemyIndex = $9F SpawnPlatformDissolved0 = $A0 SpawnPlatformDissolved1 = $A1 SpawnPlatformDissolved2 = $A2 SpawnPlatformDissolved3 = $A3 MaxEnemyBirdCount = $A4 EggWaveEnemyType = $A5 P0DeathState = $A6 P1DeathState = $A7 ; When a player bird dies, there's an explostion/particle cloud. ; These are the Coordinates for the cloud. PlayerExplosionXCoord = $A8 ; to $A9 PlayerExplosionYCoord = $AA ; to $AB ; A collection of event scheduler (ES) routine indexes. ESRoutineIndex = $AC ; to $BD ; A collection of event scheduler (ES) routine timers. ESRoutineTimer = $BE ; to $CF 18 timers total GameObjectState = $D0 ; $D0 | P0 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird ; $D1 | P1 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird ; $D2 - $D9 | EnemyBird(8) 0=dead 3=born1 4=normal 5=hit 6=invincible 7=born2 8=troll has bird $14=bird seeking rider ; $DA - $DC | Pterry(3) 0=dead A=normal B=charging C=leaving ; $DD - $E8 | Egg(12) 0=none 1=egg 2=hatching 3=rider+shell 4=rider PterryState1 = $DA PterryState2 = $DB PterryState3 = $DC EggState = $DD GameObjectAIMode = $E9 ; $E9 : P0 ; $EA : P1 ; $EB - $F2 : EnemyBird(8) GameObjectAlive = $F3 ; $F3 : P0 ; $F4 : P1 ; $F5 - $FC : EnemyBird(8) NMIModeFlag = $FD ; $00: Normal game NMI (in-game, title screen animation) - sound, input, render list processing. ; $01: 320A portion of split screen NMI mode. Automatically changes NMIModeFlag to $FF. ; $FF: 160A portion of split screen NMI mode. Automatically changes NMIModeFlag to $01. ; When a player bird enters a platform a bit low, it initiates a bounce/skip ; across the platform instead of walking. 0=not skipping, 1=skipping GameObjectPlatformSkipState = $14A ; $14A : P0 ; $14B : P1 ; $14C - $153 : EnemyBird(8) GameObjectXCoordHi = $154 ; $154 : P0 ; $155 : P1 ; $156 - $15D : EnemyBird(8) ; $15E - $160 : Pterry(3) ; $161 - $16C : Egg(12) EggX = $161 GameObjectYCoordHi = $16D ; $16D : P0 ; $16E : P1 ; $16F - $176 : EnemyBird(8) ; $177 - $179 : Pterry(3) ; $17A - $185 : Egg(12) EggY = $17A ; The palette+width used to eventually render the bird. BirdObjectPaletteAndWidth = $186 ; $186 : P0 ; $187 : P1 ; $188 - $18F : EnemyBird(8) PaletteInRam = $0190 ; to $01A7 P0C1_Ram = $0190 P0C2_Ram = $0191 P0C3_Ram = $0192 P1C1_Ram = $0193 P1C2_Ram = $0194 P1C3_Ram = $0195 P2C1_Ram = $0196 P2C2_Ram = $0197 P2C3_Ram = $0198 P3C1_Ram = $0199 P3C2_Ram = $019A P3C3_Ram = $019B P4C1_Ram = $019C P4C2_Ram = $019D P4C3_Ram = $019E P5C1_Ram = $019F P5C2_Ram = $01A0 P5C3_Ram = $01A1 P6C1_Ram = $01A2 P6C2_Ram = $01A3 P6C3_Ram = $01A4 P7C1_Ram = $01A5 P7C2_Ram = $01A6 P7C3_Ram = $01A7 Platform56GfxLo = $1A13 Platform56PaletteWidth = $1A14 Platform4GfxLo = $1A6D Platform4PaletteWidth = $1A6E Platform0GfxLo = $1D43 Platform0PaletteWidth = $1D44 Platform4XCoordinate = $1A70 ; DL object's X coordinate SpawnPoint4XCoordinate = $1A74 ; DL object's X coordinate Platform5XCoordinate = $1A16 ; DL object's X coordinate Platform6XCoordinate = $1A1A ; DL object's X coordinate Platform0XCoordinate = $1D46 ; DL object's X coordinate EasterEggXCoordinate1 = $1D96 EasterEggXCoordinate2 = $1DF0 EasterEggXCoordinate3 = $1E4B ; DL X-coordinate bytes for menu texts. MenuTwoPlayerTextXCoord = $1EA5 MenuDifficultyTextXCoord = $1EFF MenuOnePlayerTextXCoord = $1F59 BridgeRightGfxByte1 = $1F4F BridgeLeftGfxByte1 = $1F53 BridgeRightGfxByte2 = $1F57 BridgeLeftGfxByte2 = $1F5B BridgeRightGfxByte3 = $1FA5 BridgeLeftGfxByte3 = $1FA9 ; I think these are probably just graphics data hi bytes of lava sprites ; in a larger DL for the bottom level, and the lava level for each gets ; raised by changing them to scroll them out a DMA hole. LeftLavaLevelWave3 = $1FB0 RightLavaLevelWave3 = $1FAC LeftLavaLevelWave2 = $1FC3 RightLavaLevelWave2 = $1FC7 LeftLavaLevelWave1 = $1FD9 RightLavaLevelWave1 = $1FDD ; Used to derive bird walk cycle frame GameObjectFootstepAnimIndex = $1FF2 ; $1FF2 : P0 ; $1FF3 : P1 ; $1FF4 - $1FFB : EnemyBird(8) GameObjectFootstepAnimTimer = $1FFC ; $1FFC : P0 ; $1FFD : P1 ; $1FFE - $2005 : EnemyBird(8) UnusedBirdObjectArray1 = $2006 ; A bird object sized array that gets cleared with others, ; but it's never actually used after that. ; $2006 : P0 ; $2007 : P1 ; $2008 - $200F : EnemyBird(8) ; A bird timer delaying AI target re-evaluation GameObjectAITargetDelayTimer = $2010 ; $2010 : P0 ; $2011 : P1 ; $2012 - $2019 : EnemyBird(8) GameObjectSpawnPlatformIndex = $201A ; $201A : P0 ; $201B : P1 ; $201C - $2023 : EnemyBird(8) BirdInvulnerable = $2024 ; to 2025 ; When the bird spawns on a platform, this flag cycles: ; $FF, $02, $02, $01, $01, $00, $00 ; $2024 : P0 ; $2025 : P1 ; $2026 - $202D : EnemyBird(8) ; When the player tries to reverse direction when running on a platform, ; it initiates a skid until the bird comes to a stop. This location holds ; the skid direction/flag, or zero when not-skidding. GameObjectSkidDirection = $202E ; $202E : P0 ; $202F : P1 ; $2030 - $2037 : EnemyBird(8) P0SkidDirection = $202E P1SkidDirection = $202F MessageLine0Enable = $2038 ; $2040 to $20FF: 7800 console ram block 0 shadow MessageLine0Timer = $2108 MessageLine1Timer = $2109 MessageLine2Timer = $210A MessageLine3Timer = $210B ; These unused player state bytes are cleared but never used. UnusedPlayerStateArray = $210C ; to $210D TempSpawnUnsafeCounter = $2110 ; to $2113 P0JoyDelay = $2114 P1JoyDelay = $2115 P0FireDebounce = $2116 P1FireDebounce = $2117 ; $2140 to $21FF: 7800 console ram block 1 shadow ; Character strings for the animated titlescreen border TitleBorderStr0 = $2200 TitleBorderStr1 = $2201 TitleBorderStr2 = $2202 TitleBorderStr3 = $2203 TitleBorderStr4 = $2204 ; to $2223 TitleBorderStr5 = $2205 ; to $2223 ObjectWiggleAnimation = $220E ; only used for egg wiggle animation ; $220E : P0 ; $220F : P1 ; $2210 - $2217 : EnemyBird(8) ; $2218 - $221A : Pterry(3) ; $221B - $2226 : Egg(12) GameObjectXCoordLo = $2227 ; sub-pixel X ; $2227 : P0 ; $2228 : P1 ; $2229 - $2230 : EnemyBird(8) ; $2231 - $2233 : Pterry(3) ; $2234 - $223F : Egg(12) GameObjectYCoordLo = $2240 ; sub-pixel Y ; $2240 : P0 ; $2241 : P1 ; $2242 - $2249 : EnemyBird(8) ; $224A - $224C : Pterry(3) ; $224D - $2258 : Egg(12) TitleCopyrightCharBuffer = $2244 ; to $225F TitleScreenLogoCharBuffer = $2260 ; to $2347 ObjectBirdLevelAndType = $2259 ; 0:red-bounder, 1:gray-hunter, 2:blue-shadowlord, 3:??, 4:pterry ; $2259 : P0 ; $225A : P1 ; $225B - $2262 : EnemyBird(8) ; $2263 - $2265 : Pterry(3) ; $2266 - $2271 : Egg(12) EggLevelAndType = $2266 GameObjectInAir = $2272 ; ... i.e. not standing on a platform. ; $2272 : P0 ; $2273 : P1 ; $2274 - $227B : EnemyBird(8) ; $227C - $227E : Pterry(3) ; $227F - $228A : Egg(12) GameObjectYVelocityLo = $228B ; $228B : P0 ; $228C : P1 ; $228D - $2294 : EnemyBird(8) ; $2295 - $2297 : Pterry(3) ; $2298 - $22A3 : Egg(12) GameObjectYVelocityHi = $22A4 ; $22A4 : P0 ; $22A5 : P1 ; $22A6 - $22AD : EnemyBird(8) ; $22AE - $22B0 : Pterry(3) ; $22B1 - $22BC : Egg(12) GameObjectXVelocity = $22BD ; $22BD : P0 ; $22BE : P1 ; $22BF - $22C6 : EnemyBird(8) ; $22C7 - $22C9 : Pterry(3) ; $22CA - $22D5 : Egg(12) GameObjectHunterIndex = $22D6 ; When one game object tagets another, the index of the hunter is ; stored here. E.g. the index of a riderless bird targetting a reborn rider ; There's a corresponding GameObjectPreyIndex that would store the index ; of the reborn rider. ; $22D6 : P0 ; $22D7 : P1 ; $22D8 - $22DF : EnemyBird(8) ; $22E0 - $22E2 : Pterry(3) ; $22E3 - $22EE : Egg(12) UnusedGameObjectArray2 = $22EF ; A game object sized array that gets cleared with others ; but it's never actually used after that. ; $22EF : P0 ; $22F0 : P1 ; $22F1 - $22F8 : EnemyBird(8) ; $22F9 - $22FB : Pterry(3) ; $22FC - $2307 : Egg(12) GameObjectCountdownHi = $2308 ; $2308 : P0 ; $2309 : P1 ; $230A - $2311 : EnemyBird(8) ; $2312 - $2314 : Pterry(3) ; $2315 - $2320 : Egg(12) GameObjectCountdownLo = $2321 ; $2321 : P0 ; $2322 : P1 ; $2323 - $232A : EnemyBird(8) ; $232B - $232D : Pterry(3) ; $232E - $2339 : Egg(12) GameObjectDirection = $233A ; $233A : P0 ; $233B : P1 ; $233C - $2343 : EnemyBird(8) ; $2344 - $2346 : Pterry(3) ; $2347 - $2352 : Egg(12) GameObjectAnimationFrame = $2360 ; $2360 : P0 ; $2361 : P1 ; $2362 - $2369 : EnemyBird(8) ; $236A - $236C : Pterry(3) ; $236D - $2378 : Egg(12) ; ??? = $2379 ; unused? GameObjectPreyIndex = $237A ; $237A : P0 ; $237B : P1 ; $237C - $2383 : EnemyBird(8) ; $2384 - $2385 : Pterry(3) GameObjectTimerResetValue = $2387 ; $2387 : P0 ; $2388 : P1 ; $2389 - $2390 : EnemyBird(8) ; $2391 - $2393 : Pterry(3) GameObjectEventTimer1 = $2394 ; $2394 : P0 ; $2395 : P1 ; $2396 - $239D : EnemyBird(8) ; $239E - $23A0 : Pterry(3) GameObjectAnimationCounter = $23A1 ; Seems to only be used by pterry. ; A animation countdown that's used to derive the flap frame used. ; $23A1 : P0 ; $23A2 : P1 ; $23A3 - $23AA : EnemyBird(8) ; $23AB - $23AD : Pterry(3) GameObjectAnimationDelay = $23AE ; Also only used by pterry. ; Used to add delay between the pterry flap frames. ; $23AE : P0 ; $23AF : P1 ; $23B0 - $23B7 : EnemyBird(8) ; $23B8 - $23BA : Pterry(3) GameObjectChargingTimer = $23BB ; Used for timing of pterry charging at the player, ; and riderless birds sliding at riders. ; $23BB : P0 ; $23BC : P1 ; $23BD - $23C4 : EnemyBird(8) ; $23C5 - $23C7 : Pterry(3) PterryDefeatedFlag = $23C8 ; to $23CA (Pterry objects only) ; $23C8 - $23C4 : Pterry(3) ; Note this is an alias for the same underlying memory as PterryDefeatedFlag. EnemyBirdTypesForLevel = $23C8 ; to ???? PterryAgressionFlag = $23D2 ; to $23D4 ; forces faster respawn on higher levels ; $23D5 - $23D9 don't seem to be used, other than getting cleared ; with other game objects at the game start/end. GameObjectTurnCheckTimerLo = $23DA ; seems to get read when the dead bird flys off-screen ; $23DA : P0 ; $23DB : P1 ; $23DC - $23E3 : EnemyBird(8) GameObjectTurnCheckTimerHi = $23E4 ; $23E4 : P0 ; $23E5 : P1 ; $23E6 - $23ED : EnemyBird(8) ; Index into tables that load turn timer values. GameObjectTurnTimerIndex = $23EE ; $23EE : P0 ; $23EF : P1 ; $23F0 - $23F7 : EnemyBird(8) ; A Hi timer controlling the frequency of AI decision-making for birds. ; For details see the comments below for it's Lo timer counterpart. GameObjectAITimerHi = $23F8 ; $23F8 : P0 ; $23F9 : P1 ; $23FA - $2401 : EnemyBird(8) ; A Lo timer controlling the frequency of AI decision-making for birds ; and pterodactyls. Birds use this lo timer and it's hi counterpart to, ; for example, randomly turn around. Pterrys use it, for example, to home ; in on prey. GameObjectAITimerLo = $2402 ; $2402 : P0 ; $2403 : P1 ; $2404 - $240B : EnemyBird(8) ; $240C - $240E : Pterry(3) ; Flags for platform dissolving sprite animation PlatformDissolveAnimationFlag0 = $240F PlatformDissolveAnimationFlag1 = $2410 PlatformDissolveAnimationFlag2 = $2411 PlatformDissolveAnimationFlag3 = $2412 PlatformDissolveAnimationFlag4 = $2413 PlatformDissolveAnimationFlag5 = $2414 PlatformDissolveAnimationXCoord0 = $2415 PlatformDissolveAnimationXCoord1 = $2416 PlatformDissolveAnimationXCoord2 = $2417 PlatformDissolveAnimationXCoord3 = $2418 PlatformDissolveAnimationXCoord4 = $2419 PlatformDissolveAnimationXCoord5 = $241A PlatformDissolveAnimationYCoord0 = $241B PlatformDissolveAnimationYCoord1 = $241C PlatformDissolveAnimationYCoord2 = $241D PlatformDissolveAnimationYCoord3 = $241E PlatformDissolveAnimationYCoord4 = $241F PlatformDissolveAnimationYCoord5 = $2420 RiderObjectPaletteAndWidth = $2421 ; $2421 : P0 ; $2422 : P1 ; $2423 - $242A : EnemyBird(8) ; RAM structures containing DL addresses DisplayListLo = $242B ; to $2442 DisplayListHi = $2443 ; to $245A ; Game logic writes sprite data to a render list, and then the render list is ; used to update the DLs in one shot. RenderListDLLo = $245B ; to $24AF RenderListDLHi = $24B0 ; to $2504 RenderListGfxDataLo = $2505 ; to $2559 RenderListGfxDataHi = $255A ; to $25AE RenderListPaletteAndWidth = $25AF ; to $2603 RenderListXCoord = $2604 ; to $2658 HudDisplayStringBuffer = $2659 ; to ??? HudWaveNumberDigit1 = $267C HudWaveNumberDigit2 = $267D MenuLine1CharBuffer = $2685 ; "TWO PLAYER" text MenuLine2CharBuffer = $2699 ; "ONE PLAYER" text DifficultyLevelCharBuffer = $26AD SurvivalWaveFlag = $26C1 TeamWaveFlag = $26C2 GladiatorWaveFlag = $26C3 ScorePopup_ActiveTimerBase = $26C4 ; Base for active timers for score popups (12 bytes) ScorePopup_ZoneIndexBase = $26DC ; Base for zone index for score popups (12 bytes) ScorePopup_CharDataLoBase = $26E8 ; Base for character data (lo byte) for score popups (12 bytes) ScorePopup_XCoordBase = $26D0 ; Base for X coordinate for score popups (12 bytes) FinalDLL_PointerStorage_Hi = $275E FinalDLL_PointerStorage_Lo = $275F CurrentPlayer = $27AE DisplayEasterEggFlag = $27CE ; ****************** CONSTANTS ;------------------------------------------------------------------------------ ; Difficulty Level Constants ; Used with the 'Difficulty' variable ($4C) and for text display. ;------------------------------------------------------------------------------ Difficulty_Beginner = $00 Difficulty_Intermediate = $01 Difficulty_Advanced = $02 Difficulty_Expert = $03 PLAYER1_OBJECT_INDEX = $01 PLAYER1_COLLISION_HEIGHT_SPECIAL = $0B ; Specific height check value for Player 1 ;------------------------------------------------------------------------------ ; GameObjectState Constants ; Defines the various states a game object can be in. ; ; Player and Enemy Bird States ($D0 - $D9): ; Shared states for player-controlled birds and enemy AI birds. ;------------------------------------------------------------------------------ State_Dead = $00 ; Object is inactive, dead, or not present. State_Born1 = $03 ; First phase of spawning/birth animation. State_Normal = $04 ; Normal gameplay state (player controllable, AI active). State_Hit = $05 ; Object has been hit (e.g., by a lance, preparing to die/drop egg). State_Invincible = $06 ; Object is temporarily invincible (e.g., during spawn). State_Born2 = $07 ; Second phase of spawning/birth animation. State_TrollHasBird = $08 ; Object (bird) is currently held by the troll. ; EnemyBird Specific State ($D2 - $D9): State_BirdSeekingRider = $14 ; Enemy bird is actively seeking a rider (that hatched from an egg). ;------------------------------------------------------------------------------ ; Pterodactyl (Pterry) States ($DA - $DC): ;------------------------------------------------------------------------------ ; State_Dead is $00, shared with above. PterryState_Normal = $0A ; Pterry is flying normally. PterryState_Charging = $0B ; Pterry is actively charging/attacking a player. PterryState_Leaving = $0C ; Pterry is leaving the screen (e.g., after being hit or timer expiry). PterryState_DefeatedVisual = $0D ; Pterry being visually defeated on screen ;------------------------------------------------------------------------------ ; Egg States ($DD - $E8): ;------------------------------------------------------------------------------ EggState_None = $00 ; Egg slot is empty, no egg present. EggState_Egg = $01 ; A laid egg, waiting to hatch. EggState_Hatching = $02 ; Egg is actively wiggling/hatching. EggState_RiderOnShell = $03 ; Rider has hatched and is standing on the broken egg shell. EggState_StandingRider = $04 ; Rider is standing alone, shell is gone (will attract a hunter bird). ; Note: This value is the same as State_Normal for birds. ;------------------------------------------------------------------------------ ; Egg Physics Parameter Constants ; These define the specific physics characteristics for an airborne egg. ;------------------------------------------------------------------------------ EGG_WEIGHT_FACTOR = $04 ; Gravity effect on egg (lower is lighter) EGG_MAX_RISE_SPEED_NEG = $FF ; Max upward Y-velocity (effectively -1, very slow rise) EGG_MAX_FALL_SPEED = $01 ; Max downward Y-velocity (slow fall) EGG_X_SPEED_LUT_MAX_CLAMP_INDEX = $02 ; Smallest numerical index for X-speed LUT (fastest left drift) ; Note: "Max" in Temp61MaxPhysicsXSpeedIndex refers to its role in clamping logic, ; not necessarily the numerically largest index value. EGG_X_SPEED_LUT_MIN_CLAMP_INDEX = $08 ; Largest numerical index for X-speed LUT (fastest right drift) ; Note: "Min" in MinPhysicsXSpeedLUTIndex refers to its role in clamping logic. ; For eggs, this value is numerically larger than EGG_X_SPEED_LUT_MAX_CLAMP_INDEX, ; defining the allowed index range [$02..$08] for X-movement. PTERRY_SPAWN_Y_COORD_MASK = %00000011 ; Mask for selecting Y coordinate from PterrySpawnYCoordLUT PTERRY_SPAWN_XDIRVEL_MASK = %00000001 ; Mask for selecting from X/Dir/XVel LUTs PTERRY_MIN_SPAWN_DIST_X = $30 ; Minimum X distance from player for Pterry spawn PTERRY_MIN_SPAWN_DIST_Y = $20 ; Minimum Y distance from player for Pterry spawn MinEnemyBirdObjectIndex = $02 ; Smallest index for an enemy bird object MaxEnemyBirdSlots = $0A ; Number of enemy bird slots to check (index 02 to 09) InitialTimerHiByteValue = $00 ; Initial value for the high byte of the timer. DifficultyLoopCounterBase = $03 ; Base value for calculating difficulty-dependent loop iterations. ; Max Difficulty is 3. Loop runs (Base - Difficulty + 1) times. TimerLevelCalcBaseValue = $27 ; Baseline value for calculating level-dependent part of timer. RandomTimerLoopAddend = $40 ; Value added to timer in each difficulty-scaled loop iteration. ; AI Action Categories (values from BirdAIActionCategoryByProximityLUT lookup) AIActionCat_CloseDefensive = $00 AIActionCat_OptimalAttack = $01 AIActionCat_ModerateEngage = $02 AIActionCat_FarApproach = $03 ; Constants for Score Popup Display List Object ScorePopup_DLModeByte EQU $60 ; Indirect Character Mode for DL ScorePopup_DLCharHiByte EQU $27 ; High byte of character data address for HSC font ;------------------------------------------------------------------------------ ; Sound Effect (SFX) Index Constants ; Used as arguments to ScheduleSFX and for identifying sounds. ; The actual sound data is pointed to by SFX_FreqAndControlDataPtrLoLUT/Hi tables. ;------------------------------------------------------------------------------ SFX_CoinDrop = $00 ; Sound for coin drop (attract mode?) SFX_FreeBird = $01 ; Sound when a player earns an extra life. SFX_PickupEgg = $02 ; Sound when a player picks up an egg. SFX_GameStart = $03 ; Sound played at the beginning of a new game. SFX_BirdPlatformBounce = $04 ; Sound when a bird bounces off a platform edge. SFX_BirdBirdBounce = $05 ; Sound when two birds collide and bounce off each other. SFX_PlayerFootstep = $06 ; Sound of a player's bird walking on a platform. SFX_PterryDefeated = $07 ; Sound when a Pterodactyl is defeated. SFX_PterryCharging = $08 ; Sound when a Pterodactyl starts its charging attack. SFX_PlayerBorn = $09 ; Sound when a player's bird spawns/re-spawns. SFX_Invulnerable = $0A ; Sound indicating player invulnerability (e.g., during spawn). SFX_EggWigglingHatching = $0B ; Sound of an egg wiggling before hatching. SFX_EnemyBirdBorn = $0C ; Sound when an enemy bird spawns. SFX_TrollJumping = $0D ; Sound of the troll jumping out of the lava. SFX_PlatformDissolve = $0E ; Sound when a platform starts to dissolve. SFX_Skid = $0F ; Sound of a bird skidding to a stop on a platform. SFX_BirdExplosion = $10 ; Sound when a bird (player or enemy) dies in an explosion. SFX_CheepCheep = $11 ; A "cheep cheep" sound, possibly unused or for a minor event. SFX_PlayerBirdFlap = $12 ; Sound of a player's bird flapping its wings. SFX_ChannelAvailable = $FF HunterBirdXVel_Right = $02 ; X-velocity for hunter bird moving right HunterBirdXVel_Left = $FD ; X-velocity for hunter bird moving left (-3) HunterBirdX_OffscreenLeft = $1A ; Spawn X-coordinate for hunter bird appearing from left HunterBirdX_OffscreenRight = $BE ; Spawn X-coordinate for hunter bird appearing from right HunterBirdYOffsetAboveRider = $0F ; Vertical offset (15 pixels) for hunter bird above rider X_VEL_TO_LUT_INDEX_OFFSET = $05 ; Offset to convert signed X-velocity to 0-based LUT index (e.g., index 5 = zero movement) Direction_Right = $01 Direction_Left = $FF TOP_SCREEN_Y_BOUNDARY = $10 ; Y-coordinate of the top screen edge for bounce SKID_VELOCITY_THRESHOLD_RIGHT = $03 ; Min X-velocity (e.g. +3) to initiate a skid when turning left SKID_VELOCITY_THRESHOLD_LEFT = $FE ; Max X-velocity (e.g. -2) to initiate a skid when turning right ; (Max left speed is -3, which is $FD) SKID_ANIMATION_FRAME = $04 ; Footstep animation index when skidding ; NMIModeFlag Values NMIMode_NormalGame = $00 ; Normal in-game NMI processing NMIMode_SplitScreen160A = $01 ; 160A portion of split screen NMI NMIMode_SplitScreen320A = $FF ; 320A portion of split screen NMI ; Console Switch Masks (from SWCHB - Active Low) SWCHB_Reset_Mask = %00000001 ; Bit 0 for Reset SWCHB_Select_Mask = %00000010 ; Bit 1 for Select SWCHB_Pause_Mask = %00001000 ; Bit 3 for Pause ; Control Register Values CTRL_DMA_ON_160AB = $40 ; single-width chars, 160A/B, border-off CTRL_DMA_OFF = $60 CTRL_DMA_ON_320AC = $4B ; single-width chars, 320A/C, border-on ; Input Register Bitmasks Input_FireButtonMask EQU %10000000 ; Bit 7 for fire button ; ****************** MACROS ; ASCII to HSC text encoding... mac WATKINS dc.b {1}-"A" endm ; ****************** ROM ORG $8000 ;------------------------------------------------------------------------------ ; SetBirdRandomTurnTimers ; Sets the 16-bit turn timer for an AI bird (index in X) to a new random value ; based on its TurnTimerIndex. Also toggles the bird's direction. ;------------------------------------------------------------------------------ SetBirdRandomTurnTimers ADC #$01 STA GameObjectDirection,X LDY GameObjectTurnTimerIndex,X JSR ReturnRandInA AND #$0F CLC ADC TurnCheckTimerValuesLoLUT,Y STA GameObjectTurnCheckTimerLo,X LDA TurnCheckTimerValuesHiLUT,Y STA GameObjectTurnCheckTimerHi,X RTS ;------------------------------------------------------------------------------ ; RunEggObjectProcessing ; Main routine to update the state and behavior of an egg object (index in X). ; This is a state machine that handles an egg's lifecycle: ; - State 1 (Egg): A stationary egg on a platform, counting down to hatch. ; - State 2 (Hatching): The egg is wiggling, counting down to reveal the rider. ; - State 3 (RiderOnShell): A rider stands on the broken shell for a short time. ; - State 4 (StandingRider): The rider stands alone, waiting for a hunter bird. ; It also handles the physics for an egg when it is airborne. ;------------------------------------------------------------------------------ RunEggObjectProcessing LDA GameObjectState,X ; Get the current state of the egg BEQ ExitEggProcessing_A ; If state is 0 (EggState_None), skip processing LDA GameObjectInAir,X ; Is the egg currently airborne? BEQ ProcessEggOnPlatform ; If not (on a platform), handle platform logic. JSR EggIsAirborne ; If airborne, set up egg-specific physics parameters... JMP UpdateEggPhysicsAndPlatformInteraction ; ...and jump to the physics/platform interaction handler. ProcessEggOnPlatform LDA LevelBCD ; Get current level in BCD format CMP #$03 ; Is it Level 3 or higher? (BCD comparison) BNE ProcessEgg_StandardBehavior ; If not, eggs behave normally. JSR CheckIfEggSlippingOffPlatform ; On Level 3+, platforms are slippery. Check if egg is near an edge. LDA Temp60 ; Check result from the slip check. BNE ProcessEgg_StandardBehavior ; If not slipping, proceed with standard behavior. ; Egg is on Level 3+ AND is slipping off the platform's edge. LDA #$01 ; Set InAir flag to true. STA GameObjectInAir,X ; Make the egg airborne, causing it to fall. ; Falls through to ExitEggProcessing_A (RTS). ExitEggProcessing_A RTS ProcessEgg_StandardBehavior ; This is the main state machine for an egg that is resting on a platform. LDA GameObjectState,X ; Get current state of the egg. CMP #EggState_StandingRider ; State 4: Rider is standing alone. No further action needed here. BEQ ExitEggProcessing_A ; Its fate is now tied to a hunter bird. CMP #EggState_Hatching ; State 2: Egg is actively hatching. BEQ ProcessHatchingEggTimer ; Process its hatching animation timer. CMP #EggState_RiderOnShell ; State 3: Rider is on the shell. BEQ ProcessRiderOnShellTimer ; Process its timer for shedding the shell. ; --- State 1: Egg is waiting to hatch --- DEC GameObjectCountdownLo,X ; Decrement low byte of the 16-bit hatch timer. BEQ DecrementHatchTimerHi ; If low byte wrapped, handle the high byte. RTS ; Timer still active, nothing more to do. DecrementHatchTimerHi DEC GameObjectCountdownHi,X ; Decrement high byte of hatch timer. BEQ AttemptToHatchEgg ; If timer expired, try to hatch. BMI AttemptToHatchEgg ; Also handle underflow just in case. ExitEggProcessing_B RTS AttemptToHatchEgg LDA Difficulty ; Get current game difficulty. BEQ ExitEggProcessing_B ; On Beginner difficulty, eggs never hatch. LDA EnemyBirdCount ; Get current number of active enemy birds. CMP MaxEnemyBirdCount ; Compare with the maximum allowed on screen for this level. BCC ProceedWithHatching ; If we are below the max, the egg can hatch. ; Max enemy birds reached, cannot hatch now. Reset a short timer to try again soon. LDA #$0A ; Reset countdown low byte. STA GameObjectCountdownLo,X LDA #$00 ; Reset countdown high byte. STA GameObjectCountdownHi,X RTS ProceedWithHatching INC EnemyBirdCount ; One more enemy bird will be active (the rider). LDA #EggState_Hatching ; Set egg state to 'hatching' (state 2). STA GameObjectState,X LDA #$05 ; Set initial low byte for hatching animation timer. STA GameObjectCountdownLo,X LDA #$0A ; Set initial high byte for hatching animation timer. STA GameObjectCountdownHi,X LDA #SFX_EggWigglingHatching ; Schedule the egg wiggling/hatching sound effect. JSR ScheduleSFX RTS ProcessHatchingEggTimer ; --- State 2: Egg is actively hatching --- DEC GameObjectCountdownLo,X ; Decrement low byte of hatching animation timer. BEQ ContinueHatchingEggTimer ; If low byte wrapped, process high byte and animation. RTS ContinueHatchingEggTimer LDA GameObjectCountdownHi,X AND #$07 ; Check lower 3 bits of high byte timer. BEQ UpdateEggWiggleAnimation ; If zero, it's time to update the wiggle animation frame. ; Otherwise, play the sound effect (every time Lo wraps, unless Hi&7 is 0). LDA #SFX_EggWigglingHatching ; Schedule egg wiggling/hatching sound effect. JSR ScheduleSFX UpdateEggWiggleAnimation DEC GameObjectCountdownHi,X ; Decrement high byte of hatching animation timer. BEQ TransitionToRiderOnShell ; If timer fully expired, transition to the next state. LDA ObjectWiggleAnimation,X ; Get current wiggle frame. EOR #$01 ; Toggle wiggle frame (0 <-> 1). STA ObjectWiggleAnimation,X ; Store new wiggle frame. LDA #$0A ; Reset low byte of hatching animation timer for the next wiggle cycle. STA GameObjectCountdownLo,X RTS TransitionToRiderOnShell LDA #EggState_RiderOnShell ; Egg is now 'rider standing on shell' (state 3). STA GameObjectState,X LDA #$0F ; Set timer for how long rider stays on the shell. STA GameObjectCountdownLo,X ; (High byte is implicitly 0 from the previous countdown). RTS ProcessRiderOnShellTimer ; --- State 3: Rider standing on broken shell --- DEC GameObjectCountdownLo,X ; Decrement timer for rider on shell. BEQ EggIsRiderNoShell ; If timer expires, transition to rider without shell. RTS ;------------------------------------------------------------------------------ ; EggIsRiderNoShell ; Called when an egg (object X) has progressed to the state of being just a ; rider (state 4), having shed its shell. This routine finds an available enemy ; bird slot and spawns a new "hunter" bird (object Y) to fly in and retrieve ; this rider. X contains the index of the egg object (now the rider). ;------------------------------------------------------------------------------ EggIsRiderNoShell LDA #EggState_StandingRider ; Set state to: rider standing without shell. STA GameObjectState,X ; Update the former egg object's state. ; Find an available (dead) enemy bird slot to spawn the hunter bird. LDY #MinEnemyBirdObjectIndex ; Start from the first enemy bird slot (index 2). FindDeadEnemyBirdSlotLoop LDA.w GameObjectState,Y ; Get state of potential enemy bird Y. BEQ FoundDeadEnemyBirdSlot ; If state is 0 (dead), the slot is available. INY ; Try next bird slot. CPY #MaxEnemyBirdSlots ; Have we checked all enemy bird slots (up to 9)? BNE FindDeadEnemyBirdSlotLoop ; If not, loop. FoundDeadEnemyBirdSlot ; Initialize the new hunter bird (object Y) based on the rider (object X). LDA ObjectBirdLevelAndType,X ; Get rider's original bird type/level (e.g., Bounder, Hunter, Shadow Lord). STA ObjectBirdLevelAndType,Y ; Set the new hunter bird's type/level to match. TYA ; Bird Y (the hunter) is now hunting Rider X (the prey). STA GameObjectHunterIndex,X ; Link: Rider X is being hunted by Bird Y. TXA ; STA GameObjectPreyIndex,Y ; Link: Bird Y is hunting Rider X. STY TempSavedYForHunterBirdSpawn ; Save Y (hunter bird index) as it will be clobbered by the JSR. JSR DetermineInitialHunterBirdDirection ; Determine which side of the screen the bird should spawn from. LDY TempSavedYForHunterBirdSpawn ; Restore Y. STA GameObjectDirection,Y ; Set hunter bird's initial direction. LDA GameObjectDirection,Y ; Load direction again to check sign. BMI SpawnHunterBirdFacingLeft SpawnHunterBirdFacingRight LDA #HunterBirdXVel_Right ; Set X velocity for right-facing bird. STA GameObjectXVelocity,Y LDA #HunterBirdX_OffscreenLeft ; Spawn off-screen to the left. JMP SetHunterBirdInitialXPosition SpawnHunterBirdFacingLeft LDA #HunterBirdXVel_Left ; Set X velocity for left-facing bird. STA GameObjectXVelocity,Y LDA #HunterBirdX_OffscreenRight ; Spawn off-screen to the right. SetHunterBirdInitialXPosition STA GameObjectXCoordHi,Y ; Set hunter bird's initial X coordinate (high byte). ; Set hunter bird's initial Y coordinate to be slightly above the rider. LDA GameObjectYCoordHi,X ; Get rider's Y coordinate. SEC SBC #HunterBirdYOffsetAboveRider ; Spawn 15 pixels above the rider. STA GameObjectYCoordHi,Y ; Set hunter bird's Y coordinate. ; Initialize various properties for the newly spawned hunter bird. LDA #$01 ; True for boolean flags. STA GameObjectInAir,Y ; Hunter bird starts in the air. STA.w GameObjectAIMode,Y ; Set hunter bird's AI mode to seeking. LDA #$00 ; Zero for timers and some physics components. STA GameObjectChargingTimer,Y ; Clear charging timer. STA GameObjectFootstepAnimTimer,Y ; Clear footstep animation timer. STA GameObjectFootstepAnimIndex,Y ; Reset footstep animation frame. STA GameObjectYVelocityLo,Y ; Clear Y velocity (low byte). STA GameObjectYVelocityHi,Y ; Clear Y velocity (high byte). STA GameObjectPlatformSkipState,Y ; Not skipping on a platform. STA GameObjectSkidDirection,Y ; Not skidding. STA GameObjectAnimationFrame,Y ; Reset animation frame. STA.w GameObjectAlive,Y ; Mark as alive (though its state defines behavior). STA GameObjectAITargetDelayTimer,X ; Reset AI target delay for the rider it was targeting. LDA #$01 ; Default timer reset value. STA GameObjectTimerResetValue,Y ; Set timer reset value for hunter bird. STA GameObjectEventTimer1,Y ; Set event timer 1 for hunter bird. LDA #State_BirdSeekingRider ; Set state to: bird is actively seeking its rider. STA GameObjectState,Y ; Update hunter bird's state. RTS ;------------------------------------------------------------------------------ ; DetermineInitialHunterBirdDirection ; Determines the initial direction for a newly spawned hunter bird. The hunter ; pursues the rider (object index in X). The routine checks which platform the ; rider is on to decide if the hunter should enter from the left or right. ; Returns: ; A = Direction_Right ($01) if rider is on a known platform. ; A = Direction_Left ($FF) if rider is not found on a known platform. ; Preserves: X / Modifies: Y, A ;------------------------------------------------------------------------------ DetermineInitialHunterBirdDirection LDY #$06 ; Start with the last platform index (Platform 6). LDA GameObjectYCoordHi,X ; Get rider's Y coordinate (high byte). FindRiderPlatformLoop CMP PlatformTopCoordinate,Y ; Is rider at the Y level of this platform's top? BNE RiderNotOnThisPlatform ; If not, check the next platform. ; Rider is at the correct Y level, now check X bounds. LDA GameObjectXCoordHi,X ; Get rider's X coordinate (high byte). CMP PlatformLeftsideCoordinate,Y ; Is rider to the right of the platform's left edge? BCC RiderNotOnThisPlatform ; If rider is left of the left edge, not on this platform. CMP PlatformRightsideCoordinate,Y ; Is rider to the left of the platform's right edge? BCS RiderNotOnThisPlatform ; If rider is right of the right edge, not on this platform. ; Rider is on this platform. LDA #Direction_Right ; Return direction: RIGHT. RTS RiderNotOnThisPlatform DEY ; Next platform index. BPL FindRiderPlatformLoop ; If platform index is still valid, loop. ; Rider was not found on any of the checked platforms. LDA #Direction_Left ; Return direction: LEFT. RTS ;------------------------------------------------------------------------------ ; EggIsAirborne ; Sets up the physics parameters in Zero Page specifically for an airborne egg ; object. Eggs have unique, floaty physics compared to birds. After setting ; the parameters, it jumps to the common airborne physics update routine. ; X = index of the egg GameObject ;------------------------------------------------------------------------------ EggIsAirborne ; Set egg's gravity (WeightFactor). A lower value means less gravity. LDA #EGG_WEIGHT_FACTOR STA Temp64WeightFactor ; Set egg's maximum upward speed (a small negative value for a slow rise). LDA #EGG_MAX_RISE_SPEED_NEG STA Temp63MaxRiseSpeedNeg ; Set egg's maximum downward speed (a small positive value for a slow fall). LDA #EGG_MAX_FALL_SPEED STA Temp62MaxFallSpeed ; Set egg's X-axis speed Look-Up Table index range. This controls its ; horizontal drift. For eggs, this range is narrow, resulting in slow drift. LDA #EGG_X_SPEED_LUT_MAX_CLAMP_INDEX STA Temp61MaxPhysicsXSpeedIndex ; Smallest X-speed LUT index egg can use. LDA #EGG_X_SPEED_LUT_MIN_CLAMP_INDEX STA Temp60MinPhysicsXSpeedIndex ; Largest X-speed LUT index egg can use. JMP UpdateAirborneXPositionAndVelocity ; Proceed to common X-axis physics update. ;------------------------------------------------------------------------------ ; UpdateAirborneObjectPhysics ; Main physics routine for airborne birds and pterodactyls. It loads the ; appropriate physics parameters for the object type and then jumps to the ; common X and Y position update logic. ; Input: X = GameObject index ;------------------------------------------------------------------------------ UpdateAirborneObjectPhysics LDA GameObjectState,X CMP #$08 ; check if state=troll holding the bird BNE ObjectIsAirborne JMP TrollHoldingTheBird ObjectIsAirborne LDY ObjectBirdLevelAndType,X ; Get bird type for index with physics LUTs LDA.w BirdPhysicsIndexMinByType,Y STA Temp60 LDA.w BirdPhysicsIndexMaxByType,Y STA Temp61 LDA BirdWeightByTypeLUT,Y STA Temp64 LDA BirdMaxDownVelocityByTypeLUT,Y STA Temp62 LDA BirdMaxUpVelocityByTypeLUT,Y STA Temp63 ;------------------------------------------------------------------------------ ; UpdateAirborneXPositionAndVelocity ; This is the core 16-bit physics update routine for all airborne objects. ; It's jumped to after physics parameters have been loaded into ZP temps. ; It handles: ; 1. X-velocity to LUT index conversion and clamping. ; 2. 16-bit X-position update from LUT. ; 3. Horizontal screen wrapping. ; 4. 16-bit Y-velocity update (applying gravity). ; 5. 16-bit Y-position update from velocity. ; Input: X = GameObject index. ZP temps $60-$64 must be pre-loaded. ;------------------------------------------------------------------------------ UpdateAirborneXPositionAndVelocity LDA GameObjectXVelocity,X ; Load current X velocity component CLC ADC #X_VEL_TO_LUT_INDEX_OFFSET ; Convert signed X velocity to an unsigned LUT index base. ; E.g., if XVel is -5 to +5, and OFFSET is 5, result is 0 to 10. ; This resulting index (in Y) is then adjusted by specific min/max allowed indices. TAY ; Y = initial candidate X speed LUT index BMI XSpeedIndexIsNegative_SetToMaxAllowed ; If Y < 0 (unlikely for typical Xvel range), use MaxAllowedIndex. ; else (Y >= 0) XSpeedIndex_CheckAgainstMaxAllowed CPY Temp61MaxPhysicsXSpeedIndex ; Compare Y with Temp61MaxPhysicsXSpeedIndex BCS XSpeedIndex_AtOrExceedsMax_CheckMinAllowed ; If Y >= Temp61MaxPhysicsXSpeedIndex, Y is used as is for min check. ; else (Y < Temp61MaxPhysicsXSpeedIndex) XSpeedIndexIsNegative_SetToMaxAllowed ; also reached if Y < MaxAllowedIndex LDY Temp61MaxPhysicsXSpeedIndex ; Y = Temp61MaxPhysicsXSpeedIndex. If Y was < Max, it's forced to Max. XSpeedIndex_AtOrExceedsMax_CheckMinAllowed CPY Temp60MinPhysicsXSpeedIndex ; Compare Y (now possibly MaxAllowedIndex) with Temp60MinPhysicsXSpeedIndex BEQ XSpeedIndex_IsFinalized ; If Y == MinAllowedIndex, the index is finalized. BCC XSpeedIndex_IsFinalized ; If Y < MinAllowedIndex, the index is also finalized. ; (This implies that values < MinAllowedIndex are treated as MinAllowedIndex by table structure or subsequent logic) ; else (Y > MinAllowedIndex) LDY Temp60MinPhysicsXSpeedIndex ; Y = Temp60MinPhysicsXSpeedIndex. If Y was > Min, it's forced to Min. XSpeedIndex_IsFinalized TYA ; A = final Y (the determined LUT index) SEC SBC #X_VEL_TO_LUT_INDEX_OFFSET ; Convert the LUT index back to a signed X velocity value STA GameObjectXVelocity,X ; Store the (potentially modified by LUT index logic) X velocity UpdateXPositionFromLUT CLC LDA GameObjectXCoordLo,X ; Load current X sub-pixel coordinate ADC XPositionIncrementTableLoLUT,Y ; Add X sub-pixel increment from LUT using final index Y STA GameObjectXCoordLo,X LDA GameObjectXCoordHi,X ; Load current X pixel coordinate ADC XPositionIncrementTableHiLUT,Y ; Add X pixel increment from LUT (with carry from Lo) STA GameObjectXCoordHi,X HandleXScreenWrap CMP ObjectScreenWrapXRightEdgeLUT,X ; Compare X with right edge for wrapping BCC CheckLeftEdgeWrap ; If X < RightEdge, no right-to-left wrap. BEQ CheckLeftEdgeWrap ; If X == RightEdge, also no right-to-left wrap. ; else (X > RightEdge) -> wrap from right to left LDA ObjectScreenWrapXLeftEdgeLUT,X ; Load left edge X coordinate JMP StoreWrappedXAndCheckObjectRemoval CheckLeftEdgeWrap CMP ObjectScreenWrapXLeftEdgeLUT,X ; Compare X with left edge for wrapping BCS XWrapHandled_ProceedToYPhysics ; If X >= LeftEdge, no left-to-right wrap. ; else (X < LeftEdge) -> wrap from left to right LDA ObjectScreenWrapXRightEdgeLUT,X ; Load right edge X coordinate StoreWrappedXAndCheckObjectRemoval STA GameObjectXCoordHi,X ; Store wrapped X pixel coordinate CPX #$0D ; Check if object index is Pterry or Egg (Indices $0A-$0C for Pterry, $0D-$18 for Egg) ; Player/Enemy birds are $00-$09. BCS XWrapHandled_ProceedToYPhysics ; If Pterry or Egg, skip removal check. ; Object is a Player or Enemy Bird that wrapped LDA GameObjectState,X CMP #State_Hit ; is state=bird hit? ($05) BEQ KillBird ; If hit bird wrapped, remove it. CMP #PterryState_Leaving ; is state=pterry leaving? ($0C) - This check is for birds, but PterryState is used. ; This implies a bird object could be in a "leaving" state, perhaps an unridden enemy bird. BEQ RemovePterry ; If "leaving" bird wrapped, remove it. XWrapHandled_ProceedToYPhysics LDA ObjectBirdLevelAndType,X ; Get object's type (0-2 Enemy, 3 Player, 4 Pterry) CMP #$04 ; Is it Pterry? (Type 4) BEQ ApplyGravityAndYVelocity ; If Pterry, always apply Y-velocity updates. ; Not Pterry (Player or Enemy Bird) LDA GameObjectInAir,X ; Check if the bird is airborne (not on a platform) BEQ UpdateYPositionFromVelocityOnly ; If on a platform (InAir == 0), skip Y-velocity changes due to gravity. ; Only update Y position based on its current (likely zeroed on landing) Y velocity. ApplyGravityAndYVelocity ; Apply Y-velocity changes (gravity and clamping) LDA GameObjectYVelocityLo,X CLC ADC Temp64WeightFactor STA GameObjectYVelocityLo,X LDA #$00 ; Prepare to add carry to Hi byte ADC GameObjectYVelocityHi,X ; A = Y_Vel_Hi + Carry BMI YVelocityIsUpward_CheckMaxRise ; If Y-velocity is negative (moving up). ; Y-velocity is positive (moving downward) or zero CMP Temp62MaxFallSpeed BEQ StoreYVelocityHi ; If Y_Vel_Hi == Temp62MaxFallSpeed, store it. BCC StoreYVelocityHi ; If Y_Vel_Hi < Temp62MaxFallSpeed, store it (falling slower than max is fine). ; Else (Y_Vel_Hi > Temp62MaxFallSpeed - falling too fast) LDA #$00 ; Reset Lo byte of Y-velocity as Hi is being clamped STA GameObjectYVelocityLo,X LDA Temp62MaxFallSpeed ; Load Temp62MaxFallSpeed to clamp JMP StoreYVelocityHi YVelocityIsUpward_CheckMaxRise CMP Temp63MaxRiseSpeedNeg ; e.g. Y_Vel_Hi=$FE(-2), Temp63MaxRiseSpeedNeg=$FC(-4). $FE >= $FC (less negative), so BCS is taken. BCS StoreYVelocityHi ; If Y_Vel_Hi >= Temp63MaxRiseSpeedNeg (rising slower or at max rise), store it. ; Else (Y_Vel_Hi < Temp63MaxRiseSpeedNeg - rising too fast, i.e., more negative) LDA #$00 ; Reset Lo byte of Y-velocity STA GameObjectYVelocityLo,X LDA Temp63MaxRiseSpeedNeg ; Load Temp63MaxRiseSpeedNeg to clamp StoreYVelocityHi STA GameObjectYVelocityHi,X ; Store the (clamped) Hi byte of Y-velocity UpdateYPositionFromVelocityOnly ; Update Y-coordinates from Y-velocity LDA GameObjectYVelocityLo,X CLC ADC GameObjectYCoordLo,X ; Add Y_Vel_Lo to Y_Coord_Lo STA GameObjectYCoordLo,X LDA GameObjectYCoordHi,X ADC GameObjectYVelocityHi,X ; Add Y_Vel_Hi to Y_Coord_Hi (with carry) STA GameObjectYCoordHi,X JMP HandleObjectTopScreenCollision ; Jump to process Y boundary conditions (top of screen bounce, troll grab) RemovePterry LDA #$00 ; Pterry is dead and gone STA GameObjectState,X LDA PterryAliveCount BEQ SkipPterryDecrement DEC PterryAliveCount SkipPterryDecrement JSR UpdatePterryRespawnTimer LSR PterryCountdownHi ; divide pterry ROR PterryCountdownLo ; counter by two RTS KillBird LDA #$00 STA GameObjectState,X STA GameObjectAlive,X CPX #$02 ; players are X=0,1 BCC KillPlayerBird DEC EnemyBirdCount BNE MoreEnemyBirdsLeft LDA EggsPresentCount BNE MoreEnemyBirdsLeft JMP SetupNextLevel MoreEnemyBirdsLeft RTS KillPlayerBird LDA P0Lives,X BPL SetupNewPlayerBird LDA #$00 STA GameObjectState,X RTS SetupNewPlayerBird JMP SpawnNewBird ;------------------------------------------------------------------------------ ; HandleObjectTopScreenCollision ; Checks if an object has moved above the top screen boundary. If so, it reverses ; and dampens its Y velocity for a bounce effect and clamps its Y position. ; Input: X = GameObject index ;------------------------------------------------------------------------------ HandleObjectTopScreenCollision LDA GameObjectYCoordHi,X ; Get object's current Y position (high byte) CMP #TOP_SCREEN_Y_BOUNDARY ; Compare with the top screen boundary BCS ProcessTrollGrab_Or_FurtherYChecks ; If Y >= TOP_BOUNDARY (i.e., below or at safe margin), ; object is not at/above top, skip bounce logic. ; Branch to ProcessTrollGrab_Or_FurtherYChecks ; Object is at or above the top screen boundary (Y < TOP_SCREEN_Y_BOUNDARY) LDA GameObjectYVelocityHi,X ; Get Y velocity (high byte) BPL ClampYAtTopBoundaryAndExit ; If velocity is positive or zero (moving down/still), ; no upward bounce needed, just clamp position. ; Object is moving upwards into the top boundary (Y velocity is negative) ; Reverse and dampen Y velocity for bounce effect. EOR #$FF ; Negate Y-velocity (High Byte), part 1 CLC ADC #$01 ; Negate Y-velocity (High Byte), part 2 (Two's complement) STA GameObjectYVelocityHi,X LDA GameObjectYVelocityLo,X ; Get Y velocity (low byte) EOR #$FF ; Negate Y-velocity (Low Byte), part 1 CLC ADC #$01 ; Negate Y-velocity (Low Byte), part 2 STA GameObjectYVelocityLo,X ; Dampen the bounce velocity: Divide Y-velocity by 4 CLC ROR GameObjectYVelocityHi,X ; Shift combined 16-bit velocity right (effectively VelY / 2) ROR GameObjectYVelocityLo,X CLC ROR GameObjectYVelocityHi,X ; Shift again (effectively VelY / 4 total) ROR GameObjectYVelocityLo,X ClampYAtTopBoundaryAndExit LDA #TOP_SCREEN_Y_BOUNDARY ; Load the top boundary Y coordinate STA GameObjectYCoordHi,X ; Clamp object's Y position to the top boundary RTS ; Return from NMI or subroutine ProcessTrollGrab_Or_FurtherYChecks LDA GameObjectState,X CMP #$08 BEQ TrollHoldingTheBird LDA GameObjectYCoordHi,X CMP TrollGrabHeight,X BCS TrollJustGrabbedTheBird RTS TrollJustGrabbedTheBird CPX #$0D ; Eggs can't be grabbed (but Pterry can?!?) BCS TrollKilledEnemyBird LDA #$08 STA GameObjectState,X RTS TrollHoldingTheBird LDA GameObjectYCoordHi,X CMP #$BB ; See if the bird pulled down far enough to die BCS TrollKilledThBird INC GameObjectYCoordHi,X ; Pull the bird down some more RTS TrollKilledThBird CPX #$02 BCS GotoKillBird ; branch if non-player enemy bird LDA #$00 STA GameObjectState,X JMP StartPlayerDeath GotoKillBird JMP KillBird TrollKilledEnemyBird ; a shortened version of the KillBird routine LDA #$00 STA GameObjectState,X DEC EggsPresentCount BNE ExitTrollKillRoutine LDA EnemyBirdCount BNE ExitTrollKillRoutine JMP SetupNextLevel ExitTrollKillRoutine RTS ;------------------------------------------------------------------------------ ; ProcessBirdToBirdCollisionLoop ; Checks for collisions between the bird object in X and all other birds with a ; lower index. Handles simple horizontal bounces for non-player birds. ; Input: X = Index of the primary bird for collision check ;------------------------------------------------------------------------------ ProcessBirdToBirdCollisionLoop TXA ; A = ObjX_idx TAY ; Y_reg = ObjX_idx (used as the initial counter for ObjY loop) PHA ; Push ObjX_idx onto stack (will be retrieved by PLA in Bird2BirdIterateAndCheckObjY) JMP Bird2BirdIterateAndCheckObjY ; Jump to the main loop logic for iterating through ObjY ; Start of the logic for a specific ObjX vs ObjY pair Bird2BirdFilterObjYAndDetectCollision LDA.w GameObjectState,Y ; Get state of ObjY (current object in inner loop, index in Y_REG) BNE Bird2BirdCheckIfObjYBorn1 ; If not State_Dead ($00), check further JMP Bird2BirdIterateAndCheckObjY ; ObjY is dead, skip to next ObjY Bird2BirdCheckIfObjYBorn1 CMP #State_Born1 ; Is ObjY in State_Born1 ($03)? BNE Bird2BirdCheckIfObjYInvincible ; If not, check next state JMP Bird2BirdIterateAndCheckObjY ; ObjY is in Born1 state, skip to next ObjY Bird2BirdCheckIfObjYInvincible CMP #State_Invincible ; Is ObjY in State_Invincible ($06)? BNE Bird2BirdCheckIfObjYBorn2 ; If not, check next state JMP Bird2BirdIterateAndCheckObjY ; ObjY is invincible, skip to next ObjY Bird2BirdCheckIfObjYBorn2 CMP #State_Born2 ; Is ObjY in State_Born2 ($07)? BNE Bird2BirdCheckIfObjYAlive ; If not, check if alive JMP Bird2BirdIterateAndCheckObjY ; ObjY is in Born2 state, skip to next ObjY Bird2BirdCheckIfObjYAlive LDA.w GameObjectAlive,Y ; Is ObjY alive? BNE Bird2BirdPerformCollisionDetection ; If alive flag is non-zero, proceed to collision detection JMP Bird2BirdIterateAndCheckObjY ; ObjY is not alive (e.g. riderless bird leaving), skip to next ObjY Bird2BirdPerformCollisionDetection JSR GameObjCollisionDetection ; Check collision between ObjX (in X_REG) and ObjY (in Y_REG) ; Carry will be CLEAR if collision, SET if no collision. BCS Bird2BirdIterateAndCheckObjY ; If Carry SET (no collision), skip to next ObjY ; Collision detected between ObjX and ObjY (Carry is CLEAR) CPX #MinEnemyBirdObjectIndex ; Is ObjX a player (index < 2)? BCS GameObject1NotAPlayer ; If ObjX_idx >= 2 (enemy bird), check ObjY JMP CheckPlayerAndBirdY ; ObjX is a player, jump to player-involved collision logic GameObject1NotAPlayer CPY #MinEnemyBirdObjectIndex ; Is ObjY a player (index < 2)? BCS GameObject2NotAPlayer ; If ObjY_idx >= 2 (enemy bird), both are non-players JMP CheckPlayerAndBirdY ; ObjY is a player, ObjX is enemy, jump to player-involved logic GameObject2NotAPlayer ; Both ObjX and ObjY are non-player birds (indices >= 2) BirdsAtTheSameHeight LDA #SFX_BirdBirdBounce ; Sound effect for bird-to-bird bounce JSR ScheduleSFX BirdsHaveBounced ; Collision response for two non-player birds PLA ; A = Pop ObjY_idx from stack (pushed at Bird2BirdIterateAndCheckObjY) TAY ; Y_REG = ObjY_idx (the object ObjX collided with) ; X_REG still holds ObjX_idx LDA TempCollisionOverlap ; Load Y-axis overlap magnitude (from GameObjCollisionDetection) CMP #$07 ; Collision_MinYOverlapForHorizBounce (value from original code) BCS HandleVerticalBounceCollision ; If Y_overlap >= 7, jump to vertical bounce logic ; Y_overlap < 7: Handle as a primarily horizontal collision (glancing blow) ; Nudge objects apart based on their relative X positions. LDA GameObjectXCoordHi,X ; ObjX's X coordinate CMP GameObjectXCoordHi,Y ; Compare with ObjY's X coordinate BCC Bird2BirdBounceObjXLeft_ObjYRight ; If ObjX is to the left of ObjY ; ObjX is to the right of (or at same X as) ObjY. ; Nudge ObjY left, ObjX right. LDA #Direction_Left ; Set ObjY direction to Left STA GameObjectDirection,Y LDA GameObjectXCoordHi,Y SEC SBC #$01 ; ObjY_X-- STA GameObjectXCoordHi,Y LDA #Direction_Right ; Set ObjX direction to Right STA GameObjectDirection,X INC GameObjectXCoordHi,X ; ObjX_X++ JMP Bird2BirdApplyHorizontalBounceVelocities ; Proceed to adjust velocities Bird2BirdBounceObjXLeft_ObjYRight ; Nudge ObjY right, ObjX left. LDA #Direction_Right ; Set ObjY direction to Right STA GameObjectDirection,Y LDA GameObjectXCoordHi,Y CLC ADC #$01 ; ObjY_X++ STA GameObjectXCoordHi,Y LDA #Direction_Left ; Set ObjX direction to Left STA GameObjectDirection,X DEC GameObjectXCoordHi,X ; ObjX_X-- ; Fall through to Bird2BirdApplyHorizontalBounceVelocities Bird2BirdApplyHorizontalBounceVelocities ; Adjust X-velocities for both collided objects. ; The logic effectively reverses direction and slightly dampens. ; e.g., Vel +2 becomes -1; Vel -2 becomes +1. Stops if Vel was +/-1. Bird2BirdAdjustObjX_Vel LDA GameObjectXVelocity,X ; Get ObjX's current X-velocity BEQ Bird2BirdStoreAdjustedObjX_Vel ; If velocity is zero, no change needed EOR #$FF ; Invert all bits (NOT operation) BPL Bird2BirdStoreAdjustedObjX_Vel ; If result is positive (original was negative or zero), use this value ; (e.g., if original was -1 ($FF), result is $00) ; (e.g., if original was -2 ($FE), result is $01) CLC ADC #$02 ; If result was negative (original was positive), add 2 to complete pseudo-negation ; (e.g., if original was +1 ($01), NOT is $FE. $FE + 2 = $00) ; (e.g., if original was +2 ($02), NOT is $FD. $FD + 2 = $FF (-1)) Bird2BirdStoreAdjustedObjX_Vel STA GameObjectXVelocity,X ; Store new X-velocity for ObjX Bird2BirdAdjustObjY_Vel LDA GameObjectXVelocity,Y ; Get ObjY's current X-velocity BEQ Bird2BirdStoreAdjustedObjY_Vel ; If velocity is zero, no change EOR #$FF ; Invert all bits BPL Bird2BirdStoreAdjustedObjY_Vel ; If result positive, use it CLC ADC #$02 ; Else, add 2 Bird2BirdStoreAdjustedObjY_Vel STA GameObjectXVelocity,Y ; Store new X-velocity for ObjY LDA GameObjectInAir,Y ; Check if ObjY is in the air BEQ Bird2BirdFinishHorizontalBounceResponse ; If ObjY is on a platform, this horizontal bounce is sufficient. LDA TempCollisionOverlap ; ObjY is airborne, check Y-overlap again CMP #$03 BCS HandleVerticalBounceCollision ; If Y_overlap >= 3, might need vertical bounce (external logic) ; Fall through to Bird2BirdFinishHorizontalBounceResponse if Y_overlap < 3 and ObjY airborne Bird2BirdFinishHorizontalBounceResponse RTS ; Return from ProcessBirdToBirdCollisionLoop Bird2BirdIterateAndCheckObjY PLA DEY TYA BMI Bird2BirdFinishHorizontalBounceResponse PHA JMP Bird2BirdFilterObjYAndDetectCollision HandleVerticalBounceCollision LDA GameObjectYVelocityLo,X EOR #$FF ADC #$01 STA GameObjectYVelocityLo,X LDA GameObjectYVelocityLo,Y EOR #$FF ADC #$01 STA GameObjectYVelocityLo,Y LDA GameObjectYVelocityHi,X EOR #$FF ADC #$01 STA GameObjectYVelocityHi,X LDA GameObjectYVelocityHi,Y EOR #$FF ADC #$01 STA GameObjectYVelocityHi,Y LDA GameObjectYVelocityHi,X ROL ROR GameObjectYVelocityHi,X ROR GameObjectYVelocityLo,X LDA GameObjectYVelocityHi,Y ROL LDA GameObjectYVelocityHi,Y ROR STA GameObjectYVelocityHi,Y LDA GameObjectYVelocityLo,Y ROR STA GameObjectYVelocityLo,Y LDA GameObjectYCoordHi,X CMP GameObjectYCoordHi,Y BCC HandleBouncePhysicsForUpperObject LDA GameObjectYVelocityHi,Y BPL ClampWinnerVelocityOnBounce CMP #$FF BCS ClampWinnerVelocityOnBounce RTS ClampWinnerVelocityOnBounce LDA #$FF STA GameObjectYVelocityHi,Y RTS HandleBouncePhysicsForUpperObject LDA GameObjectYVelocityHi,X BPL ClampBouncedObjectVelocityHi CMP #$FF BCS ClampBouncedObjectVelocityHi RTS ClampBouncedObjectVelocityHi LDA #$FF STA GameObjectYVelocityHi,X RTS ;------------------------------------------------------------------------------ ; CheckPlayerAndBirdY ; Handles the complex logic for when a player collides with another bird ; (either another player or an enemy). Determines who wins the joust based on ; vertical position, awards points, and initiates death sequences. ;------------------------------------------------------------------------------ CheckPlayerAndBirdY ; A player and enemy bird -or- player and player have collided LDA GameObjectYCoordHi,X CMP GameObjectYCoordHi,Y BNE DetermineJoustWinner JMP BirdsAtTheSameHeight DetermineJoustWinner TXA PHA LDA #SFX_BirdExplosion JSR ScheduleSFX CPY #$02 BCS WhichBirdWasHigher ; branch if non-player enemy bird CPX #$02 BCS WhichBirdWasHigher ; branch if non-player enemy bird LDA #$00 STA PlayersWereATeam LDA #$02 STA Temp61ScoreAdd LDA #$00 STA Temp62ScoreAdd LDA PlayerWasGladiator BEQ CalculateStandardPlayerJoustScore LDA #$03 STA Temp61ScoreAdd LDA #$00 STA Temp62ScoreAdd CalculateStandardPlayerJoustScore LDA GameObjectYCoordHi,X CMP GameObjectYCoordHi,Y BCS PlayerXLosesJoustToPlayerY JSR UpdatePlayerScoreAndBonus LDA PlayerWasGladiator BEQ WhichBirdWasHigher LDA #$00 STA PlayerWasGladiator LDA GameObjectYCoordHi,Y CLC ADC #$04 STA Temp5E LDA GameObjectXCoordHi,Y CLC ADC #$0E STA Temp5F LDA #$05 STA Temp60ScoreAdd JSR CreateScorePopupAtObjectLocation JMP WhichBirdWasHigher PlayerXLosesJoustToPlayerY TXA PHA TYA TAX JSR UpdatePlayerScoreAndBonus LDA PlayerWasGladiator BEQ PlayerYWinsJoustVsPlayerX LDA #$00 STA PlayerWasGladiator LDA GameObjectYCoordHi,X CLC ADC #$04 STA Temp5E LDA GameObjectXCoordHi,X CLC ADC #$0E STA Temp5F LDA #$05 STA Temp60 JSR CreateScorePopupAtObjectLocation PlayerYWinsJoustVsPlayerX PLA TAX WhichBirdWasHigher LDA GameObjectYCoordHi,X CMP GameObjectYCoordHi,Y BCS JoustLoserIdentified TYA TAX JoustLoserIdentified CPX #$02 BCS PlayerKilledEnemyBird JSR StartPlayerDeath PLA TAX JMP BirdsHaveBounced PlayerKilledEnemyBird TYA PHA JSR ConvertKilledBirdToEgg LDA ObjectBirdLevelAndType,X BNE CheckIfKilledBirdIsHunter LDA #$00 STA Temp61ScoreAdd LDA #$50 JMP StoreCalculatedScoreValue CheckIfKilledBirdIsHunter CMP #$01 BNE CalculateShadowLordKillScore LDA #$01 STA Temp61ScoreAdd LDA #$00 JMP StoreCalculatedScoreValue SetDefaultKillScore LDA #$00 STA Temp61ScoreAdd LDA #$05 JMP StoreCalculatedScoreValue CalculateShadowLordKillScore CMP #$02 BNE SetDefaultKillScore LDA #$01 STA Temp61ScoreAdd LDA #$50 StoreCalculatedScoreValue STA Temp62ScoreAdd PLA TAX JSR UpdatePlayerScoreAndBonus PLA TAX JMP BirdsHaveBounced ;------------------------------------------------------------------------------ ; CheckPlayerEggCollision ; Iterates through all egg objects and checks for collision with a player bird. ; Handles egg pickup, scoring, and sound effects. ; Input: X = Player object index ;------------------------------------------------------------------------------ CheckPlayerEggCollision LDY #$0D CheckPlayerEggCollisionLoop LDA.w GameObjectState,Y BEQ SkipThisEggCheck JSR GameObjCollisionDetection ; carry is clear on collision BCC PlayerPickedUpAnEgg LDA GameObjectInAir,X BNE CheckAirbornePlayerEggCollision LDA GameObjectYCoordHi,Y STA Temp63 SEC SBC #$05 STA GameObjectYCoordHi,Y JSR GameObjCollisionDetection ; carry is clear on collision BCC PlayerPickedUpAnEgg LDA Temp63 STA GameObjectYCoordHi,Y JMP SkipThisEggCheck CheckAirbornePlayerEggCollision LDA.w GameObjectState,Y CMP #$04 BNE SkipThisEggCheck LDA GameObjectYCoordHi,Y STA Temp63 SEC SBC #$03 STA GameObjectYCoordHi,Y JSR GameObjCollisionDetection ; carry is clear on collision BCC PlayerPickedUpAnEgg LDA GameObjectXCoordHi,Y STA Temp64 CLC ADC #$04 STA GameObjectXCoordHi,Y JSR GameObjCollisionDetection ; carry is clear on collision BCC PlayerPickedUpAnEgg LDA Temp63 STA GameObjectYCoordHi,Y JSR GameObjCollisionDetection ; carry is clear on collision BCC PlayerPickedUpAnEgg LDA Temp64 STA GameObjectXCoordHi,Y SkipThisEggCheck INY CPY #$19 BEQ AllEggsChecked JMP CheckPlayerEggCollisionLoop AllEggsChecked RTS PlayerPickedUpAnEgg LDA #SFX_PickupEgg JSR ScheduleSFX LDA.w GameObjectState,Y CMP #$03 BEQ DecrementEnemyCountForHatchingEggPickup CMP #$02 BNE HandleEggPickupState DecrementEnemyCountForHatchingEggPickup DEC EnemyBirdCount HandleEggPickupState CMP #$04 BNE ClearPickedUpEggState STX Temp65 LDX GameObjectHunterIndex,Y LDA #$05 STA GameObjectState,X LDA #$01 STA GameObjectTimerResetValue,X LDX Temp65 ClearPickedUpEggState LDA #$00 STA.w GameObjectState,Y DEC EggsPresentCount BNE CalculateEggPickupScore LDA EnemyBirdCount BNE CalculateEggPickupScore JSR SetupNextLevel CalculateEggPickupScore LDA GameObjectDirection,Y BEQ CalculateScoreForEggPickup LDA GameObjectYCoordHi,Y SEC SBC #$08 STA Temp5E LDA GameObjectXCoordHi,Y STA Temp5F LDA #$04 STA Temp60ScoreAdd JSR CreateScorePopupAtObjectLocation LDA #$00 STA Temp61ScoreAdd LDA #$50 STA Temp62ScoreAdd JSR UpdatePlayerScoreAndBonus CalculateScoreForEggPickup LDA GameObjectYCoordHi,Y STA Temp5E LDA GameObjectXCoordHi,Y STA Temp5F LDA P0EggPointLevel,X STA Temp60ScoreAdd JSR CreateScorePopupAtObjectLocation LDA P0EggPointLevel,X TAY LDA NextEggPointLevelLUT,Y STA P0EggPointLevel,X LDA EggPointLevelScoreHiLUT,Y STA Temp61ScoreAdd LDA EggPointLevelScoreLoLUT,Y STA Temp62ScoreAdd JMP UpdatePlayerScoreAndBonus NextEggPointLevelLUT .byte $01,$02,$03,$03 ; Consecutive egg pickups score 250,500,750,1000,1000,1000... EggPointLevelScoreHiLUT .byte >$0025,>$0050,>$0075,>$0100 EggPointLevelScoreLoLUT .byte <$0025,<$0050,<$0075,<$0100 ;------------------------------------------------------------------------------ ; ProcessBirdPlatformInteraction ; Handles all physics and state changes for a bird object (index in X) ; related to its interaction with platforms. ; ; This routine has two main paths: ; 1. On-Platform Logic: If the bird is on a platform (InAir flag is false), ; it checks for proximity to edges, handles skidding, and can initiate a fall. ; 2. Airborne Logic: If the bird is airborne (InAir flag is true), it checks ; for collisions with platforms, which can result in landing, bouncing, or ; a "skip" across the surface. ;------------------------------------------------------------------------------ ProcessBirdPlatformInteraction LDA GameObjectInAir,X ; Is the bird currently airborne? BNE BirdIsAirborne_CheckForCollision ; If yes, branch to airborne logic path. ; --- On-Platform Logic --- JSR CheckIfBirdNearPlatformEdge ; Check for proximity to a platform edge. LDA Temp60 ; Load the result of the edge check. BNE OnPlatform_EdgeOrSideDetected ; If non-zero, an edge was detected. ; Bird is on a platform but not near an edge. LDA GameObjectSkidDirection,X ; Is the bird currently skidding? BEQ BirdNotSkidding1 ; If not, proceed to check if it should fall. JSR ClearSkidStateAndSound ; If it is skidding (but not near an edge), clear the skid state. BirdNotSkidding1 JMP CheckIfBirdIsUnsupportedAndShouldFall ; Check if bird is on a valid platform spot, otherwise fall. OnPlatform_EdgeOrSideDetected JSR SelectCollisionPointsAndCheckPlatform ; Perform a more detailed platform collision check. CMP #$08 ; Is the collision type a side impact? BEQ OnPlatform_BounceOffSide ; If yes, handle bouncing off the side. RTS ; Otherwise, no action needed this frame. OnPlatform_BounceOffSide INC GameObjectXCoordHi,X ; Nudge the bird slightly away from the platform. LDA #SFX_BirdPlatformBounce ; Schedule the bounce sound effect. JSR ScheduleSFX LDA GameObjectXVelocity,X ; Reverse X-velocity. EOR #$FF CLC ADC #$01 STA GameObjectXVelocity,X LDA GameObjectDirection,X ; Reverse facing direction. EOR #$FF CLC ADC #$01 STA GameObjectDirection,X LDA GameObjectSkidDirection,X ; Reverse skid direction if skidding. EOR #$FF CLC ADC #$01 STA GameObjectSkidDirection,X RTS ; --- Airborne Logic --- BirdIsAirborne_CheckForCollision JSR SelectCollisionPointsAndCheckPlatform ; Check for collision with any platform. BEQ Airborne_NoCollision_ClearSkipState ; If no collision, clear skip state and continue. BMI Airborne_HandleLanding ; If result is negative, it's a landing on top of a platform. CMP #$01 BEQ Airborne_CheckForPlatformSkip ; A result of 1 or 8 indicates a shallow landing or side hit. CMP #$08 BEQ Airborne_CheckForPlatformSkip JMP CheckIfBirdIsUnsupportedAndShouldFall ; For other collision types, check if it should fall. Airborne_HandleLanding LDA GameObjectPlatformSkipState,X ; Is the bird in a "skip" state from a previous frame? BNE CheckIfBirdIsUnsupportedAndShouldFall ; If yes, don't land yet, let it fall/continue skipping. LDA #$02 ; Set animation frame to standing/walking. STA GameObjectAnimationFrame,X LDA #$00 ; Bird is no longer in the air. STA GameObjectInAir,X STA GameObjectYVelocityHi,X ; Zero out Y-velocity. STA GameObjectYVelocityLo,X LDA GameObjectXVelocity,X ; Check X-velocity to set facing direction. BEQ Airborne_Landing_Finalize ; If stopped, branch to the JMP trampoline. BMI Airborne_Landing_FaceLeft LDA #Direction_Right ; Moving right, so face right. STA GameObjectDirection,X JMP Airborne_Landing_Finalize ; Jump to the JMP trampoline. Airborne_Landing_FaceLeft LDA #Direction_Left ; Moving left, so face left. STA GameObjectDirection,X ; Fall through to the JMP trampoline. Airborne_Landing_Finalize JMP UpdateCoordsFromTempAndExit_B ; This JMP acts as a trampoline for the short branches above. Airborne_CheckForPlatformSkip JSR CheckForShallowPlatformCollision ; Another check, possibly to confirm the nature of the shallow landing. BNE Airborne_ProcessBounce ; If it's a bounce, process it. LDA GameObjectYCoordHi,X ; Check bird's Y coordinate. CMP #$92 ; Is it above a certain height? BCS CheckIfBirdIsUnsupportedAndShouldFall ; If too low, treat as a fall. LDA #$01 ; Otherwise, initiate a "skip" across the platform surface. STA GameObjectPlatformSkipState,X BPL CheckIfBirdIsUnsupportedAndShouldFall ; Always branches. Airborne_NoCollision_ClearSkipState LDA #$00 ; No collision, so clear any platform skip state. STA GameObjectPlatformSkipState,X CheckIfBirdIsUnsupportedAndShouldFall LDA #$01 ; Set InAir flag to TRUE, making the bird subject to gravity. STA GameObjectInAir,X LDA GameObjectYCoordHi,X CMP #TOP_SCREEN_Y_BOUNDARY ; Has the bird hit the top of the screen? BCC Airborne_BounceOffTopScreen ; If Y < boundary, it has. JSR CheckForShallowPlatformCollision ; Check for platform support again. BNE Airborne_ProcessBounce ; If a bounce condition is met, process it. JMP Exit_ProcessBirdPlatformInteraction ; Otherwise, bird is airborne and falling, exit. Airborne_BounceOffTopScreen LDA GameObjectYVelocityHi,X ; Get Y-velocity. BMI Airborne_ReverseYVelocityForBounce ; If moving up (negative), reverse it for a bounce. RTS ; If moving down, just let it fall away from the top. Airborne_ReverseYVelocityForBounce EOR #$FF ; Reverse Y-velocity to bounce down. STA GameObjectYVelocityHi,X LDA GameObjectYVelocityLo,X EOR #$FF ADC #$01 STA GameObjectYVelocityLo,X RTS Airborne_ProcessBounce TAY ; A holds collision type, save in Y. BPL Airborne_Bounce_PositiveResult ; Handle different bounce types based on sign. ; Negative result: Bounce off the bottom of a platform. LDA #SFX_BirdPlatformBounce JSR ScheduleSFX LDA #$80 ; Set Y-velocity to a strong upward value. STA GameObjectYVelocityLo,X LDA #$FF STA GameObjectYVelocityHi,X JMP UpdateCoordsFromTempAndExit_B Airborne_Bounce_PositiveResult LDA #SFX_BirdPlatformBounce JSR ScheduleSFX TYA ; Restore collision type from Y. LSR BCS Airborne_Bounce_SideImpactRight ; Bit 0 set -> hit right side of platform LSR BCS Airborne_Bounce_GlancingBlow ; Bit 1 set -> glancing blow, small bounce LSR BCS Airborne_Bounce_GlancingBlow ; Bit 2 set -> also a glancing blow ; Fall-through for other bounce types LDA GameObjectXVelocity,X BPL UpdateCoordsFromTempAndExit_B ; If moving right, no X-velocity change. EOR #$FF ; If moving left, dampen X-velocity (divide by 2). CLC ADC #$01 ROR JMP Airborne_Bounce_StoreNewXVel Airborne_Bounce_SideImpactRight LDA GameObjectXVelocity,X BEQ UpdateCoordsFromTempAndExit_B ; If stopped, no change. BMI UpdateCoordsFromTempAndExit_B ; If moving left (away from impact), no change. EOR #$FF ; Moving right into platform, reverse and dampen velocity. CLC ADC #$01 SEC ROR Airborne_Bounce_StoreNewXVel STA GameObjectXVelocity,X LDA GameObjectState,X CMP #State_Hit ; Is the bird in the "hit" state? BNE UpdateCoordsFromTempAndExit_A ; If not, just update coords. LDY ObjectBirdLevelAndType,X ; If it is, reset its AI timer to make it LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y ; react more quickly after the bounce. STA GameObjectTimerResetValue,X STA GameObjectEventTimer1,X UpdateCoordsFromTempAndExit_A RTS Airborne_Bounce_GlancingBlow LDA #$50 ; Set Y-velocity to a moderate upward value. STA GameObjectYVelocityLo,X LDA #$00 STA GameObjectYVelocityHi,X UpdateCoordsFromTempAndExit_B LDA Temp65 ; Load new X coordinate calculated by collision routine. STA GameObjectXCoordHi,X LDA Temp66 ; Load new Y coordinate. STA GameObjectYCoordHi,X Exit_ProcessBirdPlatformInteraction RTS ;------------------------------------------------------------------------------ ; UpdateEggPhysicsAndPlatformInteraction ; Handles physics and platform interaction specifically for an egg object. ; Input: X = Egg object index ;------------------------------------------------------------------------------ UpdateEggPhysicsAndPlatformInteraction JSR SelectEggCollisionPointAndCheck BEQ EggNoPlatformCollision STA Temp5E LDA #$00 STA GameObjectDirection,X LDA Temp5E BMI HandlePlatformTopCollisionEgg LSR BCS EggBounceOffRightSideOfPlatform LSR BCS NegateEggYVelocityOnBounce LSR BCS NegateEggYVelocityOnBounce LSR BCS EggAirborne_BounceOffSideOfPlatform EggNoPlatformCollision RTS EggAirborne_BounceOffSideOfPlatform LDA GameObjectXVelocity,X BMI ReverseEggXVelocityOnBounce JMP UpdateEggCoordsAfterCollision ReverseEggXVelocityOnBounce EOR #$FF CLC ADC #$01 STA GameObjectXVelocity,X JMP UpdateEggCoordsAfterCollision EggBounceOffRightSideOfPlatform LDA GameObjectXVelocity,X BPL ReverseEggXVelocityOnBounce JMP UpdateEggCoordsAfterCollision NegateEggYVelocityOnBounce LDA GameObjectYVelocityHi,X BPL EggBounceYVelocityAlreadyDownward SEC LDA #$00 SBC GameObjectYVelocityLo,X STA GameObjectYVelocityLo,X LDA #$00 SBC GameObjectYVelocityHi,X STA GameObjectYVelocityHi,X EggBounceYVelocityAlreadyDownward LDA GameObjectXVelocity,X DecelerateBouncingEggXVelocity BMI DecelerateBouncingEggLeft DEC GameObjectXVelocity,X JMP UpdateEggCoordsAfterCollision DecelerateBouncingEggLeft INC GameObjectXVelocity,X JMP UpdateEggCoordsAfterCollision HandlePlatformTopCollisionEgg LDA GameObjectYVelocityHi,X BNE EggIsMovingBounce LDA GameObjectXVelocity,X BNE EggIsMovingBounce LDA GameObjectYVelocityLo,X CMP #$28 BCC EggLandedOnPlatform EggIsMovingBounce SEC LDA #$00 SBC GameObjectYVelocityLo,X STA GameObjectYVelocityLo,X LDA #$00 SBC GameObjectYVelocityHi,X STA GameObjectYVelocityHi,X ROL ROR GameObjectYVelocityHi,X ROR GameObjectYVelocityLo,X LDA GameObjectXVelocity,X BNE DecelerateBouncingEggXVelocity RTS EggLandedOnPlatform LDA #$00 STA GameObjectDirection,X STA ObjectWiggleAnimation,X STA GameObjectInAir,X STA GameObjectYVelocityLo,X JSR CalculateLevelDifficultyRandomTimer LDA Temp5E STA GameObjectCountdownLo,X LDA Temp5F STA GameObjectCountdownHi,X UpdateEggCoordsAfterCollision LDA Temp65 STA GameObjectXCoordHi,X LDA Temp66 STA GameObjectYCoordHi,X RTS ;------------------------------------------------------------------------------ ; SpawnPointSafetyCheck ; Checks if a spawn point is safe for a new bird to appear. It iterates through ; all other birds to see if any are too close to the target spawn point. ; Input: X = index of bird to be spawned. ; Output: Temp60 = 0 if safe, non-zero if unsafe. ;------------------------------------------------------------------------------ SpawnPointSafetyCheck TXA PHA ; save X CPX #$02 BCC SafetyCheckForPlayer SafetyCheckForEnemy LDX #$03 JMP SafetyCheckLoop SafetyCheckForPlayer LDX #$00 SafetyCheckLoop LDA SpawnPlatformDissolved0,X BEQ HandleSpawnOnDissolvedPlatform LDY #$09 LDA #$00 STA TempSpawnUnsafeCounter,X CheckProximityToOtherObjectsLoop LDA.w GameObjectState,Y BEQ SpawnSafetyCheckDoNextObject CMP #$05 BEQ SpawnSafetyCheckDoNextObject CMP #$03 BEQ SpawnSafetyCheckDoNextObject CMP #$07 BEQ SpawnSafetyCheckDoNextObject CMP #$06 BNE ObjectStateIsValidForProximityCheck LDA GameObjectSpawnPlatformIndex,Y STX Temp5F CMP Temp5F BNE ObjectStateIsValidForProximityCheck HandleSpawnOnDissolvedPlatform INC TempSpawnUnsafeCounter,X JMP MarkSpawnPointUnsafeAndContinueCheck ObjectStateIsValidForProximityCheck LDA GameObjectYCoordHi,Y SEC SBC PlayerRespawnY,X BPL CompareAbsoluteYDistanceToMinimum EOR #$FF CLC ADC #$01 CompareAbsoluteYDistanceToMinimum CMP #$1E BCS SpawnSafetyCheckDoNextObject LDA GameObjectXCoordHi,Y SEC SBC PlayerRespawnX,X BPL CompareAbsoluteXDistanceToMinimum EOR #$FF CLC ADC #$01 CompareAbsoluteXDistanceToMinimum CMP #$28 BCS SpawnSafetyCheckDoNextObject JMP MarkSpawnPointUnsafeAndContinueCheck SpawnSafetyCheckDoNextObject DEY BPL CheckProximityToOtherObjectsLoop STX Temp60 PLA TAX RTS MarkSpawnPointUnsafeAndContinueCheck PLA PHA CMP #$02 BCS SafetyCheckLoop_Player INX CPX #$04 BCC SafetyCheckLoop JMP MarkSpawnPointUnsafeAndExit SafetyCheckLoop_Player DEX BPL SafetyCheckLoop MarkSpawnPointUnsafeAndExit LDA #$FF STA Temp60 PLA TAX RTS ;------------------------------------------------------------------------------ ; SetupEggWave ; Initializes all egg objects for an Egg Wave. It randomly places eggs on ; available platforms, ensuring they are not too clustered. ;------------------------------------------------------------------------------ SetupEggWave LDA #$00 STA EnemyBirdCount LDA #$07 TAX LDY #$0C STY EggsPresentCount DEY ; this is the start of the random egg placement code. JSR ReturnRandInA GetNewEggPosition STX Temp64 CMP NewEggXMaximum,X BCC EggXRangeFitsPlatform GetNewEggPositionLoop LDX Temp64 JSR ReturnRandInA DEX BPL GetNewEggPosition LDX #$07 JMP GetNewEggPosition EggXRangeFitsPlatform CLC ; The width of the random X range used fits ADC NewEggXOffset,X ; the platform width, so we just need to add STA EggX,Y ; to EggX to reach the X of the platform. LDA NewEggYCoordinate,X STA EggY,Y CPY #$0B ; first egg? if so then skip BEQ EggLocationValidationDone ; egg position validation EggLocationValidation ; We first ensure that no more than 5 eggs already exist on the same ; platform. Otherwise we fetch new egg coordinates. LDA #$05 STA Temp65 LDX #$0B LDA EggY,Y EggYCountCheckLoop CMP EggY,X BNE EggNotAtSameY1 DEC Temp65 BEQ GetNewEggPositionLoop EggNotAtSameY1 DEX STX Temp66 CPY Temp66 ; only check eggs up until the current one BNE EggYCountCheckLoop ; Now we ensure that our egg is at least 5 pixels away from any other ; eggs on the same platform. Otherwise we fetch new egg coordinates. LDX #$0B EggDistanceCheckLoop LDA EggY,Y CMP EggY,X BNE EggNotAtSameY2 LDA EggX,Y SEC SBC EggX,X ; Distance is OurEggX - ThisEggX BPL SkipDistanceInversion ; if we have a negative distance, we need to invert it (A=255-A) EOR #$FF CLC ADC #$01 SkipDistanceInversion CMP #$05 BCC GetNewEggPositionLoop EggNotAtSameY2 DEX STX Temp66 CPY Temp66 BNE EggDistanceCheckLoop EggLocationValidationDone LDA EggWaveEnemyType STA EggLevelAndType,Y LDA #$01 STA.w EggState,Y JSR CalculateLevelDifficultyRandomTimer LDA Temp5E STA $232E,Y LDA Temp5F STA $2315,Y LDA #$00 STA $2347,Y STA $221B,Y STA $227F,Y STA $22CA,Y STA $22FC,Y STA $2298,Y STA $22B1,Y DEY BMI ExitEggWaveSetup JMP GetNewEggPositionLoop ExitEggWaveSetup RTS ;------------------------------------------------------------------------------ ; CalculateLevelDifficultyRandomTimer ; Calculates a 16-bit random timer value influenced by game level and difficulty. ; Used for Pterodactyl appearance delays and egg hatching countdowns. ; The final timer is primarily based on a random value plus difficulty-scaled ; additions, with an initial offset to the high byte determined by the level. ; Outputs: Temp5E (Lo), Temp5F (Hi) ;------------------------------------------------------------------------------ CalculateLevelDifficultyRandomTimer TXA ; Preserve X register PHA TYA ; Preserve Y register PHA LDA #InitialTimerHiByteValue ; Initialize high byte of timer STA Temp5F ; Temp5F will act as the high byte accumulator ; Calculate loop counter for difficulty-based additions. ; Loop runs (DifficultyLoopCounterBase - Difficulty + 1) times. LDA #DifficultyLoopCounterBase SEC SBC Difficulty ; A = DifficultyLoopCounterBase - Difficulty TAX ; X will be the loop counter (0 to 3) ; Calculate an 8-bit term based on the current level. LDA #TimerLevelCalcBaseValue SEC SBC Level ; A = TimerLevelCalcBaseValue - Level ; Multiply this level-based term by 8 (ASL A three times). ; The carry from the third ASL (representing bit 8 of an 9-bit result) ; is added to Temp5F (timer high byte). The 8 LSBs in A are then discarded. ASL ; A = A * 2 ASL ; A = A * 4 ASL ; A = A * 8. Carry C holds the 9th bit. BCC CalculateTimer_LevelComponentDone ; If C=0, no carry into 9th bit. INC Temp5F ; C=1, (LevelTerm*8) overflowed 8 bits. Add to TimerHi. CalculateTimer_LevelComponentDone ; A currently holds (TimerLevelCalcBaseValue - Level)*8 AND $FF. This value is about to be overwritten. ; Temp5F holds 0 or 1 based on the carry from the above calculation. JSR ReturnRandInA ; A = RandomByte ; The subsequent ADC loop will start with this random byte as the LSB, ; and Temp5F as the initial MSB. CalculateTimer_DifficultyLoop ; Loop (X+1) times, adding to the (Temp5F,A) 16-bit value. ADC #RandomTimerLoopAddend ; A = A + RandomTimerLoopAddend + CarryFromPreviousADC (initially 0 for first ADC) BCC CalculateTimer_EndLoopIter ; If no carry from ADC to high byte INC Temp5F ; Add carry to high byte of timer CalculateTimer_EndLoopIter DEX ; Decrement difficulty-based loop counter BPL CalculateTimer_DifficultyLoop ; Loop if X >= 0 STA Temp5E ; Store final low byte of timer in Temp5E PLA ; Restore Y register TAY PLA ; Restore X register TAX RTS ;------------------------------------------------------------------------------ ; RunPterryCountdown ; Main logic for managing the Pterodactyl appearance timer and spawning. ;------------------------------------------------------------------------------ RunPterryCountdown LDA Difficulty BEQ RunPterryCountdownExit LDA PterryAliveCount CMP #$03 ; 3 Pterrys max BEQ RunPterryCountdownExit SEC LDA PterryCountdownLo SBC #$01 STA PterryCountdownLo LDA PterryCountdownHi BMI CheckForLiveEnemyBirds SBC #$00 STA PterryCountdownHi BMI CheckForLiveEnemyBirds RTS DelayPterry INC PterryCountdownLo RunPterryCountdownExit RTS CheckForLiveEnemyBirds LDX #$09 ; last bird object CheckForLiveEnemyBirdsLoop LDA GameObjectState,X CMP #$07 ; if a bird is being born2... BEQ DelayPterry ; ...delay spawning a pterry. CMP #$06 ; if a bird is transporting-in... BEQ DelayPterry ; ...delay spawning a pterry. CMP #$03 ; if a bird is being born1... BEQ DelayPterry ; ...delay spawning a pterry. DEX ; Check another Enemy bird object so long CPX #$02 ; as we haven't reached the player birds. BCS CheckForLiveEnemyBirdsLoop LDA #SFX_PterryCharging JSR ScheduleSFX INC PterryAliveCount LDX #$0A FindDeadPterryLoop LDA GameObjectState,X BEQ InitializeNewPterryObject INX CPX #$0D BCC FindDeadPterryLoop PterrySpawnFailCrashLoop BCS PterrySpawnFailCrashLoop ; crash loop, but shouldn't ever trigger InitializeNewPterryObject LDA #$0A ; Normal Pterry state STA GameObjectState,X LDA #$04 STA ObjectBirdLevelAndType,X LDA #$00 STA GameObjectYVelocityHi,X STA GameObjectYVelocityLo,X LDA #$03 STA GameObjectAnimationCounter,X LDA #$02 STA GameObjectAnimationFrame,X LDA #$FA STA GameObjectChargingTimer,X LDA #$02 STA GameObjectAITimerLo,X JSR SetPterryInitialSpawnParameters CPX #$0A BNE UpdatePterryRespawnTimerAndExit LDA PterryAgressionFlag CMP #$02 BNE UpdatePterryRespawnTimerAndExit LDA PterryAgressionFlag+1 CMP #$02 BEQ ResetPterryCountdownForced UpdatePterryRespawnTimerAndExit JSR UpdatePterryRespawnTimer LSR PterryCountdownHi ; divide the pterry ROR PterryCountdownLo ; countdown by two RTS ResetPterryCountdownForced LDA #$00 STA PterryCountdownHi LDA #$14 STA PterryCountdownLo RTS ; Look-up table for initial Y coordinates for Pterodactyl spawn. ; Indexed by (RandomByte AND PTERRY_SPAWN_Y_COORD_MASK). PterrySpawnYCoordLUT .byte $94, $52, $52, $15 ; Look-up table for initial X coordinates for Pterodactyl spawn. ; Indexed by (RandomByte AND PTERRY_SPAWN_XDIRVEL_MASK). PterrySpawnXCoordLUT .byte $15, $BA ; Look-up table for initial facing direction for Pterodactyl spawn. ; $01 = Right, $FF = Left. ; Indexed by (RandomByte AND PTERRY_SPAWN_XDIRVEL_MASK). PterrySpawnDirectionLUT .byte Direction_Right, Direction_Left ; Look-up table for initial X velocities for Pterodactyl spawn. PterrySpawnXVelocityLUT .byte $05, $FB ;------------------------------------------------------------------------------ ; SetPterryInitialSpawnParameters ; Sets the initial spawn parameters for a new Pterodactyl and ensures it does ; not spawn too close to a player. Re-randomizes if it's too close. ; Input: X = Pterodactyl object index ;------------------------------------------------------------------------------ SetPterryInitialSpawnParameters TryNewPterrySpawnParameters JSR ReturnRandInA ; Get a random byte in A AND #PTERRY_SPAWN_Y_COORD_MASK ; Mask to get index 0-3 for Y LUT TAY ; Y = random index for Y coordinate LDA PterrySpawnYCoordLUT,Y ; Load Y coordinate STA GameObjectYCoordHi,X ; Set Pterry's initial Y JSR ReturnRandInA ; Get another random byte AND #PTERRY_SPAWN_XDIRVEL_MASK ; Mask to get index 0-1 for X/Dir/XVel LUTs TAY ; Y = random index for X, Direction, X-Velocity LDA PterrySpawnXCoordLUT,Y ; Load X coordinate STA GameObjectXCoordHi,X ; Set Pterry's initial X LDA PterrySpawnDirectionLUT,Y ; Load direction STA GameObjectDirection,X ; Set Pterry's initial direction LDA PterrySpawnXVelocityLUT,Y ; Load X-velocity STA GameObjectXVelocity,X ; Set Pterry's initial X-velocity LDY PlayerCount ; Y = number of players (0 for 1P, 1 for 2P; used as player object index) ; Player 0 is index 0, Player 1 is index 1. CheckPterrySpawnProximityToPlayerLoop ; Calculate absolute X distance to current player Y LDA GameObjectXCoordHi,X ; Pterry's X SEC SBC GameObjectXCoordHi,Y ; Pterry's X - Player Y's X BMI PterryXDistIsNegativeOrZero ; If result is negative (PlayerX > PterryX) EOR #$FF ; Make positive (abs value part 1) CLC ADC #$01 ; Make positive (abs value part 2) PterryXDistIsNegativeOrZero CMP #PTERRY_MIN_SPAWN_DIST_X ; Compare |PterryX - PlayerX| with $30 BCS PterrySpawnIsFarEnoughFromThisPlayer ; If dist >= $30, X is okay for this player. ; X distance < PTERRY_MIN_SPAWN_DIST_X, now check Y distance LDA GameObjectYCoordHi,X ; Pterry's Y SEC SBC GameObjectYCoordHi,Y ; Pterry's Y - Player Y's Y BMI PterryYDistIsNegativeOrZero ; If result is negative (PlayerY > PterryY) EOR #$FF ; Make positive (abs value part 1) PterryYDistIsNegativeOrZero ; Note: CLC ADC #$01 for abs value missing if BMI not taken. ; However, since we only care about CMP < $20, a large positive ; (if PterryY > PlayerY) will correctly fail the BCC. ; If PterryY < PlayerY, BMI is taken, and it becomes positive small. CMP #PTERRY_MIN_SPAWN_DIST_Y ; Compare |PterryY - PlayerY| with $20 BCC SetPterryInitialSpawnParameters ; If dist < $20, Pterry is too close. Re-randomize. PterrySpawnIsFarEnoughFromThisPlayer DEY ; Next player index (from PlayerCount down to -1) BPL CheckPterrySpawnProximityToPlayerLoop ; If Y >= 0, check next player. RTS ; Pterry spawn position is okay for all players. ;------------------------------------------------------------------------------ ; RunPterryProcessing ; Main routine to update the state and behavior of a Pterodactyl object. ; This is a state machine handling its movement, AI, and collision. ; Input: X = Pterodactyl object index ;------------------------------------------------------------------------------ RunPterryProcessing LDA GameObjectState,X BNE PterryIsAliveAndNotDeadState JMP ExitPterryProcessing_NoAction ; If state is 0 (dead), do nothing PterryIsAliveAndNotDeadState CMP #PterryState_DefeatedVisual ; Is Pterry in its "defeated" visual effect state ($0D)? BNE PterryNotInDefeatedVisualState ; If not, proceed to normal state processing ; Pterry is in "defeated" visual state (e.g., spinning off screen) DEC GameObjectXCoordLo,X ; Update sub-pixel X for visual effect BEQ PterryDefeatedVisual_UpdateY_And_Frame ; If XCoordLo wrapped, update Y and frame RTS ; Otherwise, visual effect continues PterryDefeatedVisual_UpdateY_And_Frame INC GameObjectAnimationFrame,X ; Advance animation frame for defeat visual DEC GameObjectYCoordLo,X ; Update sub-pixel Y for visual effect BEQ PterryDefeatedVisual_FullyOffscreen ; If YCoordLo wrapped, Pterry is gone LDA #$0A ; Reset XCoordLo for next part of visual effect STA GameObjectXCoordLo,X RTS PterryDefeatedVisual_FullyOffscreen LDA #State_Dead ; Pterry is now fully dead and off-screen STA GameObjectState,X DEC PterryAliveCount ; Decrement count of active Pterodactyls LDA #$01 ; Flag related to Pterry state or scoring? STA PterryDefeatedFlag,X ; Store this flag (unknown purpose, maybe related to next Pterry spawn timing) LDA GameObjectYCoordHi,X ; Store Pterry's last Y position STA TempPterryCoordY LDA GameObjectXCoordHi,X ; Store Pterry's last X position STA TempPterryCoordX LDA #$03 STA TempPterryScoreValue JMP CreateScorePopupAtObjectLocation ; Create a score popup PterryNotInDefeatedVisualState JSR CheckPterryPlatformCollision ; Returns collision type in A, Temp65/Temp66 updated with new coords if bounced BEQ PterryNoPlatformCollision ; If A is 0, no collision or standard fall-through BMI PterryHitPlatform_MoveUp ; If A is negative, hit bottom of platform, bounce up ; Pterry hit side or top of platform (A is positive) CLC LSR ; A = A / 2 (collision type to direction/action bits) BCS PterryHitPlatform_FaceLeftAndReverseXVel ; Bit 0 set: hit right side LSR ; A = A / 2 BCS PterryHitPlatform_MoveDownSlightly ; Bit 1 set: hit top, shallow bounce LSR ; A = A / 2 BCS PterryHitPlatform_MoveDownSlightly ; Bit 2 set: hit top, shallow bounce (alternative condition) LSR ; A = A / 2 BCC PterryNoPlatformCollision ; Bit 3 clear: no significant horizontal reaction needed ; Bit 3 set: hit left side LDA #Direction_Right ; Change direction to right STA GameObjectDirection,X LDA GameObjectXVelocity,X ; Reverse X velocity EOR #$FF CLC ADC #$01 STA GameObjectXVelocity,X JMP PterryPlatformCollision_FinalizeBounce PterryHitPlatform_MoveDownSlightly ; Hit top of platform, shallow bounce down LDA GameObjectYCoordHi,X SEC SBC #$02 ; Move Pterry down slightly (adjust Y coord up on screen) STA GameObjectYCoordHi,X JMP PterryPlatformCollision_FinalizeBounce PterryHitPlatform_MoveUp ; Hit bottom of platform, bounce up LDA GameObjectYCoordHi,X CLC ADC #$02 ; Move Pterry up slightly (adjust Y coord down on screen) STA GameObjectYCoordHi,X JMP PterryPlatformCollision_FinalizeBounce PterryHitPlatform_FaceLeftAndReverseXVel ; Hit right side of platform LDA #Direction_Left ; Change direction to left STA GameObjectDirection,X LDA GameObjectXVelocity,X ; Reverse X velocity EOR #$FF CLC ADC #$01 STA GameObjectXVelocity,X ; Fall through to PterryPlatformCollision_FinalizeBounce PterryPlatformCollision_FinalizeBounce ; Common code after platform collision LDA #SFX_BirdPlatformBounce ; Pterry uses bird bounce sound for platforms JSR ScheduleSFX LDA Temp65 ; Temp65 holds adjusted X from CheckPterryPlatformCollision STA GameObjectXCoordHi,X LDA Temp66 ; Temp66 holds adjusted Y from CheckPterryPlatformCollision STA GameObjectYCoordHi,X PterryNoPlatformCollision ; No platform collision or handled above JSR UpdateAirborneObjectPhysics ; Apply standard airborne physics (gravity, X/Y movement) CheckPterryStateAfterPhysics LDA GameObjectState,X CMP #PterryState_Leaving ; Is Pterry leaving the screen? BNE CheckPterryState_NormalOrCharging JSR SetPterryVelocityForChargingScreen ; Set fast velocity JSR AdjustBirdYBasedOnAltitude ; Fine-tune Y velocity for leaving JMP UpdatePterryTargetingAndVerticalVelocity_Main ; Further Y velocity adjustments and animation CheckPterryState_NormalOrCharging CMP #PterryState_Normal ; If Pterry is normal do his regular logic BEQ HandlePterryNormalStateLogic ; Pterry must be in Charging state ($0B) LDA GameObjectChargingTimer,X ; Check charging timer BEQ PterryChargeTimerExpired DEC GameObjectChargingTimer,X ; Decrement charging timer JMP ExitPterryProcessing_NoAction ; Continue charging PterryChargeTimerExpired LDA #PterryState_Normal ; Charge finished, switch to normal state STA GameObjectState,X LDA #$FA ; Reset timer for next charge cycle (long delay) STA GameObjectChargingTimer,X ; Set velocity back to normal Pterry speed LDA GameObjectDirection,X BPL SetPterryNormalVelocity_RightFacing LDA #$00 ; Why? This could have just been LDA #$FD. :| SEC ; Maybe the velocity was originally a variable SBC #$03 ; instead of a constant. JMP SetPterryNormalVelocity_Store SetPterryNormalVelocity_RightFacing LDA #$03 ; Normal speed right SetPterryNormalVelocity_Store STA GameObjectXVelocity,X ExitPterryProcessing_NoAction RTS HandlePterryNormalStateLogic LDA GameObjectChargingTimer,X ; Timer before Pterry starts charging BEQ PterryStartChargingSequence DEC GameObjectChargingTimer,X JMP ProcessPterryAIAndAnimation PterryStartChargingSequence LDA #SFX_PterryCharging JSR ScheduleSFX LDA #PterryState_Charging ; Switch to charging state STA GameObjectState,X LDA #$02 ; Initial animation frame for charging STA GameObjectAnimationFrame,X LDA #$03 ; Initial animation counter for charging STA GameObjectAnimationCounter,X LDA #$00 ; Zero out Y velocity when starting charge STA GameObjectYVelocityHi,X STA GameObjectYVelocityLo,X LDA #$5A ; Duration of the charge STA GameObjectChargingTimer,X ; Fall through to SetPterryVelocityForChargingScreen SetPterryVelocityForChargingScreen LDA GameObjectDirection,X BPL SetPterryChargeVelocity_RightFacing LDA #$00 ; Again, this could have been LDA #$FB SEC ; since all of the values are constants, SBC #$05 ; instead of subtracting. JMP SetPterryChargeVelocity_Store SetPterryChargeVelocity_RightFacing LDA #$05 ; Charge speed right SetPterryChargeVelocity_Store STA GameObjectXVelocity,X RTS ProcessPterryAIAndAnimation LDA GameObjectAITimerLo,X ; Low byte of AI decision timer BEQ PterryAITimerExpired_MakeDecision DEC GameObjectAITimerLo,X LDA PterryYVelocityZero ; Set Y velocity to 0 (ROM const $00) JMP UpdatePterryTargetingAndVerticalVelocity_Main PterryAITimerExpired_MakeDecision LDA #$02 ; Reset AI action timer low byte STA GameObjectAITimerLo,X JSR FindBestTargetForGameObject ; Find a player target LDY GameObjectPreyIndex,X ; Y = index of targeted player BMI PterryNoValidTarget_AdjustYVel ; If no target (or target invalid), just adjust Y based on altitude ; Target acquired, adjust Y velocity to intercept LDA GameObjectYCoordHi,Y ; Target's Y CLC ADC #$02 ; Add slight offset to target Y (aim slightly below target) CMP GameObjectYCoordHi,X ; Compare with Pterry's Y BCS PterryTargetIsLowerOrSame_FlyDown ; If Pterry is above target (TargetY >= PterryY), fly down ; Pterry is below target, needs to fly up CLC ADC #$01 ; Add a bit more to make comparison for "slightly up" CMP GameObjectYCoordHi,X BCC PterryTargetIsHigher_FlyUpSlightly ; If Pterry is still significantly below, fly up slightly ; Pterry is very close vertically, fly level LDA PterryYVelocityZero JMP UpdatePterryTargetingAndVerticalVelocity_Main PterryNoValidTarget_AdjustYVel ; No target, or lost target JSR AdjustBirdYBasedOnAltitude ; Adjust Y based on general altitude zones JMP UpdatePterryTargetingAndVerticalVelocity_Main PterryTargetIsHigher_FlyUpSlightly LDA PterryYVelocitySlightUp ; Set Y velocity to slight up (ROM const $FF) JMP UpdatePterryTargetingAndVerticalVelocity_Main PterryTargetIsLowerOrSame_FlyDown LDA PterryYVelocitySlightDown ; Set Y velocity to slight down (ROM const $01) ; Fall through to UpdatePterryTargetingAndVerticalVelocity_Main UpdatePterryTargetingAndVerticalVelocity_Main STA GameObjectYVelocityHi,X ; Store determined Y velocity LDA GameObjectAnimationDelay,X ; Check animation delay timer BEQ PterryAnimationDelay_Expired DEC GameObjectAnimationDelay,X RTS PterryAnimationDelay_Expired LDY GameObjectAnimationCounter,X ; Get current animation sequence counter LDA PterryFrameIndexAdjustmentLUT,Y ; Get frame adjustment based on counter CLC ADC GameObjectAnimationFrame,X ; Add to current animation frame STA GameObjectAnimationFrame,X ; Store new frame DEC GameObjectAnimationCounter,X ; Decrement animation sequence counter BPL SkipPterryAnimCounterWrap LDA #$03 ; Wrap counter if it went negative STA GameObjectAnimationCounter,X SkipPterryAnimCounterWrap LDA #$04 ; Reset animation delay timer STA GameObjectAnimationDelay,X RTS ;------------------------------------------------------------------------------ ; Player vs Pterodactyl Collision ; Input: X = Player index ;------------------------------------------------------------------------------ HandlePlayerVsPterry LDY #$0C PlayerVsPterryCollisionLoop LDA.w GameObjectState,Y BEQ CheckNextPterryForCollision CMP #$0D BEQ CheckNextPterryForCollision JSR GameObjCollisionDetection ; returns carry is clear on collision BCC PlayerVsPterryDetermineJoustWinner CheckNextPterryForCollision DEY CPY #$0A BCS PlayerVsPterryCollisionLoop RTS PlayerVsPterryDetermineJoustWinner ; Collision occurred. Check vertical alignment to see who wins. LDA GameObjectYCoordHi,Y STA Temp5E DEC Temp5E DEC Temp5E LDA GameObjectYCoordHi,X CMP Temp5E BEQ PterryAndPlayerSameHeight ; Player is slightly above Pterry INC Temp5E CMP Temp5E BEQ PterryAndPlayerSameHeight ; Player is level with Pterry INC Temp5E CMP Temp5E BEQ PterryAndPlayerSameHeight ; Player is slightly below Pterry JMP StartPlayerDeath ; Player is too low, player dies PterryAndPlayerSameHeight LDA GameObjectDirection,X CMP GameObjectDirection,Y BNE PlayerJoustedPterry JMP StartPlayerDeath ; Player wasn't facing pterry, player dies PlayerJoustedPterry LDA GameObjectDirection,X EOR #$FF CLC ADC #$01 STA GameObjectDirection,X LDA #$00 STA GameObjectXVelocity,X STA GameObjectXVelocity,Y LDA #SFX_PterryDefeated JSR ScheduleSFX LDA #$0D STA.w GameObjectState,Y LDA #$02 STA GameObjectYCoordLo,Y LDA #$0A STA GameObjectXCoordLo,Y LDA #$03 STA GameObjectAnimationFrame,Y LDA #$01 STA Temp61ScoreAdd LDA #$00 STA Temp62ScoreAdd JMP UpdatePlayerScoreAndBonus ;------------------------------------------------------------------------------ ; SetAnyPterrysToLeaving ; Sets the state of all active Pterodactyls to "Leaving" ($0C). ;------------------------------------------------------------------------------ SetAnyPterrysToLeaving LDY #$0C STY PterryCountdownHi SetAnyPterrysToLeavingLoop LDA.w GameObjectState,Y BEQ SkipPterryLeavingUpdate ; skip if pterry is dead and gone CMP #$0D BEQ SkipPterryLeavingUpdate ; skip if pterry is offscreen LDA #$0C STA.w GameObjectState,Y SkipPterryLeavingUpdate DEY CPY #$0A BCS SetAnyPterrysToLeavingLoop RTS ;------------------------------------------------------------------------------ ; Collision Detection Data ; These LUTs define parameters for the simplified collision detection. ;------------------------------------------------------------------------------ ObjectOffsetXLUT .byte $04,$04,$04,$04,$04,$04,$04,$04,$04,$04 ; birds .byte $07,$07,$07 ; pterrys .byte $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02 ; eggs ObjectOffsetYLUT .byte $05,$06,$05,$05,$05,$05,$05,$05,$05,$05 ; birds .byte $05,$05,$05 ; pterrys .byte $03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03 ; eggs ObjectCollisionWidthLUT .byte $07,$07,$07,$07,$07,$07,$07,$07,$07,$07 ; birds .byte $0C,$0C,$0C ; pterrys .byte $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05 ; eggs ObjectCollisionHeightLUT .byte $09,$0B,$09,$09,$09,$09,$09,$09,$09,$09 ; birds .byte $09,$09,$09 ; pterrys .byte $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07 ; eggs ;------------------------------------------------------------------------------ ; GameObjCollisionDetection ; Performs a simplified Axis-Aligned Bounding Box (AABB) collision check ; between two game objects. ; Input: X = Index of the first game object. ; Y = Index of the second game object. ; Output: Carry Flag: SET if NO collision, CLEAR if collision. ; TempCollisionOverlap holds absolute Y-distance on collision. ;------------------------------------------------------------------------------ GameObjCollisionDetection ; Calculate Effective X coordinate for Object X LDA GameObjectXCoordHi,X ; Load ObjX's base X coord CLC ADC ObjectOffsetXLUT,X ; Add ObjX's X offset STA Temp5E ; Store EffX_ObjX in Temp5E ; Calculate absolute difference between Effective X of ObjX and Effective X of ObjY LDA GameObjectXCoordHi,Y ; Load ObjY's base X coord CLC ADC ObjectOffsetXLUT,Y ; Add ObjY's X offset (EffX_ObjY) SEC ; Prepare for subtraction SBC Temp5E ; A = EffX_ObjY - EffX_ObjX BPL CalculateAbsX_IsPositive ; If result is positive, it's the absolute difference EOR #$FF ; Negate the result (part 1) CLC ADC #$01 ; Negate the result (part 2, to get absolute value) CalculateAbsX_IsPositive STA Temp66 ; Store absolute X-distance in Temp66 ; Check for X-axis overlap using Object Y's collision width threshold CMP ObjectCollisionWidthLUT,Y ; Compare abs X-distance with ObjY's collision width threshold BCS NoCollisionDetected_Return ; If DistX >= Width_Y, no X-overlap. Set Carry and RTS. ; X-axis overlaps, now check Y-axis ; Calculate Effective Y coordinate for Object X LDA GameObjectYCoordHi,X ; Load ObjX's base Y coord CLC ADC ObjectOffsetYLUT,X ; Add ObjX's Y offset STA Temp5E ; Store EffY_ObjX in Temp5E ; Calculate absolute difference between Effective Y of ObjX and Effective Y of ObjY LDA GameObjectYCoordHi,Y ; Load ObjY's base Y coord CLC ADC ObjectOffsetYLUT,Y ; Add ObjY's Y offset (EffY_ObjY) SEC ; Prepare for subtraction SBC Temp5E ; A = EffY_ObjY - EffY_ObjX BPL CalculateAbsY_IsPositive ; If positive, it's the absolute difference EOR #$FF ; Negate (part 1) CLC ADC #$01 ; Negate (part 2, to get absolute value) CalculateAbsY_IsPositive STA TempCollisionOverlap ; Store absolute Y-distance ; Special collision height check if Object Y is Player 1 CPY #PLAYER1_OBJECT_INDEX ; Is Object Y Player 1? BEQ CheckCollision_Player1_Y_Height ; Yes, branch to P1 specific height check ; Object Y is not Player 1, use its standard collision height from LUT CMP ObjectCollisionHeightLUT,Y ; Compare abs Y-distance with ObjY's collision height threshold ; Carry will be CLEAR if DistY < Height_Y (collision) ; Carry will be SET if DistY >= Height_Y (no collision) ; Fall through to RTS. If BCS was taken (no collision), Carry is SET. ; If CMP results in DistY < Height_Y, Carry is CLEAR (collision). NoCollisionDetected_Return RTS ; Return with Carry SET (no collision) or CLEAR (collision) CheckCollision_Player1_Y_Height ; Player 1 specific Y-collision height check (functionally same as LUT for P1) CMP #PLAYER1_COLLISION_HEIGHT_SPECIAL ; Compare abs Y-distance with P1's specific height value ; Carry will be CLEAR if DistY < Value (collision) ; Carry will be SET if DistY >= Value (no collision) RTS ; Return with Carry status from CMP ;------------------------------------------------------------------------------ ; ESRoutineScheduler ; Event Scheduler main loop. Iterates through 18 event slots. ; If an event's index is positive, it executes the corresponding routine. ; If an event's index is negative, it treats it as a countdown timer. When the ; timer reaches zero, the index is made positive so it will run on the next pass. ;------------------------------------------------------------------------------ ESRoutineScheduler INC IncrementingRandSeed LDX #$11 ESRoutineSchedulerLoop LDA ESRoutineIndex,X BEQ ESRoutineSchedulerLoopBottom ; if index=0 handler is off BMI UpdateEventTimers ; if index<0 update this timer ; if index>0 run this routine ASL TAY ; y=index*2 (table has sequential lo+hi pairs) LDA ESRoutinesLo,Y STA TempPoint5ACurrentESRoutineLo LDA ESRoutinesHi,Y STA TempPoint5ACurrentESRoutineHi JMP (TempPoint5ACurrentESRoutineLo) UpdateEventTimers DEC ESRoutineTimer,X BNE EventTimerStillCountingDown ; Once the timer expires, we invert the function index to turn off ; the timer. The next time the handler loop is called, it will run. LDA ESRoutineIndex,X EOR #$FF STA ESRoutineIndex,X INC ESRoutineIndex,X EventTimerStillCountingDown JMP ESRoutineSchedulerLoopBottom ESScheduleNextRoutine ; Common endpoint for many ES Jump table functions. Sets/Resets timer ; and advances and inverts the index. (index=0-index+1) STA ESRoutineTimer,X LDA ESRoutineIndex,X EOR #$FF ESUpdateRoutineIndex STA ESRoutineIndex,X ESRoutineSchedulerLoopBottom DEX BPL ESRoutineSchedulerLoop RTS ESCancelRoutine ; Cancels the currently running event by setting its index to 0. LDA #$00 BEQ ESUpdateRoutineIndex ;------------------------------------------------------------------------------ ; Event Scheduler Routine Jump Table ;------------------------------------------------------------------------------ ESRoutinesLo ; Event Timer jump table .byte <ESGameColdInit ; event index $00 ESRoutinesHi .byte >ESGameColdInit .byte <ESSetPointedValueFromRandom ; event index $01 .byte >ESSetPointedValueFromRandom .byte <ES_AdvanceLavaSparkleFrame ; event index $02 .byte >ES_AdvanceLavaSparkleFrame .byte <ES_ReverseLavaSparkleFrame ; event index $03 .byte >ES_ReverseLavaSparkleFrame .byte <ES_SetRandomLavaSparkleFrameAndCancel ; event index $04 .byte >ES_SetRandomLavaSparkleFrameAndCancel .byte <ESSetupFlameAnimation ; event index $05 .byte >ESSetupFlameAnimation .byte <ESDoFlameAnimation ; event index $06 .byte >ESDoFlameAnimation .byte <ESSetupBridgeBurning ; event index $07 .byte >ESSetupBridgeBurning .byte <ESAnimateBridgeBurning ; event index $08 .byte >ESAnimateBridgeBurning .byte <ESAnimateBridgeReforming ; event index $09 .byte >ESAnimateBridgeReforming .byte <ESWave1StartRoutines ; event index $0A .byte >ESWave1StartRoutines .byte <ESRaiseLavaWave1 ; event index $0B .byte >ESRaiseLavaWave1 .byte <ESWave2StartRoutines ; event index $0C .byte >ESWave2StartRoutines .byte <ESRaiseLavaWave2 ; event index $0D .byte >ESRaiseLavaWave2 .byte <ESWave3StartRoutines ; event index $0E .byte >ESWave3StartRoutines .byte <ESRaiseLavaWave3 ; event index $0F .byte >ESRaiseLavaWave3 .byte <ES_StartEndOfWaveBonusDisplayTimer ; event index $10 .byte >ES_StartEndOfWaveBonusDisplayTimer .byte <ESTransitionToNextLevel ; event index $11 .byte >ESTransitionToNextLevel .byte <ES_StartBuzzardBaitWarningDelay ; event index $12 .byte >ES_StartBuzzardBaitWarningDelay .byte <ESShowBuzzardBaitText ; event index $13 .byte >ESShowBuzzardBaitText .byte <ES_StartPreWaveEnemySpawnDelay ; event index $14 .byte >ES_StartPreWaveEnemySpawnDelay .byte <ESIfEggWaveDoSetup ; event index $15 .byte >ESIfEggWaveDoSetup .byte <UNUSED_ES_AdvanceBottomPlatformDissolve ; event index $16 .byte >UNUSED_ES_AdvanceBottomPlatformDissolve .byte <UNUSED_ES_AdvanceBottomPlatformDissolve ; event index $17 .byte >UNUSED_ES_AdvanceBottomPlatformDissolve .byte <UNUSED_ES_AdvanceBottomPlatformDissolve ; event index $18 .byte >UNUSED_ES_AdvanceBottomPlatformDissolve .byte <UNUSED_ES_AdvanceBottomPlatformDissolve ; event index $19 .byte >UNUSED_ES_AdvanceBottomPlatformDissolve .byte <UNUSED_ES_SetBottomPlatformDissolveDelay ; event index $1A .byte >UNUSED_ES_SetBottomPlatformDissolveDelay .byte <UNUSED_ES_CleanupBottomPlatformDissolve ; event index $1B .byte >UNUSED_ES_CleanupBottomPlatformDissolve ; this sequence of functions does the top center platform (4) dissolve animation... .byte <ESShakePlatform4Left ; event index $1C .byte >ESShakePlatform4Left .byte <ESShakePlatform4Right ; event index $1D .byte >ESShakePlatform4Right .byte <ESShakePlatform4Left ; event index $1E .byte >ESShakePlatform4Left .byte <ESShakePlatform4Right ; event index $1F .byte >ESShakePlatform4Right .byte <ESShakePlatform4Left ; event index $20 .byte >ESShakePlatform4Left .byte <ESShakePlatform4Right ; event index $21 .byte >ESShakePlatform4Right .byte <ESShakePlatform4Left ; event index $22 .byte >ESShakePlatform4Left .byte <ESShakePlatform4Right ; event index $23 .byte >ESShakePlatform4Right .byte <ESStartPlatform4DissolveVisuals ; event index $24 .byte >ESStartPlatform4DissolveVisuals .byte <ESUpdatePlatform4DissolveParticles ; event index $25 .byte >ESUpdatePlatform4DissolveParticles .byte <ESUpdatePlatform4DissolveParticles ; event index $26 .byte >ESUpdatePlatform4DissolveParticles .byte <ESUpdatePlatform4DissolveParticles ; event index $27 .byte >ESUpdatePlatform4DissolveParticles .byte <AdvancePlatform4DissolveFrame ; event index $28 .byte >AdvancePlatform4DissolveFrame .byte <ESUpdatePlatform4DissolveParticles ; event index $29 .byte >ESUpdatePlatform4DissolveParticles .byte <ESUpdatePlatform4DissolveParticles ; event index $2A .byte >ESUpdatePlatform4DissolveParticles .byte <ESUpdatePlatform4DissolveParticles ; event index $2B .byte >ESUpdatePlatform4DissolveParticles .byte <ESDissolvingPlatformAnimationCleanup ; event index $2C .byte >ESDissolvingPlatformAnimationCleanup ; this sequence of functions does the top side-wrapping platform (5+6) dissolve animation... .byte <ESShakePlatforms56Left ; event index $2D .byte >ESShakePlatforms56Left .byte <ESShakePlatforms56Right ; event index $2E .byte >ESShakePlatforms56Right .byte <ESShakePlatforms56Left ; event index $2F .byte >ESShakePlatforms56Left .byte <ESShakePlatforms56Right ; event index $30 .byte >ESShakePlatforms56Right .byte <ESShakePlatforms56Left ; event index $31 .byte >ESShakePlatforms56Left .byte <ESShakePlatforms56Right ; event index $32 .byte >ESShakePlatforms56Right .byte <ESShakePlatforms56Left ; event index $33 .byte >ESShakePlatforms56Left .byte <ESShakePlatforms56Right ; event index $34 .byte >ESShakePlatforms56Right .byte <ESStartPlatforms56DissolveVisuals ; event index $35 .byte >ESStartPlatforms56DissolveVisuals .byte <ESUpdatePlatforms56DissolveParticles ; event index $36 .byte >ESUpdatePlatforms56DissolveParticles .byte <ESUpdatePlatforms56DissolveParticles ; event index $37 .byte >ESUpdatePlatforms56DissolveParticles .byte <ESUpdatePlatforms56DissolveParticles ; event index $38 .byte >ESUpdatePlatforms56DissolveParticles .byte <ESAdvancePlatforms56DissolveFrame ; event index $39 .byte >ESAdvancePlatforms56DissolveFrame .byte <ESUpdatePlatforms56DissolveParticles ; event index $3A .byte >ESUpdatePlatforms56DissolveParticles .byte <ESUpdatePlatforms56DissolveParticles ; event index $3B .byte >ESUpdatePlatforms56DissolveParticles .byte <ESUpdatePlatforms56DissolveParticles ; event index $3C .byte >ESUpdatePlatforms56DissolveParticles .byte <ESDissolvingPlatformAnimationCleanup ; event index $3D .byte >ESDissolvingPlatformAnimationCleanup ; this sequence of functions does the low center platform (0) dissolve animation... .byte <ESShakePlatform0Left ; event index $3E .byte >ESShakePlatform0Left .byte <ESShakePlatform0Right ; event index $3F .byte >ESShakePlatform0Right .byte <ESShakePlatform0Left ; event index $40 .byte >ESShakePlatform0Left .byte <ESShakePlatform0Right ; event index $41 .byte >ESShakePlatform0Right .byte <ESShakePlatform0Left ; event index $42 .byte >ESShakePlatform0Left .byte <ESShakePlatform0Right ; event index $43 .byte >ESShakePlatform0Right .byte <ESShakePlatform0Left ; event index $44 .byte >ESShakePlatform0Left .byte <ESShakePlatform0Right ; event index $45 .byte >ESShakePlatform0Right .byte <ESStartPlatform0DissolveVisuals ; event index $46 .byte >ESStartPlatform0DissolveVisuals .byte <ESUpdatePlatform0DissolveParticles ; event index $47 .byte >ESUpdatePlatform0DissolveParticles .byte <ESUpdatePlatform0DissolveParticles ; event index $48 .byte >ESUpdatePlatform0DissolveParticles .byte <ESUpdatePlatform0DissolveParticles ; event index $49 .byte >ESUpdatePlatform0DissolveParticles .byte <ESAdvancePlatform0DissolveFrame ; event index $4A .byte >ESAdvancePlatform0DissolveFrame .byte <ESUpdatePlatform0DissolveParticles ; event index $4B .byte >ESUpdatePlatform0DissolveParticles .byte <ESUpdatePlatform0DissolveParticles ; event index $4C .byte >ESUpdatePlatform0DissolveParticles .byte <ESUpdatePlatform0DissolveParticles ; event index $4D .byte >ESUpdatePlatform0DissolveParticles .byte <ESDissolvingPlatformAnimationCleanup ; event index $4E .byte >ESDissolvingPlatformAnimationCleanup UNUSED_ES_AdvanceBottomPlatformDissolve INC SpawnPlatformDissolved1,X UNUSED_ES_SetBottomPlatformDissolveDelay LDA #$04 JMP ESScheduleNextRoutine UNUSED_ES_CleanupBottomPlatformDissolve LDA #$00 STA SpawnPlatformDissolved1,X JMP ESCancelRoutine ES_StartPreWaveEnemySpawnDelay LDA #$50 JMP ESScheduleNextRoutine ESIfEggWaveDoSetup TXA PHA TYA PHA JSR InitializeWave LDA IsEggWave BEQ EggWaveSetupDone JSR SetupEggWave EggWaveSetupDone PLA TAY PLA TAX JMP ESCancelRoutine ESDissolvingPlatformAnimationCleanup LDA #$00 LDY #$05 PlatformAnimationCleanupLoop STA PlatformDissolveAnimationFlag0,Y ; reset all 6 flags DEY BPL PlatformAnimationCleanupLoop STA ESRoutineIndex,X JMP ESRoutineSchedulerLoopBottom ; Platforms by number: ; 0: Bottom center ; 1: Bottom left (wraps) ; 2: Bottom right (wraps) ; 3: Mid-level platform ; 4: Top center ; 5: Top left (wraps) ; 6: Top right (wraps) ESShakePlatform4Left DEC Platform4XCoordinate DEC SpawnPoint4XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESShakePlatform4Right INC Platform4XCoordinate INC SpawnPoint4XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESStartPlatform4DissolveVisuals LDA #$00 STA Platform4PaletteWidth STA Platform4GfxLo LDA #$01 STA PlatformDissolveAnimationFlag0 STA PlatformDissolveAnimationFlag1 LDA #$32 STA PlatformDissolveAnimationXCoord0 LDA #$3E STA PlatformDissolveAnimationXCoord1 LDA #$41 STA PlatformDissolveAnimationYCoord0 STA PlatformDissolveAnimationYCoord1 LDA #$02 JMP ESScheduleNextRoutine ESUpdatePlatform4DissolveParticles INC PlatformDissolveAnimationXCoord0 DEC PlatformDissolveAnimationXCoord1 INC PlatformDissolveAnimationYCoord0 INC PlatformDissolveAnimationYCoord1 LDA #$02 JMP ESScheduleNextRoutine AdvancePlatform4DissolveFrame INC PlatformDissolveAnimationFlag0 INC PlatformDissolveAnimationFlag1 LDA #$02 JMP ESScheduleNextRoutine ESShakePlatforms56Left ; this label is misleading, but named to match the existing pattern ; The two platform halves shake by moving in and out. DEC Platform5XCoordinate INC Platform6XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESShakePlatforms56Right INC Platform5XCoordinate DEC Platform6XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESStartPlatforms56DissolveVisuals LDA #$00 STA Platform56PaletteWidth STA Platform56GfxLo LDA #$01 STA PlatformDissolveAnimationFlag2 STA PlatformDissolveAnimationFlag3 LDA #$90 STA PlatformDissolveAnimationXCoord2 LDA #$02 STA PlatformDissolveAnimationXCoord3 LDA #$39 STA PlatformDissolveAnimationYCoord2 STA PlatformDissolveAnimationYCoord3 LDA #$02 JMP ESScheduleNextRoutine ESUpdatePlatforms56DissolveParticles INC PlatformDissolveAnimationXCoord2 DEC PlatformDissolveAnimationXCoord3 INC PlatformDissolveAnimationYCoord2 INC PlatformDissolveAnimationYCoord3 LDA #$02 JMP ESScheduleNextRoutine ESAdvancePlatforms56DissolveFrame INC PlatformDissolveAnimationFlag2 INC PlatformDissolveAnimationFlag3 LDA #$02 JMP ESScheduleNextRoutine ESShakePlatform0Left DEC Platform0XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESShakePlatform0Right INC Platform0XCoordinate LDA #$04 JMP ESScheduleNextRoutine ESStartPlatform0DissolveVisuals LDA #$00 STA Platform0PaletteWidth STA Platform0GfxLo LDA #$01 STA PlatformDissolveAnimationFlag4 STA PlatformDissolveAnimationFlag5 LDA #$39 STA PlatformDissolveAnimationXCoord4 LDA #$45 STA PlatformDissolveAnimationXCoord5 LDA #$81 STA PlatformDissolveAnimationYCoord4 STA PlatformDissolveAnimationYCoord5 LDA #$02 JMP ESScheduleNextRoutine ESUpdatePlatform0DissolveParticles INC PlatformDissolveAnimationXCoord4 DEC PlatformDissolveAnimationXCoord5 INC PlatformDissolveAnimationYCoord4 INC PlatformDissolveAnimationYCoord5 LDA #$02 JMP ESScheduleNextRoutine ESAdvancePlatform0DissolveFrame INC PlatformDissolveAnimationFlag4 INC PlatformDissolveAnimationFlag5 LDA #$02 JMP ESScheduleNextRoutine ES_StartBuzzardBaitWarningDelay LDA #$1E JMP ESScheduleNextRoutine ESShowBuzzardBaitText TXA ; save X and Y PHA TYA PHA LDA #$02 ; "buzzard bait" JSR DisplayGameMessage PLA ; restore X and Y TAY PLA TAX JMP ESCancelRoutine ES_StartEndOfWaveBonusDisplayTimer LDA #$46 JMP ESScheduleNextRoutine ESTransitionToNextLevel LDA PterryState1 ORA PterryState2 ORA PterryState3 BEQ NoPterrysAlive2 JSR SetAnyPterrysToLeaving DEC ESRoutineIndex,X ; Change event to the event above this one LDA #$05 JMP ESScheduleNextRoutine NoPterrysAlive2 TXA PHA TYA PHA JSR DisplayLevelStartMsg PLA TAY PLA TAX JMP ESCancelRoutine ESSetupBridgeBurning LDA #$1E STA BridgeBurningWidth LDA #$05 ; schedule flame sprite frame animation STA ESRoutineIndex+8 LDA #$1E STA $6E LDA #$14 LDY #$00 JMP ESScheduleNextRoutine ESAnimateBridgeBurning INC BridgeBurningWidth DEC $6E BMI ESAnimateBridgeBurningChangeState INC BridgeLeftGfxByte1 INC BridgeLeftGfxByte3 INC BridgeLeftGfxByte2 DEC BridgeRightGfxByte1 DEC BridgeRightGfxByte3 DEC BridgeRightGfxByte2 ESBridgeAnimationScheduleNextFrame DEC ESRoutineIndex,X LDA #$0F JMP ESScheduleNextRoutine ESAnimateBridgeBurningChangeState LDA #$10 STA $6E LDA #$0F JMP ESScheduleNextRoutine ESAnimateBridgeReforming DEC $6E BMI FinishBridgeReforming DEC BridgeLeftGfxByte1 DEC BridgeLeftGfxByte3 INC BridgeRightGfxByte1 INC BridgeRightGfxByte3 JMP ESBridgeAnimationScheduleNextFrame FinishBridgeReforming JMP ESCancelRoutine TopFlameAnimationGfxLoLUT .byte $3A, $38, $36, $2E, $2C, $2A, $28, $26 .byte $24, $22, $20, $34, $32, $30, $2E, $2C .byte $2A, $28, $26, $24, $22, $20 BottomFlameAnimationGfxLoLUT .byte $56, $54, $52, $4A, $48, $46, $44, $42 .byte $40, $3E, $3C, $50, $4E, $4C, $4A, $48 .byte $46, $44, $42, $40, $3E, $3C ESSetupFlameAnimation ; event index $05 LDA #$15 STA LeftFlameAnimationIndex LDA #$06 STA RightFlameAnimationIndex LDA #$01 JMP ESScheduleNextRoutine ESDoFlameAnimation ; event index $06 LDY LeftFlameAnimationIndex LDA TopFlameAnimationGfxLoLUT,Y STA $1F50 LDA BottomFlameAnimationGfxLoLUT,Y STA $1FA6 LDY RightFlameAnimationIndex LDA TopFlameAnimationGfxLoLUT,Y STA $1F4C LDA BottomFlameAnimationGfxLoLUT,Y STA $1FA2 DEC LeftFlameAnimationIndex BPL SkipWrapFixLeftFlameIndex LDA #$15 STA LeftFlameAnimationIndex SkipWrapFixLeftFlameIndex DEC RightFlameAnimationIndex BPL SkipWrapFixRightFlameIndex LDA #$15 STA RightFlameAnimationIndex SkipWrapFixRightFlameIndex LDA #$01 DEC ESRoutineIndex,X JMP ESScheduleNextRoutine ESWave1StartRoutines ; event index $0A LDA #$06 SetValueThenESScheduleNextRoutine STA ESTemp6ELavaRiseCounter LDA #$0F JMP ESScheduleNextRoutine ESWave2StartRoutines LDA #$FF STA $1FC4 LDA #$7C STA $1FC8 LDA #$06 JMP SetValueThenESScheduleNextRoutine ESWave3StartRoutines LDA #$FF STA $1FB1 LDA #$7C STA $1FAD LDA #$02 JMP SetValueThenESScheduleNextRoutine ESRaiseLavaWave1 DEC LeftLavaLevelWave1 DEC RightLavaLevelWave1 DEC ESTemp6ELavaRiseCounter BMI DoneRisingLavaWave1 ScheduleThisRoutineAgainAfterDelay LDA #$0F ; Number of ticks to wait before running. DEC ESRoutineIndex,X ; Decrement this timer so the "next" JMP ESScheduleNextRoutine ; routine is this one again. DoneRisingLavaWave1 LDA #$01 STA ESRoutineIndex+3 STA ESRoutineIndex+4 JMP ESCancelRoutine ; We're done ESRaiseLavaWave2 DEC LeftLavaLevelWave2 DEC RightLavaLevelWave2 DEC ESTemp6ELavaRiseCounter BMI DoneRisingLavaWave2 JMP ScheduleThisRoutineAgainAfterDelay DoneRisingLavaWave2 LDA #$01 STA ESRoutineIndex+1 STA ESRoutineIndex+2 JMP ESCancelRoutine ESRaiseLavaWave3 DEC LeftLavaLevelWave3 DEC RightLavaLevelWave3 DEC ESTemp6ELavaRiseCounter BMI DoneRisingLavaWave3 JMP ScheduleThisRoutineAgainAfterDelay DoneRisingLavaWave3 LDA #$01 STA ESRoutineIndex LDA #$07 ; Schedule the ESSetupBridgeBurning routine STA ESRoutineIndex+7 ; in 8th slot. (8th slot significance unknown) JMP ESCancelRoutine ESSetPointedValueFromRandom JSR ES_LoadLavaSparkleGfxPtr JSR ReturnRandInA ClampRandomValueLoop CMP #$20 BCC StoreRandomValueAndScheduleNext CMP #$79 BCC ContinueClampingRandomValue CMP #$99 BCC StoreRandomValueAndScheduleNext ContinueClampingRandomValue SBC #$3B JMP ClampRandomValueLoop StoreRandomValueAndScheduleNext LDY #$03 STA (TempPoint5ACurrentESRoutineLo),Y LDA #$08 JMP ESScheduleNextRoutine ES_AdvanceLavaSparkleFrame JSR ES_LoadLavaSparkleGfxPtr LDY #$00 LDA (TempPoint5ACurrentESRoutineLo),Y CLC ADC #$01 STA (TempPoint5ACurrentESRoutineLo),Y LDA #$06 JMP ESScheduleNextRoutine ES_ReverseLavaSparkleFrame JSR ES_LoadLavaSparkleGfxPtr LDY #$00 LDA (TempPoint5ACurrentESRoutineLo),Y SEC SBC #$01 STA (TempPoint5ACurrentESRoutineLo),Y CPX #$00 BNE ScheduleNextESRoutineShortDelay LDA #$B0 LDY #$03 STA (TempPoint5ACurrentESRoutineLo),Y ScheduleNextESRoutineShortDelay LDA #$05 JMP ESScheduleNextRoutine ES_LoadLavaSparkleGfxPtr LDA ES_LavaSparkleAnimationPtrLoLUT,X STA TempPoint5ACurrentESRoutineLo LDA ES_LavaSparkleAnimationPtrHiLUT,X STA TempPoint5ACurrentESRoutineHi RTS ES_SetRandomLavaSparkleFrameAndCancel JSR ES_LoadLavaSparkleGfxPtr LDA #$B0 LDY #$03 STA (TempPoint5ACurrentESRoutineLo),Y LDA #$00 STA ESRoutineIndex,X JSR ReturnRandInA AND #$1F JMP ESScheduleNextRoutine ;------------------------------------------------------------------------------ ; ReturnRandInA ; A simple pseudo-random number generator. ; It uses an incrementing seed to read 4 bytes from ROM code space ($B0xx) and ; adds them together. ; Returns: A = random byte. Preserves Y. ;------------------------------------------------------------------------------ ReturnRandInA TYA PHA INC IncrementingRandSeed LDA IncrementingRandSeed STA Temp68 LDA #$B0 STA Temp69 LDY #$03 RandLoop ADC ($68),Y DEY BPL RandLoop STA Temp68 PLA TAY LDA Temp68 RTS ;------------------------------------------------------------------------------ ; TrollAiLogic ; Manages the troll that lives in the lava. If conditions are right, it will ; jump out to grab a bird and pull it into the lava. ;------------------------------------------------------------------------------ TrollAiLogic LDA Level CMP #$03 ; Troll only appears on level 3 and higher BMI TrollTargetSearchFailed LDA Difficulty BEQ TrollTargetSearchFailed ; Troll does not appear on Beginner difficulty LDA TrollState BEQ SearchForTrollTarget ; 0=troll hiding in lava BMI TrollInAirProcessing ; ff=troll jumping at bird CMP #$01 BNE ProcessTrollState ; 02=troll holding a bird JMP TrollHoldingBirdUpdateState ProcessTrollState JMP TrollIsRetreating SearchForTrollTarget LDX #$09 SearchForTrollTargetLoop LDA GameObjectYCoordHi,X CMP TrollMinimumTargetYCoord BCC TrollTargetSearch_CheckNextObject LDA GameObjectState,X CMP #$04 BNE TrollTargetSearch_CheckNextObject LDA GameObjectAlive,X BEQ TrollTargetSearch_CheckNextObject LDA GameObjectXCoordHi,X CMP #$33 BCC TrollTargetFound CMP #$A4 BCS TrollTargetFound TrollTargetSearch_CheckNextObject DEX BPL SearchForTrollTargetLoop TrollTargetSearchFailed RTS TrollTargetFound STX TrollTargetIndex LDA #$B6 STA TrollYCoord Troll_StartJump LDA GameObjectXCoordHi,X STA TrollXCoord LDA #$FF ; troll is jumping at a bird STA TrollState LDA #SFX_TrollJumping JSR ScheduleSFX SetTrollGrabGfxFrame LDA ObjectGrabYOffsetLUT,X CLC ADC GameObjectYCoordHi,X SEC SBC TrollYCoord BPL SelectTrollJumpFrameByDistance EOR #$FF CLC ADC #$01 SelectTrollJumpFrameByDistance CMP #$03 BCS TrollGfxSelectMediumDistanceFrame LDA #$06 JMP TrollGfxFrameUpdate TrollGfxSelectMediumDistanceFrame CMP #$06 BCS TrollGfxSelectFarDistanceFrame LDA #$04 JMP TrollGfxFrameUpdate TrollGfxSelectFarDistanceFrame CMP #$09 BCS TrollGfxSetDefaultOrRetreat LDA #$02 JMP TrollGfxFrameUpdate TrollGfxSetDefaultOrRetreat LDA #$00 TrollGfxFrameUpdate STA TrollGfxOffset RTS TrollInAirProcessing ; Troll is in the air, check if it should grab the bird or retreat LDX TrollTargetIndex LDA GameObjectState,X CMP #$04 BNE TrollTargetInvalid LDA GameObjectAlive,X BEQ TrollTargetInvalid LDA GameObjectYCoordHi,X CMP TrollMinimumTargetYCoord BCC TrollTargetInvalid LDY GameObjectXCoordHi,X CPY #$33 BCC TrollTargetStillValid CPY #$A4 BCS TrollTargetStillValid TrollTargetInvalid ; troll retreats LDA #$02 STA TrollState BPL SetTrollGrabGfxFrame TrollTargetStillValid ; Target is still valid, continue moving towards it STY TrollXCoord CLC ADC ObjectGrabYOffsetLUT,X CMP TrollYCoord BCS TrollGrabbedBirdCheckGrabHeight LDA TrollYCoord CMP TrollMinimumGrabYCoord BCC TrollContinuesJump DEC TrollYCoord TrollContinuesJump JMP SetTrollGrabGfxFrame TrollHoldingBirdUpdateState LDX TrollTargetIndex LDA GameObjectState,X CMP #$04 ; alive BEQ TrollHoldingBirdUpdateGrabPosition LDA GameObjectAlive,X BEQ TrollTargetInvalid TrollHoldingBirdUpdateGrabPosition LDA GameObjectYCoordHi,X CLC ADC ObjectGrabYOffsetLUT,X TrollGrabbedBirdCheckGrabHeight CMP TrollMinimumGrabYCoord BCS TrollGrabbedTheBird JMP Troll_StartJump TrollGrabbedTheBird STA TrollYCoord LDA #$00 STA GameObjectXVelocity,X LDA GameObjectYVelocityLo,X CLC ADC TrollPullingVelocity STA GameObjectYVelocityLo,X LDA GameObjectYVelocityHi,X ADC #$00 STA GameObjectYVelocityHi,X LDA TrollXCoord STA GameObjectXCoordHi,X JMP SetTrollGrabGfxFrame TrollIsRetreating INC TrollYCoord LDA TrollYCoord CMP #$B6 BCC TrollUpdateRetreatingFrame LDA #$00 STA TrollState ; troll in lava (default) STA TrollYCoord TrollUpdateRetreatingFrame JMP TrollGfxSetDefaultOrRetreat ObjectGrabYOffsetLUT ; bird objects only .byte $0A, $0C, $0A, $0A, $0A, $0A, $0A, $0A, $0A, $0A ;------------------------------------------------------------------------------ ; Platform Collision Detection Routines ; These routines check for collisions between a game object and the platforms. ;------------------------------------------------------------------------------ CheckPlatformCollision LDA GameObjectXCoordHi,X STA Temp5E LDA GameObjectYCoordHi,X STA Temp5F STY Temp68 LDY Temp69 LDA PlatformCollisionCheckPointXLUT,Y CLC ADC Temp5E STA Temp62 LDA PlatformCollisionCheckPointYLUT,Y CLC ADC Temp5F STA Temp61 LDA PlatformPresentBitmask STA Temp63 LDY #$06 CheckCollisionAgainstEachPlatformLoop LSR Temp63 BCS CheckCollisionWithPresentPlatform CollisionCheckNextPlatform DEY BPL CheckCollisionAgainstEachPlatformLoop JMP CheckCollisionWithLavaBridge CheckCollisionWithPresentPlatform LDA Temp61 CMP PlatformYTop,Y BCS PlatformCollisionCheckYBottomAndXBounds JMP PlatformCollisionNoHitReturnZero PlatformCollisionCheckYBottomAndXBounds LDA Temp5F CMP PlatformYBottom,Y BCS CollisionCheckNextPlatform LDA Temp62 CMP PlatformXLeftEdge,Y BEQ CollisionCheckNextPlatform BCC CollisionCheckNextPlatform LDA Temp5E CMP PlatformXRightEdge,Y BCS CollisionCheckNextPlatform LDA Temp61 CLC ADC #$04 LSR LSR LSR STA Temp60 LDA Temp62 SEC SBC PlatformXLeftBounce,Y BMI InitializeRightSideCollisionCheck SEC SBC Temp60 BCS HandleLeftSidePlatformCollision JMP CollisionCheckNextPlatform HandleLeftSidePlatformCollision ADC #$00 STA TempCollisionOverlap LDA #$01 STA Temp64 LDA Temp5E SEC SBC TempCollisionOverlap STA Temp65 LDA Temp5F STA Temp66 JMP ContinueRightSideCollisionCheck InitializeRightSideCollisionCheck LDA #$64 STA TempCollisionOverlap ContinueRightSideCollisionCheck LDA PlatformXRightBounce,Y SEC SBC Temp5E BMI ContinueCollisionCheckWithYAxis SEC SBC Temp60 BCS UpdateClosestRightSideCollision JMP CollisionCheckNextPlatform UpdateClosestRightSideCollision ADC #$00 CMP TempCollisionOverlap BCS ContinueCollisionCheckWithYAxis STA TempCollisionOverlap CLC ADC Temp5E STA Temp65 LDA Temp5F STA Temp66 LDA #$08 STA Temp64 ContinueCollisionCheckWithYAxis LDA Temp5F SEC SBC PlatformYBottomForBounceCheckLUT,Y BMI CheckPlatformTopCollision STA Temp60 LDA Temp62 CLC ADC #$02 LSR LSR SEC SBC Temp60 BCS UpdateClosestBottomSideCollision JMP CollisionCheckNextPlatform UpdateClosestBottomSideCollision ADC #$00 CMP TempCollisionOverlap BCS CheckPlatformTopCollision STA TempCollisionOverlap CLC ADC Temp5F STA Temp66 LDA Temp5E STA Temp65 LDA #$02 STA Temp64 CheckPlatformTopCollision LDA Temp5E CLC ADC #$02 LSR LSR STA Temp60 LDA PlatformYTopForBounceCheckLUT,Y SEC SBC Temp5F BMI SkipUpdatingClosestCollision SEC SBC Temp60 BCS UpdateClosestBottomPlatformCollision JMP CollisionCheckNextPlatform UpdateClosestBottomPlatformCollision ADC #$00 CMP TempCollisionOverlap BCS SkipUpdatingClosestCollision STA TempCollisionOverlap CLC ADC Temp5F STA Temp66 LDA Temp5E STA Temp65 LDA #$04 STA Temp64 SkipUpdatingClosestCollision LDA Temp61 SEC SBC PlatformYTop,Y CLC ADC #$02 CMP TempCollisionOverlap BEQ UpdateClosestCollisionPoint BCC UpdateClosestCollisionPoint JMP FinalizePlatformCollisionCheck UpdateClosestCollisionPoint STA TempCollisionOverlap LDA Temp62 SEC SBC #$03 CMP PlatformXLeftEdge,Y BCS FinalizeTopPlatformCollision JMP CollisionCheckNextPlatform FinalizeTopPlatformCollision LDA PlatformXRightEdge,Y SEC SBC #$03 CMP Temp5E BCS HandlePlatformTopCollision JMP CollisionCheckNextPlatform HandlePlatformTopCollision LDA #$FF STA Temp64 LDA Temp5E STA Temp65 LDA Temp5F SEC SBC TempCollisionOverlap STA Temp66 INC Temp66 JMP FinalizePlatformCollisionCheck CheckCollisionWithLavaBridge LDA Temp61 SEC SBC #$AF BMI PlatformCollisionNoHitReturnZero STA Temp60 LDA Temp62 SEC SBC BridgeBurningWidth STA TempCollisionOverlap INC TempCollisionOverlap LDA #$01 STA Temp64 LDA Temp5E SEC SBC TempCollisionOverlap STA Temp65 LDA Temp5F STA Temp66 LDA #$E0 SEC SBC BridgeBurningWidth SEC SBC Temp5E CMP TempCollisionOverlap BCS PrioritizeLavaBridgeHorizontalCollision STA TempCollisionOverlap INC TempCollisionOverlap LDA #$08 STA Temp64 LDA Temp5E CLC ADC TempCollisionOverlap STA Temp65 LDA Temp5F STA Temp66 PrioritizeLavaBridgeHorizontalCollision LDA Temp60 CMP TempCollisionOverlap BCS FinalizePlatformCollisionCheck LDA Temp62 SEC SBC #$03 CMP BridgeBurningWidth BCS CheckLavaBridgeXBounds JMP PlatformCollisionNoHitReturnZero CheckLavaBridgeXBounds LDA #$E0 SEC SBC BridgeBurningWidth SEC SBC #$03 CMP Temp5E BCS HandleLavaBridgeTopCollision JMP PlatformCollisionNoHitReturnZero HandleLavaBridgeTopCollision LDA #$FF STA Temp64 LDA Temp5E STA Temp65 LDA Temp5F SEC SBC Temp60 STA Temp66 FinalizePlatformCollisionCheck LDY Temp68 LDA Temp64 RTS PlatformCollisionNoHitReturnZero LDY Temp68 LDA #$00 RTS SelectEggCollisionPointAndCheck LDA #$04 STA Temp69 JMP CheckPlatformCollision SelectCollisionPointsAndCheckPlatform LDA GameObjectSkidDirection,X BNE SelectCollisionPointsForSkiddingBird LDA #$00 STA Temp69 JMP CheckPlatformCollision SelectCollisionPointsForSkiddingBird LDA #$0A STA Temp69 JMP CheckPlatformCollision CheckForShallowPlatformCollision LDA GameObjectXCoordHi,X CMP #$B0 BCS FallbackToStandardCollisionCheck CMP #$AA BEQ FallbackToStandardCollisionCheck BCC FallbackToStandardCollisionCheck LDA GameObjectYCoordHi,X CMP #$66 BCS FallbackToStandardCollisionCheck CMP #$62 BCC FallbackToStandardCollisionCheck LDA GameObjectXVelocity,X BPL FallbackToStandardCollisionCheck LDA #$AA STA Temp65 LDA #$73 STA Temp66 LDA #$02 RTS FallbackToStandardCollisionCheck CPX #$01 BNE SelectCollisionPointForOtherBirds LDA #$08 STA Temp69 JMP CheckPlatformCollision SelectCollisionPointForOtherBirds LDA #$02 STA Temp69 JMP CheckPlatformCollision CheckPterryPlatformCollision LDA GameObjectXCoordHi,X CMP #$AD BCS SelectCollisionPointsForPterry CMP #$AA BCC SelectCollisionPointsForPterry LDA GameObjectYCoordHi,X CMP #$67 BCS SelectCollisionPointsForPterry CMP #$62 BCC SelectCollisionPointsForPterry LDA GameObjectXVelocity,X BPL SelectCollisionPointsForPterry LDA #$AA STA Temp65 LDA #$73 STA Temp66 LDA #$02 RTS SelectCollisionPointsForPterry LDA #$06 STA Temp69 JMP CheckPlatformCollision CheckIfEggSlippingOffPlatform STY Temp64 LDY #$04 JMP PerformPlatformEdgeCheck CheckIfBirdNearPlatformEdge STY Temp64 LDA GameObjectSkidDirection,X BNE SelectCollisionPointForSkiddingBird LDY #$00 JMP PerformPlatformEdgeCheck SelectCollisionPointForSkiddingBird LDY #$0A PerformPlatformEdgeCheck LDA GameObjectXCoordHi,X STA Temp5E LDA GameObjectYCoordHi,X STA Temp5F LDA #$00 STA Temp60 LDA PlatformCollisionCheckPointYLUT,Y CLC ADC Temp5F STA Temp61 INC Temp61 LDA PlatformCollisionCheckPointXLUT,Y CLC ADC Temp5E STA Temp62 LDA PlatformPresentBitmask STA Temp63 LDY #$06 PlatformEdgeCheckLoop LSR Temp63 BCC CheckNextPlatformForEdge LDA Temp61 CMP PlatformYTop,Y BEQ ConfirmBirdIsOnPlatform BCS CheckNextPlatformForEdge JMP FinishPlatformEdgeCheck ConfirmBirdIsOnPlatform LDA Temp62 SEC SBC #$03 CMP PlatformXLeftEdge,Y BCC CheckNextPlatformForEdge LDA PlatformXRightEdge,Y SEC SBC #$03 CMP Temp5E BCC CheckNextPlatformForEdge JMP PlatformEdgeCheckOnPlatformReturnTrue CheckNextPlatformForEdge DEY BPL PlatformEdgeCheckLoop LDA Temp61 CMP #$B0 BNE FinishPlatformEdgeCheck LDA #$E0 SEC SBC BridgeBurningWidth CMP Temp5E BEQ FinishPlatformEdgeCheck BCC FinishPlatformEdgeCheck LDA Temp62 CMP BridgeBurningWidth BEQ FinishPlatformEdgeCheck BCC FinishPlatformEdgeCheck LDA #$E0 SEC SBC BridgeBurningWidth CMP Temp5E BEQ FinishPlatformEdgeCheck BCC FinishPlatformEdgeCheck PlatformEdgeCheckOnPlatformReturnTrue LDA #$01 STA Temp60 FinishPlatformEdgeCheck LDY Temp64 RTS ; Pairs of coordinates used for platform collision checks PlatformCollisionCheckPointXLUT .byte $08 PlatformCollisionCheckPointYLUT .byte $0F .byte $08,$0A .byte $04,$05 .byte $10,$09 .byte $08,$0C .byte $08,$0E PlatformXLeftEdge .byte $57,$AB,$18,$8D,$4E,$18,$A8 PlatformXRightEdge .byte $7B,$CD,$44,$AE,$7D,$33,$C4 PlatformYTop .byte $80,$70,$70,$68,$40,$38,$38 PlatformYBottom .byte $86,$77,$76,$72,$46,$3E,$3E PlatformXLeftBounce ; used to start low-approacing bird bouncing .byte $47,$9D,$0A,$80,$46,$11,$A1 PlatformYBottomForBounceCheckLUT .byte $6D,$4A,$6A,$47,$2D,$34,$11 PlatformYTopForBounceCheckLUT .byte $9F,$A4,$82,$9D,$5F,$48,$6B PlatformXRightBounce ; used to start low-approacing bird bouncing .byte $8B,$DB,$52,$BB,$85,$3A,$CB ; Platform information tables used by riderless bird figuring out which ; direction to start with to get to it's hatched rider. PlatformTopCoordinate .byte $32,$3A,$62,$6A,$7A,$AA,$AA PlatformLeftsideCoordinate .byte $A8,$4E,$8D,$AB,$4D,$3C,$A4 PlatformRightsideCoordinate .byte $C0,$65,$9D,$C0,$89,$70,$C0 ; Doesn't seem to be referenced during play, even indirectly. UnusedPterrySpawnYCoordLUT .byte $15,$52,$52,$52,$52,$94,$94 ; Data for random egg placement during Egg Waves NewEggXMaximum .byte $10,$0B,$27,$1D,$20,$12,$20,$59 NewEggXOffset .byte $AB,$23,$51,$90,$23,$AE,$5A,$45 NewEggYCoordinate .byte $32,$32,$3A,$62,$6A,$6A,$7A,$AA ;------------------------------------------------------------------------------ ; UpdatePlayerScoreAndBonus ; Adds a score value to the current player's score and checks for extra lives. ; Input: X = player index. Temp60/61/62 = score value to add. ;------------------------------------------------------------------------------ UpdatePlayerScoreAndBonus TXA PHA TYA PHA LDA P0Lives,X BMI FinalizeScoreUpdateAndExit LDA DemoMode BNE FinalizeScoreUpdateAndExit STA Temp60 TXA BNE UpdatePlayer1Score LDY #$02 SED CLC AddScoreToPlayer0Loop LDA.w Temp60,Y ADC.w P0Score,Y STA.w P0Score,Y DEY BPL AddScoreToPlayer0Loop TXA JSR CheckForPlayer0BonusLife JMP FinalizeScoreUpdateAndExit UpdatePlayer1Score LDY #$02 SED CLC AddScoreToPlayer1Loop LDA.w Temp60,Y ADC.w P1Score,Y STA.w P1Score,Y DEY BPL AddScoreToPlayer1Loop TXA JSR CheckForPlayer1BonusLife FinalizeScoreUpdateAndExit JSR UpdateScoreDisplay PLA TAY PLA TAX RTS CheckForPlayer0BonusLife LDY #$01 CLC AddScoreToBonusLifeCounterLoop: LDA.w Temp61,Y ADC.w P0ExtraLifeScore,Y STA.w P0ExtraLifeScore,Y DEY BPL AddScoreToBonusLifeCounterLoop CLD LDA P0ExtraLifeScore BMI NoBonusLifeAwarded SEC SBC #$80 STA P0ExtraLifeScore JMP AwardBonusLife NoBonusLifeAwarded RTS CheckForPlayer1BonusLife LDY #$01 CLC AddScoreToP1BonusLifeCounterLoop LDA.w Temp61,Y ADC.w P1ExtraLifeScore,Y STA.w P1ExtraLifeScore,Y DEY BPL AddScoreToP1BonusLifeCounterLoop CLD LDA P1ExtraLifeScore BMI NoBonusLifeAwarded SEC SBC #$80 STA P1ExtraLifeScore JMP AwardBonusLife ;------------------------------------------------------------------------------ ; InitPlayerLivesAndBonus ; Initializes lives and bonus score thresholds at the start of a game. ;------------------------------------------------------------------------------ InitPlayerLivesAndBonus ; Initializes the lives and bonus score for one or both players LDA #$FF STA P1Lives LDA #$04 STA P0Lives LDX PlayerCount BEQ InitPlayerLivesDone ; leave P1Lives=FF for one player mode STA P1Lives InitPlayerLivesDone LDA #$80 STA P0ExtraLifeScore STA P1ExtraLifeScore ASL STA P0ExtraLifeScore+1 STA P1ExtraLifeScore+1 EarlyReturn3 RTS ;------------------------------------------------------------------------------ ; DeadPlayerChecks ; Handles the logic when a player dies: decrements lives, checks for game over. ; Input: X = player index ;------------------------------------------------------------------------------ DeadPlayerChecks LDA #$00 STA LevelWasSurvived ; No survival points if you die. STA P0EggPointLevel,X DEC P0Lives,X ; Lose a life and return LDA P0Lives,X ; only if you have more. BPL EarlyReturn3 LDA P0Lives ; when both player lives are zero, we skip EOR P1Lives ; over player death notifications, and BEQ SkipPlayerGameOverMsg ; instead display "thy game is over" LDA DemoMode BNE EarlyReturn3 TXA CLC ADC #$08 ; game message 8="player one", 9="player two" JSR DisplayGameMessage LDA #$0A ; "game over" JMP DisplayGameMessage SkipPlayerGameOverMsg LDA DemoMode BNE EarlyReturn3 LDA #$01 STA GameActiveFlag LDA #$0B ; "thy game is over" JMP DisplayGameMessage AwardBonusLife LDA P0Lives,X CMP #$7F ; Maximum lives is $7F BEQ ScheduleFreeBirdSound INC P0Lives,X JSR UpdatePlayerLivesDisplayed ScheduleFreeBirdSound LDA #SFX_FreeBird JMP ScheduleSFX UpdateScoreDisplay LDA #$00 STA Temp5E TAX UpdateScoreDisplayP0HandleLeadingZeros LDA P0Score,X LSR LSR LSR LSR BNE UpdateScoreDisplayP0ProcessDigit JSR AddSpaceToScoreHudString LDA P0Score,X AND #$0F BNE UpdateScoreDisplayP0ProcessUnitsDigit JSR AddSpaceToScoreHudString INX CPX #$03 BMI UpdateScoreDisplayP0HandleLeadingZeros JMP FinalizeP0ScoreDisplay UpdateScoreDisplayP0Loop LDA P0Score,X LSR LSR LSR LSR UpdateScoreDisplayP0ProcessDigit CLC ADC #$01 JSR AddCharToScoreHudString LDA P0Score,X AND #$0F UpdateScoreDisplayP0ProcessUnitsDigit CLC ADC #$01 JSR AddCharToScoreHudString INX CPX #$03 BMI UpdateScoreDisplayP0Loop FinalizeP0ScoreDisplay LDA #$01 JSR AddCharToScoreHudString LDA PlayerCount BNE UpdatePlayer1ScoreDisplay RTS UpdatePlayer1ScoreDisplay LDA #$0D STA Temp5E LDX #$00 UpdateScoreDisplayP1HandleLeadingZeros LDA P1Score,X LSR LSR LSR LSR BNE UpdateScoreDisplayP1ProcessDigit JSR AddSpaceToScoreHudString LDA P1Score,X AND #$0F BNE UpdateScoreDisplayP1ProcessUnitsDigit JSR AddSpaceToScoreHudString INX CPX #$03 BMI UpdateScoreDisplayP1HandleLeadingZeros BPL FinalizeP1ScoreDisplay UpdateScoreDisplayP1Loop LDA P1Score,X LSR LSR LSR LSR UpdateScoreDisplayP1ProcessDigit CLC ADC #$0C JSR AddCharToScoreHudString LDA P1Score,X AND #$0F UpdateScoreDisplayP1ProcessUnitsDigit CLC ADC #$0C JSR AddCharToScoreHudString INX CPX #$03 BMI UpdateScoreDisplayP1Loop FinalizeP1ScoreDisplay LDA #$0C BNE AddCharToScoreHudString UpdatePlayerLivesDisplayed TXA PHA TYA PHA LDA DemoMode BNE UpdatePlayerLivesExit LDA HudPlayerLivesStartXOffsetLUT,X STA Temp5E LDY #$03 DrawPlayerLivesLoop TYA CMP P0Lives,X BPL DrawEmptyLifeSlot LDA HudPlayerLifeIconCharLUT,X JSR AddCharToScoreHudString JMP UpdatePlayerLivesContinueLoop DrawEmptyLifeSlot JSR AddSpaceToScoreHudString UpdatePlayerLivesContinueLoop DEY BPL DrawPlayerLivesLoop UpdatePlayerLivesExit PLA TAY PLA TAX RTS HudPlayerLifeIconCharLUT .byte $0B,$16 ; Character codes for P0 and P1 life icons HudPlayerLivesStartXOffsetLUT .byte $07,$14 ; Start offsets in HUD buffer for P0 and P1 lives AddSpaceToScoreHudString LDA #$00 ; character index for space AddCharToScoreHudString STY Temp5F LDY Temp5E STA HudDisplayStringBuffer,Y LDY Temp5F INC Temp5E RTS ;------------------------------------------------------------------------------ ; DisplayGameMessage ; Schedules a message to be displayed on screen. ; Input: A = message index ;------------------------------------------------------------------------------ DisplayGameMessage STA Temp69 TXA PHA TYA PHA LDA Temp69 TAX LDY MessageLineNumber,X LDA Temp69 STA $2038,Y PLA TAY PLA TAX RTS ;------------------------------------------------------------------------------ ; ManageMessageTimers ; Manages the timers for on-screen messages, clearing them when they expire. ;------------------------------------------------------------------------------ ManageMessageTimers LDX #$03 UpdateMessageDisplayTimers LDA $2038,X BMI ManageMessageTimersCheckNextLine LDA MessageLine0Timer,X BPL ManageMessageTimersCheckNextLine LDA $2038,X JSR DisplayMessageAndSetTimer LDA #$FF STA $2038,X ManageMessageTimersCheckNextLine DEX BPL UpdateMessageDisplayTimers LDX #$03 ClearExpiredMessageTimersLoop: LDA MessageLine0Timer,X CMP #$FF BEQ CheckNextMessageTimer LDA MessageLine0Timer,X BMI CheckNextMessageTimer DEC MessageLine0Timer,X BNE CheckNextMessageTimer LDA MsgBufferLo,X STA TempPointLo5A LDA MsgBufferHi,X STA TempPointHi5B LDY #$0F LDA #$00 ClearMessageBufferLoop STA (TempPointLo5A),Y DEY BPL ClearMessageBufferLoop CheckNextMessageTimer DEX BPL ClearExpiredMessageTimersLoop RTS DisplayMessageAndSetTimer STA Temp69 TXA PHA TYA PHA LDX Temp69 LDA MessageLineNumber,X TAX LDY Temp69 LDA MessageDisplayTime,Y STA MessageLine0Timer,X JSR UpdateDLWithMessageString LDA Temp69 BNE FinishDisplayingMessage TAX TAY JSR UpdateDLWithMessageString LDA LevelBCD LSR LSR LSR LSR BEQ DisplayWaveNumberProcessUnitsDigit CLC ADC #$0C STA HudWaveNumberDigit1 DisplayWaveNumberProcessUnitsDigit LDA LevelBCD AND #$0F CLC ADC #$0C STA HudWaveNumberDigit2 FinishDisplayingMessage PLA TAY PLA TAX RTS UpdateDLWithMessageString LDA MsgBufferLo,X STA TempPointLo5A LDA MsgBufferHi,X STA TempPointHi5B TYA ASL ASL ASL ASL ; A = Y * 16 PHP CLC ADC #<GameMessages STA Temp5E BCC AddHiByteWithNoCarry LDA #$01 BNE FinalizeMessagePointerHiByte AddHiByteWithNoCarry LDA #$00 FinalizeMessagePointerHiByte PLP ADC #>GameMessages STA Temp5F LDY #$0F CopyMessageStringToBufferLoop LDA (Temp5E),Y CLC ADC #$00 STA (TempPointLo5A),Y DEY BPL CopyMessageStringToBufferLoop RTS MessageLineNumber .byte 0,2,3,1,1,1,1,1,2,2,3,2,1,1,1,2,1,1,1 MessageDisplayTime .byte $3C, $46, $28, $3C, $3C, $3C, $3C, $3C .byte $3C, $3C, $3C, $F0, $3C, $3C, $3C, $3C .byte $3C, $3C, $3C MsgBufferLo .byte <$2671 .byte <$2685 .byte <$2699 .byte <$26AD MsgBufferHi .byte >$2671 .byte >$2685 .byte >$2699 .byte >$26AD GameMessages .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 ; "WAVE" .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 ; "PREPARE TO JOUST" .byte $23 ; 'P' .byte $24 ; 'R' .byte $1B ; 'E' .byte $23 ; 'P' .byte $17 ; 'A' .byte $24 ; 'R' .byte $1B ; 'E' .byte $00 .byte $26 ; 'T' .byte $0C ; '0' .byte $00 .byte $1F ; 'J' .byte $0C ; '0' .byte $27 ; 'U' .byte $25 ; 'S' .byte $26 ; 'T' .byte $00 .byte $00 ; "BUZZARD BAIT" .byte $18 ; 'B' .byte $27 ; 'U' .byte $2C ; 'Z' .byte $2C ; 'Z' .byte $17 ; 'A' .byte $24 ; 'R' .byte $1A ; 'D' .byte $00 .byte $18 ; 'B' .byte $17 ; 'A' .byte $1E ; 'I' .byte $26 ; 'T' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 ; "EGG WAVE" .byte $1B ; 'E' .byte $1C ; 'G' .byte $1C ; 'G' .byte $00 .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $1C ; 'G' .byte $20 ; 'L' .byte $17 ; 'A' .byte $1A ; 'D' .byte $1E ; 'I' .byte $17 ; 'A' .byte $26 ; 'T' .byte $0C ; 'O' .byte $24 ; 'R' .byte $00 .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $23 ; 'P' .byte $26 ; 'T' .byte $1B ; 'E' .byte $24 ; 'R' .byte $24 ; 'R' .byte $2B ; 'Y' .byte $00 .byte $00 .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $25 ; 'S' .byte $27 ; 'U' .byte $24 ; 'R' .byte $28 ; 'V' .byte $1E ; 'I' .byte $28 ; 'V' .byte $17 ; 'A' .byte $20 ; 'L' .byte $00 .byte $00 .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $00 .byte $26 ; 'T' .byte $1B ; 'E' .byte $17 ; 'A' .byte $21 ; 'M' .byte $00 .byte $00 .byte $29 ; 'W' .byte $17 ; 'A' .byte $28 ; 'V' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $23 ; 'P' .byte $20 ; 'L' .byte $17 ; 'A' .byte $2B ; 'Y' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $0D ; '1' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $23 ; 'P' .byte $20 ; 'L' .byte $17 ; 'A' .byte $2B ; 'Y' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $0E ; '2' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $1C ; 'G' .byte $17 ; 'A' .byte $21 ; 'M' .byte $1B ; 'E' .byte $00 .byte $00 .byte $0C ; '0' .byte $28 ; 'V' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $00 .byte $26 ; 'T' .byte $1D ; 'H' .byte $2B ; 'Y' .byte $00 .byte $1C ; 'G' .byte $17 ; 'A' .byte $21 ; 'M' .byte $1B ; 'E' .byte $00 .byte $1E ; 'I' .byte $25 ; 'S' .byte $00 .byte $0C ; '0' .byte $28 ; 'V' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $0F ; '3' .byte $0C ; '0' .byte $0C ; '0' .byte $0C ; '0' .byte $00 .byte $00 .byte $25 ; 'S' .byte $27 ; 'U' .byte $24 ; 'R' .byte $28 ; 'V' .byte $1E ; 'I' .byte $28 ; 'V' .byte $17 ; 'A' .byte $20 ; 'L' .byte $00 .byte $00 .byte $00 .byte $00 .byte $0F ; '3' .byte $0C ; '0' .byte $0C ; '0' .byte $0C ; '0' .byte $00 ; .byte $00 ; .byte $26 ; 'T' .byte $1B ; 'E' .byte $17 ; 'A' .byte $21 ; 'M' .byte $00 .byte $00 .byte $00 .byte $00 .byte $0F ; '3' .byte $0C ; '0' .byte $0C ; '0' .byte $0C ; '0' .byte $00 .byte $1C ; 'G' .byte $20 ; 'L' .byte $17 ; 'A' .byte $1A ; 'D' .byte $1E ; 'I' .byte $17 ; 'A' .byte $26 ; 'T' .byte $0C ; '0' .byte $24 ; 'R' .byte $00 .byte $00 .byte $23 ; 'P' .byte $0C ; '0' .byte $1E ; 'I' .byte $22 ; 'N' .byte $26 ; 'T' .byte $25 ; 'S' .byte $00 .byte $17 ; 'A' .byte $29 ; 'W' .byte $17 ; 'A' .byte $24 ; 'R' .byte $1A ; 'D' .byte $1B ; 'E' .byte $1A ; 'D' .byte $00 .byte $00 .byte $00 .byte $22 ; 'N' .byte $0C ; '0' .byte $00 .byte $00 .byte $25 ; 'S' .byte $27 ; 'U' .byte $24 ; 'R' .byte $28 ; 'V' .byte $1E ; 'I' .byte $28 ; 'V' .byte $17 ; 'A' .byte $20 ; 'L' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $22 ; 'N' .byte $0C ; '0' .byte $00 .byte $00 .byte $26 ; 'T' .byte $1B ; 'E' .byte $17 ; 'A' .byte $21 ; 'M' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $22 ; 'N' .byte $0C ; '0' .byte $00 .byte $1C ; 'G' .byte $20 ; 'L' .byte $17 ; 'A' .byte $1A ; 'D' .byte $1E ; 'I' .byte $17 ; 'A' .byte $26 ; 'T' .byte $0C ; 'O' .byte $24 ; 'R' .byte $00 .byte $00 StringCopyright .byte $2E ; 1/2 (c) symbol .byte $2F ; 1/2 (c) symbol .byte $00 ; ' ' .byte $17 ; 'A' .byte $26 ; 'T' .byte $17 ; 'A' .byte $24 ; 'R' .byte $1E ; 'I' .byte $00 ; ' ' .byte $0D ; '1' .byte $15 ; '9' .byte $14 ; '8' .byte $10 ; '4' .byte $2E ; 1/2 (c) symbol .byte $2F ; 1/2 (c) symbol .byte $00 ; ' ' .byte $29 ; 'W' .byte $1E ; 'I' .byte $20 ; 'L' .byte $20 ; 'L' .byte $1E ; 'I' .byte $17 ; 'A' .byte $21 ; 'M' .byte $25 ; 'S' .byte $00 ; ' ' .byte $0D ; '1' .byte $15 ; '9' .byte $14 ; '8' .byte $0E ; '2' ;------------------------------------------------------------------------------ ; DisplayRoutineInit ; Initializes the working Display List pointers in RAM ($242B/$2443) ; from the master pointers in ROM. It then proceeds to build the render list ; for the current frame by processing all active game objects. ;------------------------------------------------------------------------------ DisplayRoutineInit LDX #$17 ; 24 DLs InitializeDisplayListPointers LDA DisplayListLoLUT,X STA DisplayListLo,X LDA DisplayListHiLUT,X STA DisplayListHi,X DEX BPL InitializeDisplayListPointers ; loop through all of the birds... LDY #$09 RenderBirdObjectsLoop LDA.w GameObjectState,Y BEQ RenderNextBird ; if state is dead then skip CMP #$03 ; if state is born1 BEQ RenderNextBird ; then skip JSR PrepareBirdSpriteForRenderList LDA GameObjectInAir,Y BNE RenderAirborneBirdRider JSR PrepareOnPlatformBirdSprite RenderAirborneBirdRider LDA.w GameObjectAlive,Y BEQ RenderNextBird JSR PrepareRiderOnBirdSpriteForRenderList RenderNextBird DEY BPL RenderBirdObjectsLoop ; loop through all of the pterrys... LDY #$02 RenderPterryObjectsLoop LDA.w PterryState1,Y BEQ RenderNextPterry JSR PreparePterrySpriteForRenderList RenderNextPterry DEY BPL RenderPterryObjectsLoop ; loop through all of the eggs... LDY #$0B RenderEggObjectsLoop LDA.w EggState,Y BEQ RenderNextEggObject JSR PrepareEggSpriteForRenderList RenderNextEggObject DEY BPL RenderEggObjectsLoop ; loop through all of the player birds... LDY #$01 RenderPlayerDeathExplosionLoop LDA.w P0DeathState,Y BEQ RenderNextPlayerDeathExplosion JSR PreparePlayerExplosionSpriteForRenderList RenderNextPlayerDeathExplosion DEY BPL RenderPlayerDeathExplosionLoop LDY #$05 RenderDissolvingPlatformObjectsLoop LDA PlatformDissolveAnimationFlag0,Y BEQ RenderNextDissolvingParticle JSR PrepareDissolvingPlatformParticleForRenderList RenderNextDissolvingParticle DEY BPL RenderDissolvingPlatformObjectsLoop LDA TrollState BEQ RenderTrollIfVisible ; Troll hiding in lava? JSR PrepareTrollSpriteForRenderList RenderTrollIfVisible STX RenderListCount LDA #$01 STA RenderListDirty RTS PrepareTrollSpriteForRenderList LDA TrollGfxOffset STA Temp5EGfxDataLo LDA #$A8 STA Temp5FGfxDataHi LDA #$1E STA Temp60PaletteAndWidth LDA TrollXCoord SEC SBC #$20 STA Temp61SpriteXCoord LDA #$9A STA Temp62 LDA TrollYCoord SEC SBC #$10 LDY TrollTargetIndex CPY #$01 BNE StoreTrollSpriteYCoord SBC #$02 StoreTrollSpriteYCoord STA Temp63SpriteYCoord JMP AddSpriteToRenderList PrepareDissolvingPlatformParticleForRenderList SEC SBC #$01 ASL ASL CLC ADC #$78 STA Temp5EGfxDataLo LDA #$A8 STA Temp5FGfxDataHi LDA #$1C STA Temp60PaletteAndWidth LDA PlatformDissolveAnimationXCoord0,Y STA Temp61SpriteXCoord LDA #$A1 STA Temp62 LDA PlatformDissolveAnimationYCoord0,Y SEC SBC #$10 STA Temp63SpriteYCoord JMP AddSpriteToRenderList PreparePlayerExplosionSpriteForRenderList LDA.w P0DeathState,Y SEC SBC #$01 ASL CLC ADC #$70 STA Temp5EGfxDataLo LDA #$A8 STA Temp5FGfxDataHi LDA #$7E STA Temp60PaletteAndWidth LDA.w PlayerExplosionXCoord,Y SEC SBC #$20 STA Temp61SpriteXCoord LDA #$A2 STA Temp62 LDA.w PlayerExplosionYCoord,Y SEC SBC #$10 STA Temp63SpriteYCoord JMP AddSpriteToRenderList ; This appears to be dead menu code. Apparently at one point in development ; changing menu options would update the DL with the relevant character object. ; This was abandoned for the current character-buffer update system. STY Temp65 LDA #$8F STA Temp60PaletteAndWidth LDA #$27 STA Temp61SpriteXCoord LDA UNUSED_TitleMenuTextAddrLoLUT,Y STA Temp5EGfxDataLo LDA UNUSED_TitleMenuTextAddrHiLUT,Y STA Temp5F LDA UNUSED_TitleMenuDLZoneLUT,Y TAY JSR UpdateRenderList LDY Temp65 RTS PreparePterrySpriteForRenderList LDA $2344,Y ; pterry direction BMI SetPterryBaseGfxForLeftFacing LDA #$44 JMP StorePterryBaseGfxAndContinue SetPterryBaseGfxForLeftFacing LDA #$2C StorePterryBaseGfxAndContinue STA Temp5EGfxDataLo LDA $236A,Y ; pterry animation frame ASL ASL ADC Temp5EGfxDataLo STA Temp5EGfxDataLo LDA #$A8 STA Temp5F STX Temp61 LDA $236A,Y TAX LDA PterrySpritePaletteAndWidthLUT,X STA Temp60PaletteAndWidth LDX Temp61 LDA $015E,Y SEC SBC #$20 STA Temp61SpriteXCoord LDA #$9A STA Temp62 LDA $0177,Y SEC SBC #$10 STA Temp63SpriteYCoord JMP AddSpriteToRenderList PrepareEggSpriteForRenderList CMP #$04 BEQ PrepareRiderSpriteForRenderList CMP #$03 BEQ PrepareRiderSpriteForRenderList LDA $221B,Y CLC ADC #$80 STA Temp5EGfxDataLo LDA EggX,Y SEC SBC #$20 STA Temp61SpriteXCoord LDA #$9F STA Temp60PaletteAndWidth LDA #$A8 STA Temp5FGfxDataHi LDA #$A4 STA Temp62 LDA EggY,Y SEC SBC #$0F STA Temp63SpriteYCoord JMP AddSpriteToRenderList PrepareRiderSpriteForRenderList LDA.w EggState,Y CMP #$03 BNE RenderHatchedRiderSprite LDA #$CB STA Temp5EGfxDataLo LDA #$C0 STA Temp5FGfxDataHi LDA #$9E STA Temp60PaletteAndWidth LDA EggX,Y SEC SBC #$21 STA Temp61SpriteXCoord LDA EggY,Y SEC SBC #$0C LSR LSR LSR STY TempCollisionOverlap TAY JSR UpdateRenderList LDY TempCollisionOverlap RenderHatchedRiderSprite LDA EggLevelAndType,Y ASL CLC ADC #$58 STA Temp5EGfxDataLo LDA #$C0 STA Temp5FGfxDataHi LDA #$5E STA Temp60PaletteAndWidth LDA EggX,Y SEC SBC #$20 STA Temp61SpriteXCoord LDA EggY,Y SEC SBC #$0C LSR LSR LSR STY TempCollisionOverlap TAY JSR UpdateRenderList LDY TempCollisionOverlap RTS PrepareRiderOnBirdSpriteForRenderList LDA RiderObjectPaletteAndWidth,Y STA Temp60PaletteAndWidth LDA GameObjectDirection,Y BMI SetRiderBaseGfxForLeftFacing LDA #$5E JMP StoreRiderBaseGfxAndContinue SetRiderBaseGfxForLeftFacing LDA #$5C StoreRiderBaseGfxAndContinue STA Temp5E CPY #$02 BCS CalculateEnemyRiderGfxOffset ; branch if non-player enemy bird TYA JMP CalculateFinalRiderGfxPointer CalculateEnemyRiderGfxOffset LDA ObjectBirdLevelAndType,Y CLC ADC #$02 CalculateFinalRiderGfxPointer ASL ASL ADC Temp5EGfxDataLo STA Temp5EGfxDataLo LDA #$A8 STA Temp5F LDA GameObjectXCoordHi,Y CLC ADC GameObjectDirection,Y SEC SBC #$20 STA Temp61SpriteXCoord LDA #$A1 STA Temp62 LDA GameObjectYCoordHi,Y SEC SBC #$0F STA Temp63SpriteYCoord JMP AddSpriteToRenderList PrepareOnPlatformBirdSprite STX TempCollisionOverlap LDA.w GameObjectState,Y CMP #$06 ; invincible BNE RenderBirdOnPlatform LDA BirdObjectPaletteAndWidth,Y STA Temp60PaletteAndWidth LDA BirdSpawnGfxOffsetLUT,Y CLC LDX GameObjectDirection,Y BMI SetSpawnGfxForLeftFacingBird ADC #$02 SetSpawnGfxForLeftFacingBird STA Temp5E LDA GameObjectYCoordHi,Y SEC SBC #$05 STA Temp66 AND #$07 STA Temp64 LDA #$A8 CLC ADC Temp64 STA Temp5F LDA Temp66 LSR LSR LSR STA Temp66 JMP FinalizeOnPlatformSpriteCoordsAndRender RenderBirdOnPlatform LDA #$1E STA Temp60PaletteAndWidth LDA #$AB STA Temp5FGfxDataHi LDA GameObjectFootstepAnimIndex,Y ASL LDX GameObjectDirection,Y BMI SelectLeftFacingWalkFrame CLC ADC #$0A SelectLeftFacingWalkFrame CLC ADC #$C4 ADC BirdWalkCycleGfxOffsetLUT,Y STA Temp5EGfxDataLo LDA GameObjectYCoordHi,Y SEC SBC #$07 LSR LSR LSR STA Temp66 FinalizeOnPlatformSpriteCoordsAndRender LDA GameObjectXCoordHi,Y LDX GameObjectDirection,Y CLC BMI SetLeftFacingOnPlatformSpriteXCoord ADC #$01 SetLeftFacingOnPlatformSpriteXCoord SEC SBC #$20 STA Temp61SpriteXCoord LDX TempCollisionOverlap STY Temp65 LDY Temp66 JSR UpdateRenderList LDY Temp65 RTS PrepareBirdSpriteForRenderList STX TempCollisionOverlap LDA BirdObjectPaletteAndWidth,Y STA Temp60PaletteAndWidth LDA GameObjectDirection,Y BMI SetBirdSpriteBaseGfxForLeftFacing LDA #$06 JMP ContinuePrepareBirdSprite SetBirdSpriteBaseGfxForLeftFacing LDA #$00 ContinuePrepareBirdSprite STA Temp5E LDA GameObjectInAir,Y BEQ SetOnPlatformAnimationOffset LDA GameObjectAnimationFrame,Y ASL JMP CalculateFinalBirdGfxPointer SetOnPlatformAnimationOffset LDA #$04 CalculateFinalBirdGfxPointer CLC ADC Temp5E ADC BirdGfxAnimationOffsetLUT,Y STA Temp5E LDX TempCollisionOverlap LDA #$A8 STA Temp5F LDA GameObjectXCoordHi,Y SEC SBC #$20 STA Temp61 LDA #$9C STA Temp62 LDA GameObjectYCoordHi,Y SEC SBC #$10 CMP #$F0 BCC SkipClampYCoord LDA #$00 SkipClampYCoord STA Temp63SpriteYCoord ;------------------------------------------------------------------------------ ; AddSpriteToRenderList ; Takes sprite parameters from ZP temps and adds one or more 8-pixel tall sprite ; slices to the render list. It handles breaking down taller sprites into ; multiple slices and calculating their positions in the Display List zones. ;------------------------------------------------------------------------------ AddSpriteToRenderList STY Temp65 ; save Y LDA Temp63SpriteYCoord AND #$07 STA Temp64SpriteYOffset ; Y offset in zone LDA Temp5FGfxDataHi CLC ADC Temp64SpriteYOffset STA Temp5FGfxDataHi LDA Temp63SpriteYCoord LSR LSR LSR TAY ; Y is zone index for this sprite AddAllSpriteSlicesToRenderListLoop JSR UpdateRenderList LDA Temp5FGfxDataHi SEC SBC #$08 CMP Temp62 BCC FinishMultiSliceSpriteRender STA Temp5FGfxDataHi INY JMP AddAllSpriteSlicesToRenderListLoop FinishMultiSliceSpriteRender LDY Temp65 ; restore Y RTS ;------------------------------------------------------------------------------ ; UpdateRenderList ; The core function that adds a single sprite slice to the render list arrays. ; It also decrements the pointer for the corresponding DL zone to make space. ;------------------------------------------------------------------------------ UpdateRenderList CPY #$16 BCS UpdateRenderList_Exit INX LDA Temp5EGfxDataLo STA RenderListGfxDataLo,X LDA Temp5FGfxDataHi STA RenderListGfxDataHi,X LDA Temp60PaletteAndWidth STA RenderListPaletteAndWidth,X LDA Temp61SpriteXCoord STA RenderListXCoord,X LDA DisplayListLo,Y SEC SBC #$04 STA DisplayListLo,Y STA RenderListDLLo,X LDA DisplayListHi,Y SBC #$00 STA DisplayListHi,Y STA RenderListDLHi,X UpdateRenderList_Exit RTS ;------------------------------------------------------------------------------ ; UpdateDLWithBackgroundSprites ; Initializes the static background elements of the Display Lists by copying ; data from ROM tables into their respective DL object locations in RAM. ; This sets up platforms, lava, and other non-interactive scenery. ;------------------------------------------------------------------------------ UpdateDLWithBackgroundSprites LDX #$20 BackgroundSpriteUpdateLoop LDA GameDLStartLutLo,X STA TempPointLo5A LDA GameDLStartLutHi,X STA TempPointHi5B LDA BackgroundSpriteGfxLoLUT,X LDY #$00 STA (TempPointLo5A),Y LDA BackgroundSpritePaletteWidthLUT,X INY STA (TempPointLo5A),Y LDA BackgroundSpriteGfxHiLUT,X INY STA (TempPointLo5A),Y LDA BackgroundSpriteXCoordLUT,X INY STA (TempPointLo5A),Y DEX BPL BackgroundSpriteUpdateLoop LDX #$05 UpdateDLWithMsgAndHUDCharObjects LDA HUDCharDLAddrLoLUT,X STA TempPointLo5A LDA HUDCharDLAddrHiLUT,X STA TempPointHi5B ; DL byte 0 LDA MsgAndHUDCharObjectStringLoLUT,X LDY #$00 STA (TempPointLo5A),Y ; DL byte 1 LDA #$60 ; character mode INY STA (TempPointLo5A),Y ; DL byte 2 LDA MsgAndHUDCharObjectStringHiLUT,X INY STA (TempPointLo5A),Y ; DL byte 3 LDA MsgAndHUDCharObjectPaletteAndWidthLUT,X INY STA (TempPointLo5A),Y ; DL byte 4 LDA MsgAndHUDCharObjectXLUT,X INY STA (TempPointLo5A),Y DEX BPL UpdateDLWithMsgAndHUDCharObjects LDA DisplayEasterEggFlag BEQ SkipEasterEggDisplaySetup LDX #$0E CopyEasterEggDataToRamLoop LDA EasterEggDisplayData,X STA $21FF,X DEX BNE CopyEasterEggDataToRamLoop LDA #$30 STA $1FEF SkipEasterEggDisplaySetup LDX #$09 ; loop through all of the birds InitializeBirdPalettesLoop LDA BirdPaletteAndWidthLUT,X STA BirdObjectPaletteAndWidth,X LDA RiderPaletteAndWidthLUT,X STA RiderObjectPaletteAndWidth,X DEX BPL InitializeBirdPalettesLoop ; Initialize the working Display List pointers from the master ROM table LDX #$17 InitializeWorkDLPointerLoop LDA DisplayListLoLUT,X STA DisplayListLo,X LDA DisplayListHiLUT,X STA DisplayListHi,X DEX BPL InitializeWorkDLPointerLoop LDX #$00 LDY #$00 CopyWorkDLToFinalDLLLoop LDA DisplayListHi,X STA $275E,Y LDA DisplayListLo,X STA $275F,Y INY INY INY INX CPX #$18 BNE CopyWorkDLToFinalDLLLoop LDX #$18 InitializeScorePopupJumpTable LDA ReturnFromScorePopupCreation,X STA $27B2,X DEX BNE InitializeScorePopupJumpTable EasterEggDisplayData RTS ; easter egg data .byte $18 .byte $29 .byte $21 .byte $26 .byte $21 .byte $FD .byte $1B .byte $17 .byte $21 .byte $23 .byte $23 .byte $1C .byte $23 .byte $1C ;------------------------------------------------------------------------------ ; SetupTitleScrDLs ; Initializes all Display List objects specifically for the title screen. ;------------------------------------------------------------------------------ SetupTitleScrDLs LDX #$50 SetupTitleScrCharacterDLs ; destination memory for next DL object... LDA TitleScrDLAddrLoLUT,X STA TempPointLo5A LDA TitleScrDLAddrHiLUT,X STA TempPointHi5B LDA TitleScrCharObject_LoAddress,X LDY #$00 STA (TempPointLo5A),Y ; Byte 0: Lo Address LDA #$60 ; Indirect/Character Object INY STA (TempPointLo5A),Y ; Byte 1: Mode LDA TitleScrCharObject_HiAddress,X INY STA (TempPointLo5A),Y ; Byte 2: Hi Address LDA TitleScrCharObject_PalleteWidth,X INY STA (TempPointLo5A),Y ; Byte 3: Palette+Width LDA TitleScrCharObject_XCoordinate,X INY STA (TempPointLo5A),Y ; Byte 4: X Coordinate DEX BPL SetupTitleScrCharacterDLs LDX #$0C SetupTitleScrSpriteDLs ; destination memory for next DL object... LDA TitleScrCharacterObjectLoLUT,X STA TempPointLo5A LDA TitleScrCharacterObjectHiLUT,X STA TempPointHi5B LDA TitleScrSpriteObjectLoLUT,X LDY #$00 STA (TempPointLo5A),Y ; Byte 0: Lo Address LDA TitleScrSpriteObject_PaletteWidth,X INY STA (TempPointLo5A),Y ; Byte 1: Palette+Width LDA TitleScrSpriteObjectHiLUT,X INY STA (TempPointLo5A),Y ; Byte 2: Hi Address LDA TitleScrSpriteObject_XCoordinate,X INY STA (TempPointLo5A),Y ; Byte 3: X Coordinate DEX BPL SetupTitleScrSpriteDLs RTS ;------------------------------------------------------------------------------ ; SetColorRegisters ; Copies the 24-byte color palette from RAM ($0190) to the hardware color ; registers ($20-$3F) every frame. ;------------------------------------------------------------------------------ SetColorRegisters LDA #$00 STA BACKGRND LDA PaletteInRam+$00 STA P0C1 LDA PaletteInRam+$01 STA P0C2 LDA PaletteInRam+$02 STA P0C3 LDA PaletteInRam+$03 STA P1C1 LDA PaletteInRam+$04 STA P1C2 LDA PaletteInRam+$05 STA P1C3 LDA PaletteInRam+$06 STA P2C1 LDA PaletteInRam+$07 STA P2C2 LDA PaletteInRam+$08 STA P2C3 LDA PaletteInRam+$09 STA P3C1 LDA PaletteInRam+$0A STA P3C2 LDA PaletteInRam+$0B STA P3C3 LDA PaletteInRam+$0C STA P4C1 LDA PaletteInRam+$0D STA P4C2 LDA PaletteInRam+$0E STA P4C3 LDA PaletteInRam+$0F STA P5C1 LDA PaletteInRam+$10 STA P5C2 LDA PaletteInRam+$11 STA P5C3 LDA PaletteInRam+$12 STA P6C1 LDA PaletteInRam+$13 STA P6C2 LDA PaletteInRam+$14 STA P6C3 LDA PaletteInRam+$15 STA P7C1 LDA PaletteInRam+$16 STA P7C2 LDA PaletteInRam+$17 STA P7C3 RTS ; well, how did I get here? ; (clear the HUD display string buffer) LDX #$67 LDA #$00 ClearHudDisplayStringBuffer STA HudDisplayStringBuffer,X DEX BPL ClearHudDisplayStringBuffer RTS InitializeFinalDisplayListPointers LDX #$56 CopyFinalDllPointersLoop LDA DllLUT,X STA $2700,X STA $2757,X DEX BPL CopyFinalDllPointersLoop RTS ;------------------------------------------------------------------------------ ; CreateScorePopupAtObjectLocation ; Creates a score popup (e.g., "500") at a specified location. It finds an ; available popup slot and initializes its timer, position, and character value. ; Input: Temp5E/Temp5F = Y/X coordinates. Temp60 = score value index. ;------------------------------------------------------------------------------ CreateScorePopupAtObjectLocation TXA PHA TYA PHA LDX #$0B FindAvailableScorePopupSlot LDA $26C4,X BEQ FoundAvailableScorePopupSlotInitialize DEX BPL FindAvailableScorePopupSlot LDX #$0B FoundAvailableScorePopupSlotInitialize LDA #$1E STA $26C4,X LDA Temp5E SEC SBC #$10 BPL CalculateScorePopupZone CMP #$E0 BCC CalculateScorePopupZone LDA Temp5F SEC SBC #$12 STA Temp5F LDA #$00 CalculateScorePopupZone LSR LSR LSR STA $26DC,X LDA Temp5F SEC SBC #$26 CMP #$91 BCC StoreClampedScorePopupXCoord CMP #$C0 BCC ClampScorePopupXTooFarRight LDA #$00 BEQ StoreClampedScorePopupXCoord ClampScorePopupXTooFarRight LDA #$90 StoreClampedScorePopupXCoord STA $26D0,X LDY Temp60 LDA ScorePopupValues,Y STA $26E8,X PLA TAY PLA TAX ReturnFromScorePopupCreation RTS ; Data for score popups .byte $00 .byte $0E .byte $11 .byte $0C .byte $00 .byte $11 .byte $0C .byte $0C .byte $00 .byte $13 .byte $11 .byte $0C .byte $0D .byte $0C .byte $0C .byte $0C .byte $00 .byte $06 .byte $01 .byte $01 .byte $0F .byte $0C .byte $0C .byte $0C ScorePopupValues ; scores 250, 500, 750, ... .byte $B3 .byte $B7 .byte $BB .byte $BF .byte $C3 .byte $C7 ;------------------------------------------------------------------------------ ; NMI_ROUTINE ; Non-Maskable Interrupt handler. This is the heart of the game's frame-by-frame ; processing. It is responsible for sound, input, palette updates, and, most ; importantly, processing the render list to update the hardware display lists. ; It supports three modes via NMIModeFlag: ; $00: Normal in-game processing. ; $01: Title screen, 160A mode (left/right borders). ; $FF: Title screen, 320A mode (central logo area). ;------------------------------------------------------------------------------ NMI_ROUTINE NMI_SaveRegisters PHA ; Save A TXA PHA ; Save X TYA PHA ; Save Y LDA NMIModeFlag ; Check current NMI mode BEQ NMI_ProcessNormalGame ; If $00, handle normal game NMI BMI NMI_ProcessSplitScreen_320A_Mode ; If $FF (negative), handle 320A part of split screen ; This is the 160A portion of the title screen's split-screen rendering. ; It handles the scrolling borders on the left and right. NMI_ProcessSplitScreen_160A_Mode ; NMIModeFlag was $01 LDA #CTRL_DMA_ON_160AB ; Set CTRL for 160A mode (normal width pixels) STA CTRL JSR CycleTitleScreenPaletteAndCounters ; Update title screen colors and border animation LDA #NMIMode_SplitScreen320A ; Set flag for the *next* NMI to be the 320A part STA NMIModeFlag JMP NMI_ExitAndRestoreRegisters ; This is the 320A portion of the title screen's split-screen rendering. ; It handles the central logo area with double-width pixels. NMI_ProcessSplitScreen_320A_Mode ; NMIModeFlag was $FF STA WSYNC ; Wait until the end of the line STA WSYNC ; Wait until the end of the line LDA #CTRL_DMA_ON_320AC ; Set CTRL for 320A mode (double-width pixels) STA CTRL LDA #NMIMode_SplitScreen160A ; Set flag for the *next* NMI to be the 160A part STA NMIModeFlag JMP NMI_ExitAndRestoreRegisters ; This is the main NMI handler for gameplay and demo mode. NMI_ProcessNormalGame JSR ServiceSFX ; Process active sound effects ; Read Player 0 Fire Button with a one-frame debounce. ; P0LastFire holds the state from the previous NMI, P0CurrentFire holds this NMI's state. ; This prevents a single press from being registered on multiple consecutive frames. LDA INPT4 ; Read Player 0 input port AND #Input_FireButtonMask ; Isolate fire button bit CMP P0LastFire ; Compare with last latched state BEQ NMI_P0_Fire_NoChange ; If same, no change in press state STA P0LastFire ; New state, update P0LastFire BNE NMI_P0_Fire_StoreCurrent ; If different and non-zero (pressed), store it as current NMI_P0_Fire_NoChange STA P0CurrentFire ; Store current state (either newly pressed or still same as last) NMI_P0_Fire_StoreCurrent ; Read Player 1 Fire Button with a one-frame debounce. LDA INPT5 ; Read Player 1 input port AND #Input_FireButtonMask ; Isolate fire button bit CMP P1LastFire ; Compare with last latched state BEQ NMI_P1_Fire_NoChange ; If same, no change in press state STA P1LastFire ; New state, update P1LastFire BNE NMI_P1_Fire_StoreCurrent ; If different and non-zero (pressed), store it as current NMI_P1_Fire_NoChange STA P1CurrentFire ; Store current state NMI_P1_Fire_StoreCurrent ; Increment global 16-bit frame timer INC TimerLo BNE NMI_Timer_HiByteNoInc ; If TimerLo didn't wrap, skip TimerHi increment INC TimerHi NMI_Timer_HiByteNoInc JSR SetColorRegisters ; Update hardware color palette registers from RAM LDA RenderListDirty ; Check if the game logic has prepared a new list of sprites to draw BNE ProcessDirtyRenderList ; If dirty, branch to process it JMP NMI_ExitAndRestoreRegisters ; If not dirty, nothing to render, so exit NMI ProcessDirtyRenderList LDX RenderListCount ; Get number of sprites in the render list BMI FinalizeDisplayListPointers ; If negative (e.g., $FF from init), skip sprite processing RenderSpritesFromListToDisplayList ; This loop iterates through the render list (built by the main game logic) ; and writes the 5-byte sprite definitions into the appropriate Display List zones. LDA RenderListDLLo,X ; Get Lo byte of target DL entry address for this sprite STA TempPoint5CLo ; Store in ZP pointer LDA RenderListDLHi,X ; Get Hi byte of target DL entry address STA TempPoint5DHi ; Store in ZP pointer LDY #$00 ; Y will be offset into the 5-byte DL object LDA RenderListGfxDataLo,X ; Byte 0: Graphics Data Lo STA (TempPoint5CLo),Y INY LDA RenderListPaletteAndWidth,X ; Byte 1: Palette and Width STA (TempPoint5CLo),Y INY LDA RenderListGfxDataHi,X ; Byte 2: Graphics Data Hi STA (TempPoint5CLo),Y INY LDA RenderListXCoord,X ; Byte 3: X Coordinate (Horizontal Position) STA (TempPoint5CLo),Y DEX BPL RenderSpritesFromListToDisplayList ; After processing sprites, process score popups (if any) LDX #$0B ; Max index for score popups (12 popups, 0 to 11) ProcessScorePopupsLoop LDA ScorePopup_ActiveTimerBase,X ; Check if this score popup timer is active BEQ SkipThisScorePopup ; If timer is 0, skip this popup DEC ScorePopup_ActiveTimerBase,X ; Decrement active timer LDY ScorePopup_ZoneIndexBase,X ; Y = Zone index for this score popup SEC LDA DisplayListLo,Y ; Get current Lo pointer for this zone's DL SBC #$05 ; Make space for a 5-byte character DL object by moving the pointer up STA DisplayListLo,Y ; Store updated Lo pointer STA TempPoint5CLo ; Use ZP pointer for indirect write LDA DisplayListHi,Y ; Get current Hi pointer SBC #$00 ; Adjust Hi pointer if Lo underflowed STA DisplayListHi,Y ; Store updated Hi pointer STA TempPoint5DHi ; Use ZP pointer LDY #$00 ; Y = offset into DL object LDA ScorePopup_CharDataLoBase,X ; Byte 0: Character Data Lo (e.g., '2' for "250") STA (TempPoint5CLo),Y INY LDA #ScorePopup_DLModeByte ; Byte 1: Mode (Indirect Character) STA (TempPoint5CLo),Y INY LDA #ScorePopup_DLCharHiByte ; Byte 2: Character Data Hi (High byte of HSC font base) STA (TempPoint5CLo),Y INY LDA #$7C ; Byte 3: Palette & Width (seems fixed for score popups) STA (TempPoint5CLo),Y INY LDA ScorePopup_XCoordBase,X ; Byte 4: X Coordinate STA (TempPoint5CLo),Y SkipThisScorePopup DEX ; Next score popup slot BPL ProcessScorePopupsLoop ; Loop if X is not negative FinalizeDisplayListPointers ; Copy the adjusted DisplayListLo/Hi pointers (from $242B/$2443) ; into the final RAM area ($275E onwards) that Maria's DLL will use. ; This is done in reverse order because the final DLL structure is 3 bytes ; per entry (Interrupt/Height, Hi, Lo) and it's easier to fill from the end. LDX #$17 ; Number of DL zones - 1 (0 to 23) LDY #$45 ; Offset into FinalDLL_PointerStorage (starts at $275E + $45 = $27A3) CopyDLLPointersToFinalRAMLoop LDA DisplayListHi,X ; Get Hi byte of DL pointer for zone X STA FinalDLL_PointerStorage_Hi,Y ; Store it LDA DisplayListLo,X ; Get Lo byte of DL pointer for zone X STA FinalDLL_PointerStorage_Lo,Y ; Store it DEY ; Next storage slot (lower address) DEY DEY ; DLL entries are 3 bytes (interrupt+height, Hi, Lo) DEX ; Next zone BPL CopyDLLPointersToFinalRAMLoop INX ; X = 0 STX RenderListDirty ; Clear the dirty flag, signaling the main loop that rendering is complete. NMI_ExitAndRestoreRegisters PLA ; Restore Y TAY PLA ; Restore X TAX PLA ; Restore A ; Fall through to IRQ RTI IRQ_ROUTINE RTI ;------------------------------------------------------------------------------ ; Title Screen and Menu Logic ;------------------------------------------------------------------------------ AttractModeMain JSR SetupTitleScreen LDA TimerLo STA $6E SEC SBC #$01 STA Temp68 LDA #$01 STA Temp69 AttractMode_FrameLoop LDA TimerLo CMP $6E BEQ AttractMode_FrameLoop STA $6E JSR HandleDemoModeJoyInput JSR AnimateTitleScreenFrame LDA Temp68 CMP TimerLo BNE AttractMode_FrameLoop DEC Temp69 BPL AttractMode_FrameLoop LDA #$00 STA Temp62 AttractMode_HSC_Loop JSR DoHscStatusCheck BMI HscLoopContinueOrExit JSR DoHscAttractMode LDA INPT4 AND INPT5 JSR CheckForAttractModeExit HscLoopContinueOrExit INC Temp62 LDA Temp62 CMP #$04 BCC AttractMode_HSC_Loop RTS SetupTitleScreen SEI LDA #$60 STA CTRL JSR ClearRamMuteAudio JSR LoadTitlePalette JSR SetColorRegisters JSR SetupTitleScrText JSR SetupTitleScrDLs WaitVblankOver BIT MSTAT BMI WaitVblankOver WaitVblankStart BIT MSTAT BPL WaitVblankStart ; ** We're now in vblank LDA #$00 STA DPPL LDA #$27 STA DPPH ; Register $2700 as the DLL location LDA #$40 ; DMA on, single-width chars STA CTRL RTS DisplayGameOptions JSR SetupTitleScreen LDX #$0F CopyPlayerStringLoop LDA StringOnePlayer,X STA MenuLine2CharBuffer,X LDA StringTwoPlayer,X STA MenuLine1CharBuffer,X DEX BPL CopyPlayerStringLoop JSR SetupGameOptionsText JSR SetMenuJoyDebounceTimerTo20 JSR SetMenuSelectDebounceTimerTo20 JSR SetMenuResetTimer ; MenuResetTimer = Timerhi - 1 GameOptionsMenuLoop JSR CheckMenuFireButtonAndStartGame JSR SetupGameOptionsText JSR AnimateTitleScreenFrame LDA SWCHA AND #$F0 CMP #$F0 BNE MenuJoyInput_ProcessAfterDebounce LDA #$00 STA MenuJoyDebounceTimer GoMenuHandlingAndUpdate JMP MenuHandlingAndUpdate ; MenuJoyInput_ProcessAfterDebounce ; This code is reached after the joystick debounce timer (MenuJoyDebounceTimer) ; has expired, indicating it's time to process joystick input for the menu. ; Part of the DisplayGameOptions routine. MenuJoyInput_ProcessAfterDebounce DEC MenuJoyDebounceTimer ; Decrement debounce timer BPL GoMenuHandlingAndUpdate ; If timer still active, skip input processing for now JSR SetMenuJoyDebounceTimerTo20 ; Reset debounce timer for next input LDA SWCHA ; Read Player 1 Joystick & Console Switches ; SWCHA bits (active low for joystick) ; 7654 3210 ; ---- RLDU (Right, Left, Down, Up for P1 Joystick) ASL ; Shift P1 Right (Bit 3) into Carry BCC HandleP0JoyRight ASL ; Shift P1 Left (Bit 2) into Carry BCC HandleP0JoyLeft ASL ; Shift P1 Down (Bit 1) into Carry BCS MenuJoyInput_CheckP1UpOrNoVerticalInput JMP MenuSelectOnePlayer ; P1 Down IS pressed: Select 1 Player MenuJoyInput_CheckP1UpOrNoVerticalInput ASL ; Shift P1 Up (Bit 0) into Carry BCS HandleP0JoyRight JMP MenuSelectTwoPlayers ; P1 Up IS pressed: Select 2 Players ;------------------------------------------------------------------------------ ; HandleP0JoyRight ; Increases the game difficulty, capping at Difficulty_Expert. ; Resets the counters used for the menu easter egg. ;------------------------------------------------------------------------------ HandleP0JoyRight LDX Difficulty CPX #Difficulty_Expert ; Max difficulty? BPL SkipDifficultyIncrease ; If at or above max, skip INX ; Increase difficulty STX Difficulty JSR ClearScores ; Clear scores when difficulty changes SkipDifficultyIncrease LDA #$00 ; Reset easter egg press counters STA EasterEggJoyDownCount STA EasterEggJoyLeftCount JMP MenuTextUpdate ; Redraw menu text ;------------------------------------------------------------------------------ ; HandleP0JoyLeft ; Decreases the game difficulty, bottoming out at Difficulty_Beginner. ; Jumps to update counters used for the menu easter egg. ;------------------------------------------------------------------------------ HandleP0JoyLeft LDX Difficulty BEQ SkipDifficultyDecrease ; If already at Beginner, skip DEX ; Decrease difficulty STX Difficulty JSR ClearScores ; Clear scores when difficulty changes SkipDifficultyDecrease JMP MenuUpdateCounter ; This section seems to be entirely dead. ; Emulation debugging during regular play shows no access. ; In assembly it would be "BIT $56, ORA $03, KIL, KIL". ; It's not accessed by Maria, and isn't sensible in ASCII nor the game's character set. .byte $24 ; $9FFA .byte $56 ; $9FFB .byte $05 ; $9FFC .byte $03 ; $9FFD .byte $12 ; $9FFE .byte $12 ; $9FFF ; ORG $A000 ; This upcoming bit is a bit ugly. It's mostly Maria gfx data, but they stuck some ; 6502 data in the middle of each page. .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00 ; A058 BirdWalkCycleGfxOffsetLUT .byte $00, $14, $28, $28, $28, $28, $28, $28, $28, $28 BirdSpawnGfxOffsetLUT .byte $82, $86, $8A, $8A, $8A, $8A, $8A, $8A, $8A, $8A BirdPaletteAndWidthLUT .byte $BE,$DE,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE RiderPaletteAndWidthLUT .byte $7E,$7E,$5E,$5E,$5E,$5E,$5E,$5E,$5E,$5E BirdGfxAnimationOffsetLUT .byte $08, $14, $20, $20, $20 ; This doesn't seem to be reached by Sally or Maria .byte $20, $20, $20, $20, $20 ; This is graphics data (A08E) .byte $03, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $F0, $3F, $55, $55, $55, $55, $55, $55 .byte $55, $55, $55, $55, $55, $7F, $FD, $55 .byte $55, $55, $55, $55, $55, $55, $55, $55 .byte $55, $55, $7C, $00, $EB, $FF, $FF, $FB .byte $FF, $FA, $AF, $FF, $BE, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $EB, $FB, $AF, $AF .byte $FE, $FF, $AB, $BF, $FF, $AF, $FF, $FF .byte $A8, $0F, $BE, $A0, $00, $AF, $F8, $2F .byte $FF, $A8, $BB, $FA, $FC, $0F, $FF, $AF .byte $80, $FF, $EB, $E8, $2A, $C2, $BF, $E8 .byte $F0, $EE, $AF, $00, $00, $00, $00, $00 ; A100 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 ; A180 TitleScrSpriteObject_PaletteWidth .byte $FA, $FF, $F7, $FD, $F6, $F6, $FA, $F6 .byte $F6, $FA, $33, $33, $34 .byte $00 ; not used ; A18E .byte $0E, $FA .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA .byte $AA, $AA, $AB, $FF, $EA, $AA, $AA, $AA .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AF .byte $FC, $2F, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $00, $AB, $FF, $BF, $FA .byte $BF, $FF, $EA, $BE, $FF, $FF, $FF, $FF .byte $FF, $FF, $EA, $BE, $BE, $AA, $AE, $FA .byte $AF, $FE, $AF, $EE, $AB, $FB, $AB, $FE .byte $AA, $0E, $BF, $A8, $02, $BF, $FE, $FF .byte $FA, $FE, $BF, $BF, $EA, $FF, $FE, $FB .byte $B3, $FF, $BA, $EA, $2F, $A2, $FA, $B0 .byte $E0, $AA, $BB, $FC, $0A, $C0, $00, $00 ; A200 .byte $F8, $00, $F8, $00, $3E, $00, $F0, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 ; A280 TitleScrSpriteObject_XCoordinate .byte $41, $2F, $0F, $57, $31, $57, $7D, $31 .byte $57, $7D, $B4, $B4, $B8 .byte $00 ; not used ; A28E .byte $02, $BF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $F8, $0D, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $DF, $F7, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $DF, $00, $3A, $FB, $EB, $FF .byte $BF, $FF, $FA, $EF, $FF, $FF, $FE, $AF .byte $FE, $BF, $BE, $EE, $FF, $FA, $AB, $FF .byte $FF, $FE, $AF, $AA, $FA, $AF, $3F, $EA .byte $AA, $83, $FF, $E8, $00, $BF, $FF, $BF .byte $EF, $FF, $FE, $FE, $BE, $BF, $FE, $AF .byte $FE, $AF, $FE, $3F, $AB, $EF, $B8, $02 .byte $AF, $FF, $FC, $AF, $BA, $F0, $00, $00 ; A300 .byte $BE, $00, $BE, $00, $3F, $00, $FC, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $FC, $3A, $7C .byte $00, $00, $3F, $00, $3D, $AC, $00, $00 .byte $00, $00, $BB, $C0, $00, $00, $00, $00 .byte $03, $EE, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 ; A380 PterryFrameIndexAdjustmentLUT .byte $01, $01, $FF, $FF BirdBornSFXType .byte $09, $09, $0C, $0C, $0C, $0C, $0C, $0C, $0C, $0C ; A38E .byte $0F, $AF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FA .byte $A8, $37, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $F7, $DF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $F7, $C0, $3E, $BF, $FF, $FF .byte $FE, $AA, $EE, $AA, $FF, $FF, $EA, $FE .byte $FB, $AF, $FF, $EF, $EF, $FF, $BF, $FF .byte $FF, $FA, $EA, $BF, $FA, $A8, $03, $AB .byte $EA, $A2, $FF, $FA, $00, $FF, $FF, $EF .byte $FF, $FF, $EB, $FF, $FF, $EF, $FF, $EE .byte $EA, $BF, $FA, $AF, $BA, $AA, $A0, $0A .byte $FF, $FF, $F0, $EA, $FA, $EF, $AC, $00 ; A400 .byte $BF, $80, $BF, $80, $3F, $C0, $FF, $40 .byte $00, $00, $0F, $B0, $00, $00, $00, $00 .byte $0E, $F0, $00, $00, $03, $AF, $05, $6F .byte $02, $BF, $FA, $C0, $F9, $50, $FE, $80 .byte $00, $00, $EE, $F0, $00, $00, $00, $00 .byte $0F, $BB, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ,$00, $00 .byte $00, $00, $00, $00, $00, $00 ; A48E .byte $0F, $AB .byte $FF, $EA, $AE, $AA, $AB, $FA, $AA, $FF .byte $FF, $FF, $AB, $FA, $AB, $FF, $EA, $AA .byte $AA, $BE, $EA, $AB, $FB, $FA, $AA, $AA .byte $FC, $3F, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $80, $0F, $AF, $FF, $FF .byte $FA, $AF, $FE, $FB, $BF, $FF, $EF, $FF .byte $EF, $FF, $FF, $FB, $FF, $FF, $EB, $EA .byte $BF, $FB, $FF, $FF, $FE, $BE, $00, $BF .byte $FE, $A8, $FF, $EA, $80, $3F, $FF, $FE .byte $FF, $FF, $EF, $FF, $FF, $FF, $EA, $FB .byte $BA, $BF, $FF, $EA, $AA, $BE, $88, $AA .byte $FF, $AA, $A0, $EF, $FE, $BF, $FF, $00 ; A500 .byte $3F, $E0, $3F, $E0, $3F, $F0, $FD, $80 .byte $03, $F8, $03, $B8, $03, $B8, $2F, $C0 .byte $2E, $C0, $2E, $C0, $05, $A8, $06, $A8 .byte $06, $A8, $2A, $50, $2A, $90, $2A, $90 .byte $01, $A8, $37, $AC, $45, $B8, $2A, $40 .byte $3A, $DC, $2E, $51, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; A58E .byte $05, $55 .byte $55, $55, $55, $55, $55, $55, $57, $55 .byte $55, $55, $D5, $55, $55, $55, $55, $55 .byte $55, $55, $55, $55, $55, $55, $55, $55 .byte $54, $3F, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $80, $0F, $EB, $FF, $FF .byte $BB, $FF, $FF, $FF, $FF, $FE, $FF, $FF .byte $BF, $FF, $FF, $FF, $FF, $FF, $FE, $BF .byte $EF, $FF, $FF, $FF, $FF, $AC, $00, $FF .byte $FA, $AA, $BE, $AA, $A0, $2F, $FF, $FF .byte $AA, $AF, $FF, $FE, $FF, $FF, $AF, $BF .byte $FE, $FF, $FF, $AA, $BB, $FF, $AA, $AB .byte $FA, $FA, $00, $EB, $BF, $AE, $AF, $C0 ; A600 .byte $3F, $F0, $3F, $FC, $BE, $FC, $39, $D0 .byte $0F, $FF, $0F, $EB, $0F, $EE, $FF, $F0 .byte $EB, $F0, $BB, $F0, $36, $A0, $35, $A0 .byte $35, $A0, $0A, $9C, $0A, $5C, $0A, $5C .byte $46, $BA, $06, $E6, $56, $AE, $AE, $91 .byte $9B, $90, $BA, $95, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; A68E .byte $05, $55 .byte $55, $55, $55, $55, $55, $55, $5D, $55 .byte $55, $55, $75, $55, $55, $55, $55, $55 .byte $55, $55, $55, $55, $55, $55, $55, $55 .byte $54, $EB, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FB, $EF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FB, $A0, $0E, $AF, $BF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $EF, $BC, $00, $EB .byte $EF, $FA, $BA, $FF, $AA, $2F, $FF, $EE .byte $AB, $EA, $FF, $FF, $FF, $FE, $FF, $FF .byte $FF, $FF, $FF, $AB, $EB, $FF, $AA, $AF .byte $EB, $FF, $00, $FF, $FA, $AF, $AB, $C0 ; A700 .byte $3F, $F8, $3F, $F8, $BE, $FF, $3E, $60 .byte $3C, $EE, $1C, $BA, $1F, $FA, $BB, $3C .byte $AE, $34, $AF, $F4, $16, $9B, $16, $80 .byte $16, $80, $E6, $94, $02, $94, $02, $94 .byte $56, $AC, $46, $A9, $1A, $BB, $3A, $95 .byte $6A, $91, $EE, $A4, $00, $00, $00, $00 .byte $00, $00, $00, $00, $40, $00, $15, $54 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $15, $54, $00, $01 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; A78E .byte $05, $55 .byte $55, $55, $55, $55, $55, $55, $75, $55 .byte $55, $55, $5D, $55, $55, $55, $55, $55 .byte $55, $55, $55, $55, $55, $55, $55, $55 .byte $54, $FE, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $EF, $FB, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $EF, $80, $0A, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $EF, $FC, $00, $3B .byte $EF, $FF, $AB, $FF, $AA, $AB, $EF, $EE .byte $BF, $FF, $AE, $FF, $FF, $FF, $FF, $FF .byte $FB, $FF, $FE, $AF, $FF, $FF, $EB, $FF .byte $FF, $FF, $00, $55, $55, $55, $55, $50 ; A800 .byte $3F, $F4, $3E, $F4, $FE, $F0, $3E, $F0 .byte $13, $F8, $13, $FE, $13, $FC, $2F, $C4 .byte $BF, $C4, $3F, $C4, $16, $57, $16, $00 .byte $16, $00, $D5, $94, $00, $94, $00, $94 .byte $16, $BA, $56, $A8, $0A, $A0, $AE, $94 .byte $2A, $95, $0A, $A0, $00, $3F, $C0, $00 .byte $50, $3F, $C0, $00, $14, $F1, $55, $50 .byte $00, $00, $C3, $30, $00, $00, $C3, $00 .byte $00, $00, $C0, $00, $00, $03, $FC, $00 .byte $00, $03, $FC, $05, $05, $55, $4F, $14 .byte $33, $0C, $00, $00, $03, $0C, $00, $00 .byte $00, $0C, $00, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $3C, $3C, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; A88E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 .byte $00, $00, $0F, $EF, $EA, $AA, $80, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00 ; A8C4 BirdSpawnInvulnAnimStateSequence_TypeA .byte $00, $00, $00, $00 .byte $00, $00, $00, $01, $02, $03, $04, $02 .byte $03, $04, $02, $03, $04, $02, $03, $04 .byte $02, $03, $04, $02, $03, $04, $02, $03 .byte $04, $02, $03, $04, $02, $03, $04, $05 .byte $06, $05, $06, $05, $06, $05, $06, $05 .byte $06, $05, $06, $05, $06, $05, $06, $05 .byte $06, $05, $06, $05, $06, $05, $06, $07 ; A900 .byte $3F, $FC, $3E, $FC, $FA, $FC, $3E, $A0 .byte $10, $FC, $10, $00, $10, $00, $3F, $04 .byte $00, $04, $00, $04, $38, $9A, $17, $00 .byte $17, $00, $A6, $2C, $00, $D4, $00, $D4 .byte $00, $AB, $14, $00, $00, $00, $EA, $00 .byte $00, $14, $00, $00, $00, $FF, $FF, $C0 .byte $35, $F1, $55, $C0, $05, $FD, $55, $00 .byte $F3, $CF, $33, $C0, $03, $03, $00, $C0 .byte $00, $00, $00, $00, $03, $FF, $FF, $00 .byte $03, $55, $4F, $5C, $00, $55, $7F, $50 .byte $0F, $33, $CF, $3C, $0C, $03, $03, $00 .byte $00, $00, $00, $00, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00 .byte $00, $00, $00, $00, $00, $00, $82, $08 .byte $02, $A8, $8A, $00, $02, $82, $00, $20 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; A98E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 .byte $00, $00, $AE, $BE, $BE, $FF, $A0, $00 .byte $00, $00, $00, $00, $00, $00, $00, $2A .byte $A0, $00, $00, $00, $3C, $EB, $EB, $3F .byte $A0, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $10 ; A9C4 BirdSpawnInvulnAnimStateSequence_TypeB .byte $02, $02, $02, $02 .byte $02, $02, $02, $00, $04, $04, $04, $04 .byte $04, $04, $03, $03, $03, $03, $03, $03 .byte $02, $02, $02, $02, $02, $02, $02, $02 .byte $02, $01, $01, $01, $00, $00, $00, $04 .byte $04, $04, $04, $03, $03, $03, $03, $02 .byte $02, $02, $02, $02, $02, $01, $01, $01 .byte $01, $01, $01, $00, $00, $00, $00, $00 ; AA00 .byte $3F, $CC, $3E, $CF, $FB, $CF, $3E, $F0 .byte $10, $3E, $1C, $00, $30, $00, $BC, $04 .byte $00, $34, $00, $0C, $38, $2B, $1C, $00 .byte $1C, $00, $E8, $2C, $00, $34, $00, $34 .byte $00, $2A, $00, $00, $00, $00, $A8, $00 .byte $00, $00, $00, $00, $03, $C7, $FF, $FF .byte $3D, $45, $55, $5F, $FD, $45, $55, $CF .byte $33, $33, $3C, $00, $33, $30, $0C, $00 .byte $33, $30, $00, $00, $FF, $FF, $D3, $C0 .byte $F5, $55, $51, $7C, $F3, $55, $51, $7F .byte $00, $F3, $33, $30, $00, $C0, $33, $30 .byte $00, $00, $33, $30, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00 .byte $00, $00, $00, $00, $20, $20, $00, $00 .byte $23, $E2, $8A, $80, $08, $82, $03, $28 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00 ; AA8E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 .byte $00, $FF, $FB, $BF, $AB, $FE, $A0, $00 .byte $00, $00, $00, $00, $00, $02, $80, $AA .byte $BC, $00, $00, $00, $AA, $BF, $FF, $FF .byte $FE, $EE, $00, $2A, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $10, $00 .byte $00, $00, $10, $44 ; AAC4 MaxEnemyBirdCountLUT .byte $06, $06, $06, $06, $06, $06, $08, $08, $08, $08 EggWaveEnemyTypeLUT .byte $00, $00, $01, $01, $01, $01, $01, $01, $01, $01 PlatformsInLevelLUT .byte $1F, $1F, $0F, $0F, $0D, $0C, $0C, $04, $0F, $07 .byte $04, $04, $0F, $0F, $0F, $0F, $0E, $0E, $06, $06 .byte $04, $04, $04, $04, $0F, $0F, $0D, $0D, $07, $0D .byte $05, $05, $0E, $06, $06, $04, $07, $0D, $05, $05 ; AB00 .byte $3C, $C0, $3C, $C0, $FC, $F0, $3E, $A0 .byte $10, $3E, $1C, $00, $10, $00, $BC, $04 .byte $00, $34, $00, $04, $34, $3F, $10, $00 .byte $10, $00, $FC, $1C, $00, $04, $00, $04 .byte $00, $2B, $00, $00, $00, $00, $E8, $00 .byte $00, $00, $00, $00, $55, $07, $FC, $00 .byte $05, $03, $FF, $C0, $01, $0D, $55, $5C .byte $CF, $30, $CF, $3C, $CC, $30, $00, $F0 .byte $0C, $00, $00, $30, $00, $3F, $D0, $55 .byte $03, $FF, $C0, $50, $35, $55, $70, $40 .byte $F3, $CC, $33, $CC, $3C, $00, $30, $CC .byte $30, $00, $00, $C0, $55, $51, $45, $55 .byte $AA, $A2, $8A, $AA, $55, $51, $45, $55 .byte $AA, $A2, $8A, $AA, $FF, $F3, $CF, $FF .byte $00, $00, $01, $00, $01, $00, $08, $80 .byte $23, $E0, $8E, $0C, $22, $A2, $00, $80 .byte $28, $A0, $04, $14, $14, $10, $20, $38 .byte $2C, $08, $70, $50, $05, $0D ; AB8E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 .byte $3A, $FF, $FF, $FF, $FF, $AA, $FF, $00 .byte $00, $00, $00, $00, $00, $AA, $AB, $AB .byte $AA, $BF, $00, $2A, $BF, $AA, $BF, $FF .byte $FF, $EA, $FE, $AA, $B0, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $10 .byte $00, $00, $00, $10, $04, $14, $01, $40 .byte $00, $50, $00, $14, $04, $10, $14, $10 .byte $01, $40, $05, $00, $14, $00, $04, $10 .byte $14, $05, $01, $80, $00, $10, $00, $04 .byte $1C, $60, $50, $14, $02, $40, $04, $00 .byte $10, $00, $09, $34, $70, $50, $06, $00 .byte $01, $80, $00, $60, $14, $50, $05, $0D .byte $00, $90, $02, $40, $09, $00, $05, $14 ; AC00 .byte $0C, $C0, $3C, $F0, $FB, $3C, $3E, $F0 .byte $14, $3F, $14, $00, $14, $00, $FC, $14 .byte $00, $14, $00, $14, $04, $0F, $10, $00 .byte $10, $00, $F0, $10, $00, $04, $00, $04 .byte $00, $0E, $00, $00, $00, $00, $B0, $00 .byte $00, $00, $00, $00, $05, $41, $FC, $00 .byte $10, $00, $00, $00, $04, $00, $00, $00 .byte $0C, $33, $33, $30, $0C, $33, $03, $30 .byte $00, $33, $03, $00, $00, $3F, $41, $50 .byte $00, $00, $00, $04, $00, $00, $00, $10 .byte $33, $33, $30, $C0, $33, $03, $30, $C0 .byte $03, $03, $30, $00, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $15, $54, $00 .byte $00, $2A, $A8, $00, $00, $3F, $FC, $00 .byte $01, $40, $04, $40, $01, $10, $80, $08 .byte $AB, $22, $BE, $2C, $23, $E0, $0A, $28 .byte $AA, $A8, $01, $04, $10, $40, $08, $08 .byte $20, $20, $30, $10, $04, $0C ; AC8E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 .byte $FF, $FA, $FF, $FF, $FF, $FF, $EF, $00 .byte $00, $00, $00, $00, $00, $FF, $AA, $EA .byte $FF, $FF, $00, $AE, $FF, $FF, $FF, $FF .byte $FF, $AB, $EB, $AB, $F0, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $DC .byte $00, $10, $00, $00, $01, $04, $00, $48 .byte $00, $10, $00, $04, $04, $10, $10, $40 .byte $21, $00, $04, $00, $10, $00, $04, $10 .byte $05, $04, $02, $40, $00, $10, $00, $04 .byte $04, $70, $10, $50, $01, $80, $04, $00 .byte $10, $00, $0D, $10, $30, $10, $01, $00 .byte $00, $40, $00, $10, $05, $24, $04, $0C .byte $00, $40, $01, $00, $04, $00, $18, $50 ; AD00 .byte $00, $00, $30, $30, $F3, $CC, $3E, $A0 .byte $54, $0E, $54, $00, $54, $00, $B0, $15 .byte $00, $15, $00, $15, $14, $0F, $50, $00 .byte $50, $00, $F0, $14, $00, $05, $00, $05 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $5F, $C0 .byte $40, $00, $00, $00, $10, $00, $00, $00 .byte $30, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $03, $F5, $00, $00 .byte $00, $00, $00, $01, $00, $00, $00, $04 .byte $00, $00, $00, $30, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $24, $18, $00 .byte $00, $18, $24, $00, $00, $34, $1C, $00 .byte $00, $18, $24, $00, $00, $2C, $38, $00 .byte $00, $00, $01, $00, $01, $00, $08, $80 .byte $2B, $2A, $0F, $2C, $A8, $0A, $AE, $AB .byte $AA, $AA, $01, $44, $11, $40, $02, $20 .byte $08, $80, $24, $10, $04, $18 ; AD8E .byte $FF,$FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $0E .byte $FF, $FF, $FD, $55, $55, $57, $FE, $00 .byte $00, $0B, $AE, $C0, $0E, $FF, $FF, $FA .byte $FA, $AF, $03, $FF, $EF, $55, $55, $55 .byte $FA, $BF, $FE, $BF, $FE, $00, $05, $55 .byte $55, $50, $0A, $AA, $AA, $A0, $00, $00 .byte $10, $44, $00, $00, $01, $44, $00, $44 .byte $00, $14, $00, $04, $01, $04, $11, $40 .byte $11, $00, $14, $00, $10, $00, $10, $40 .byte $01, $14, $00, $54, $00, $90, $14, $14 .byte $01, $10, $14, $40, $15, $00, $06, $00 .byte $14, $14, $04, $40, $24, $10, $01, $00 .byte $00, $40, $30, $10, $01, $14, $04, $18 .byte $00, $40, $01, $00, $04, $0C, $14, $40 ; AE00 .byte $00, $00, $00, $00, $F0, $F0, $2F, $B0 .byte $10, $0B, $10, $00, $10, $00, $E0, $04 .byte $00, $04, $00, $04, $38, $03, $D0, $00 .byte $D0, $00, $C0, $2C, $00, $07, $00, $07 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $05, $5C .byte $00, $00, $00, $00, $40, $00, $00, $00 .byte $C0, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $3F, $50, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $01 .byte $00, $00, $00, $0C, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $3C, $3C, $00 .byte $00, $00, $00, $00, $20, $20, $00, $00 .byte $33, $AA, $0F, $AB, $AE, $2A, $A2, $8B .byte $AA, $2A, $00, $54, $15, $00, $00, $B0 .byte $0E, $00, $04, $50, $05, $10 ; AE8E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $35 .byte $55, $55, $75, $55, $55, $55, $D5, $40 .byte $02, $BB, $FF, $A0, $0A, $AA, $BF, $BF .byte $EA, $BB, $0F, $FF, $5D, $55, $55, $55 .byte $7F, $FF, $FF, $FF, $FF, $C0, $15, $55 .byte $55, $54, $2A, $AA, $AA, $A8, $00, $00 .byte $00, $10, $00, $00, $00, $54, $00, $54 .byte $00, $14, $01, $4C, $01, $44, $15, $00 .byte $15, $00, $14, $00, $31, $40, $11, $40 .byte $03, $D4, $03, $DC, $01, $DC, $07, $DC .byte $01, $55, $17, $C0, $37, $C0, $37, $40 .byte $37, $D0, $55, $40, $04, $50, $01, $04 .byte $00, $40, $0E, $D0, $00, $54, $05, $10 .byte $10, $40, $01, $00, $07, $B0, $15, $00 ; AF00 .byte $00, $00, $00, $00, $C0, $00, $0B, $C0 .byte $00, $03, $00, $00, $00, $00, $C0, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $54 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $15, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $14, $14, $00 .byte $00, $28, $28, $00, $00, $3C, $3C, $00 .byte $00, $00, $00, $00, $00, $00, $82, $08 .byte $C3, $A2, $BC, $3E, $A8, $22, $80, $00 .byte $28, $0A, $00, $50, $05, $00, $00, $00 .byte $00, $00, $0A, $90, $06, $A0 ; AF8E .byte $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $15 .byte $55, $55, $D5, $55, $55, $55, $75, $40 .byte $0A, $AA, $BE, $A8, $15, $55, $55, $55 .byte $55, $57, $15, $55, $75, $55, $55, $55 .byte $5D, $55, $55, $55, $55, $50, $55, $55 .byte $55, $55, $AA, $AA, $AA, $AA, $00, $00 .byte $00, $00, $00, $00, $00, $50, $00, $54 .byte $00, $50, $00, $50, $00, $00, $05, $00 .byte $15, $00, $05, $00, $05, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $0A, $90, $01, $90 .byte $02, $60, $03, $E0, $00, $00, $06, $A0 .byte $06, $40, $09, $80, $0B, $C0, $00, $00 GameColdInit ESGameColdInit SEI LDA #$60 STA CTRL LDA #$17 STA INPTCTRL LDA #$00 STA OFFSET CLD LDX #$FF TXS JSR SystemHardwareInit StartGameInDemoMode JSR AttractModeMain LDA #$01 STA DemoMode JSR InitializeNewGame LDA TimerHi CLC ADC #$06 STA DemoTimer ; run demo for ~24-30 seconds JMP MainGameLoop StartNewGameFromMenu LDA #$00 STA DemoMode JSR InitializeNewGame MainGameLoop LDA TimerLo STA GamePacingTimer ; Initialize the pacer with the current frame time MainGameLoop_CheckState LDA GameActiveFlag ; Check if the game is active or in a game-over transition BEQ GameIsActiveOrDemo ; If 0, game is running normally (or in demo) ; Game is in the "ending" state (GameActiveFlag = 1) LDA GameEndDelayTimer BPL DecrementGameOverTimer LDA #$40 ; If timer underflowed, reset it STA GameEndDelayTimer DecrementGameOverTimer JSR CheckResetSwitch ; Allow player to reset during the game over sequence DEC GameEndDelayTimer ; Countdown before transitioning to high score screen BNE GameIsActiveOrDemo ; If timer still running, continue normal processing ; Game over timer has expired, transition to High Score screen JSR MuteAudio LDA #$00 STA CurrentPlayer ; Set to Player 1 for first score entry JSR DoHscScoreEntry ; Call High Score Cartridge for P1 LDA PlayerCount BEQ GameOver_ScoresEntered LDA #$01 ; If 2 players, set to Player 2 STA CurrentPlayer JSR DoHscScoreEntry ; Call High Score Cartridge for P2 GameOver_ScoresEntered LDA Difficulty STA Temp62 ; Preserve difficulty setting JSR DoHscAttractMode ; Show high score table JMP StartGameInDemoMode ; After high scores, return to demo mode GameIsActiveOrDemo LDA DemoMode BEQ PacingLoop ; If not in demo mode, skip to game pacing logic LDA TimerHi CMP DemoTimer ; Check if the demo timer has expired BEQ StartGameInDemoMode ; If so, restart the demo/attract sequence PacingLoop ; This loop ensures the main game logic runs at a consistent rate (every 2 frames). ; It prevents the game speed from fluctuating based on processing load. LDA TimerLo SEC SBC GamePacingTimer CMP #$02 ; Has the frame timer advanced by at least 2 ticks? BCC PacingLoop ; If not, wait. LDA TimerLo STA GamePacingTimer ; Latch the new time for the next pace check JSR HandleConsoleSwitches ; Check for Pause, Reset, Select JSR UpdateAllGameObjects ; Run all game object logic (players, enemies, eggs, etc.) JSR ESRoutineScheduler ; Run any scheduled events (lava rising, platform dissolving, etc.) JSR ManageMessageTimers ; Update the HUD string buffer with current scores/lives WaitForRender ; Wait here until the NMI has finished processing the previous frame's render list. ; This synchronizes the main logic thread with the VBlank/NMI thread. LDA RenderListDirty BNE WaitForRender JSR DisplayRoutineInit ; Prepare the render list for the upcoming frame JMP MainGameLoop_CheckState ; Loop back to the start of the main logic RestartGameFromMenu LDX #$FF ; Reset the stack pointer TXS JMP StartNewGameFromMenu ; Jump to start a new game ResetStackAndDisplayGameOptions LDX #$FF TXS JMP DisplayGameOptions ResetStackAndStartGameInDemoMode LDX #$FF TXS JMP StartGameInDemoMode InitializeNewGame SEI LDA #$60 STA CTRL JSR ClearRamMuteAudio JSR LoadGamePalette JSR SetColorRegisters JSR ResetMessageDisplayFlags JSR UpdateDLWithBackgroundSprites WaitForVblankEnd BIT MSTAT BMI WaitForVblankEnd WaitForVblankStart BIT MSTAT BPL WaitForVblankStart LDA #$57 STA DPPL LDA #$27 STA DPPH LDA #$40 STA CTRL JSR InitPlayerLivesAndBonus JSR SpawnInitialPlayerBirds JSR InitializeSpawnPlatformStates LDA #$FF STA GameEndDelayTimer LDA #$10 STA BridgeBurningWidth LDA #$0A STA ESRoutineIndex+9 LDA #$FF STA OldPlatformPresentBitmask LDA #$01 STA LevelBCD STA IsEggWave STA PterryCountdownHi JSR DisplayLevelStartMsg LDA DemoMode BNE DisplayGameStartMsg LDA #$01 ; "prepare to joust" JSR DisplayGameMessage LDA #$12 STA ESRoutineIndex+$0D LDA #SFX_GameStart JSR ScheduleSFX JSR ClearScores DisplayGameStartMsg JSR UpdateScoreDisplay LDX #$01 ; "prepare to joust" JSR UpdatePlayerLivesDisplayed DEX ; "Wave #" JMP UpdatePlayerLivesDisplayed DisplayLevelStartMsg JSR UpdateAIParametersForLevel JSR DisplayGameStartMsg JSR SetAnyPterrysToLeaving LDA #$00 ; "Wave #" JMP DisplayGameMessage AwardEndOfWaveBonuses LDA GladiatorWaveFlag BEQ CheckForTeamWaveBonus LDA PlayerWasGladiator BNE DisplayNoGladiatorBonusMessage LDA #$0E ; "3000 gladiator" JSR DisplayGameMessage JMP FinalizeGladiatorBonus DisplayNoGladiatorBonusMessage LDA #$12 ; "no gladiator" JSR DisplayGameMessage FinalizeGladiatorBonus LDA #$00 STA PlayerWasGladiator STA GladiatorWaveFlag JMP DisplayPointsAwardedMessage CheckForTeamWaveBonus LDA TeamWaveFlag BEQ CheckForSurvivalWaveBonus LDA PlayersWereATeam BEQ DisplayNoTeamBonusMessage LDA #$10 STA ESRoutineIndex+$0C LDA #$03 STA Temp61ScoreAdd LDA #$00 STA Temp62ScoreAdd LDX #$00 JSR UpdatePlayerScoreAndBonus LDX #$01 JSR UpdatePlayerScoreAndBonus LDA #$0D ; "3000 team" JSR DisplayGameMessage JMP DisplayPointsAwardedMessage DisplayNoTeamBonusMessage LDA #$11 ; "no team" JSR DisplayGameMessage JMP DisplayPointsAwardedMessage CheckForSurvivalWaveBonus LDA SurvivalWaveFlag BEQ ExitWaveBonusChecks LDA LevelWasSurvived BEQ DisplayNoSurvivalBonusMessage LDA #$10 STA ESRoutineIndex+$0C LDA #$03 STA Temp61ScoreAdd LDA #$00 STA Temp62ScoreAdd LDX #$00 JSR UpdatePlayerScoreAndBonus LDA #$0C ; "3000 survival" JSR DisplayGameMessage JMP DisplayPointsAwardedMessage DisplayNoSurvivalBonusMessage LDA #$10 ; "no survival" JSR DisplayGameMessage DisplayPointsAwardedMessage LDA #$0F ; "points awarded" JMP DisplayGameMessage ExitWaveBonusChecks RTS SetupNextLevel LDA GameActiveFlag BNE ExitWaveBonusChecks TXA PHA TYA PHA JSR SetAnyPterrysToLeaving JSR AwardEndOfWaveBonuses INC Level LDA Level CMP #$28 BMI SkipLevelRepeat LDA #$20 ; Levels greater than $28 repeat levels $20-$28 STA Level SkipLevelRepeat LDA LevelBCD ; adjust the BCD level BEQ IncrementLevelBCD SED CLC ADC #$01 CLD STA LevelBCD IncrementLevelBCD LDA Level CMP #$01 BNE SetupNextLevelCheckWave2 LDA #$0C STA ESRoutineIndex+$0A JMP FinalizeNextLevelSetup SetupNextLevelCheckWave2 CMP #$02 BNE FinalizeNextLevelSetup LDA #$0E STA ESRoutineIndex+$0B FinalizeNextLevelSetup LDA ESRoutineIndex+$0C BNE SkipResettingWaveEndTimer LDA #$10 STA ESRoutineIndex+$0C SkipResettingWaveEndTimer PLA TAY PLA TAX RTS UpdateAIParametersForLevel LDA #$AE SEC SBC Level STA TrollMinimumGrabYCoord SBC #$18 STA TrollMinimumTargetYCoord LDA Level CLC ADC Difficulty ADC Difficulty ASL ADC #$0A ; A = (2 * LEVEL) + (4 * Difficulty) + 10 STA TrollPullingVelocity ASL BCS AnimateTitleScreen ASL AnimateTitleScreen EOR #$FF STA EnemyAITargetDelayBase LDA Difficulty BNE SetAIParamsForNormalOrHarder LDA #$03 STA Temp5E LDA #$02 STA Temp5F LDA #$07 STA Temp60 LDA #$08 STA Temp61 LDA #$02 STA Temp62 LDA #$01 STA Temp63 LDA #$08 STA Temp64 LDA #$09 STA Temp65 JMP StoreCalculatedAIPhysicsParameters SetAIParamsForNormalOrHarder LDA #$02 STA Temp5E LDA #$01 STA Temp5F LDA #$08 STA Temp60 LDA #$09 STA Temp61 LDA #$01 STA Temp62 LDA #$00 STA Temp63 LDA #$09 STA Temp64 LDA #$0A STA Temp65 StoreCalculatedAIPhysicsParameters LDA Level CMP #$02 BCS SetAIPhysicsForHigherLevels LDA Temp5E STA BirdPhysicsIndexMaxByType STA BirdPhysicsIndexMaxByType+1 STA BirdPhysicsIndexMaxByType+2 LDA Temp5F STA BirdPhysicsIndexMaxByType+3 STA BirdPhysicsIndexMaxByType+4 LDA Temp60 STA BirdPhysicsIndexMinByType STA BirdPhysicsIndexMinByType+1 STA BirdPhysicsIndexMinByType+2 LDA Temp61 STA BirdPhysicsIndexMinByType+3 STA BirdPhysicsIndexMinByType+4 JMP ResetWaveBonusFlags SetAIPhysicsForHigherLevels LDA Temp62 STA BirdPhysicsIndexMaxByType STA BirdPhysicsIndexMaxByType+1 STA BirdPhysicsIndexMaxByType+2 STA BirdPhysicsIndexMaxByType+3 LDA Temp63 STA BirdPhysicsIndexMaxByType+4 LDA Temp64 STA BirdPhysicsIndexMinByType STA BirdPhysicsIndexMinByType+1 STA BirdPhysicsIndexMinByType+2 STA BirdPhysicsIndexMinByType+3 LDA Temp65 STA BirdPhysicsIndexMinByType+4 ResetWaveBonusFlags LDA #$00 STA LevelWasSurvived STA PlayersWereATeam STA PlayerWasGladiator STA SurvivalWaveFlag STA TeamWaveFlag STA GladiatorWaveFlag STA PterryWave LDA Level AND #$03 BNE ProcessNonEggWaveSetup LDA IsEggWave BNE ProcessNonEggWaveSetup LDA #$01 STA IsEggWave LDA #$03 ; "Egg Wave" JSR DisplayGameMessage LDA #$0F STA PlatformsInLevel LDA Level ; Level (range from 0 to 40) LSR ; LSR ; TAX ; X=Level/4 (range from 0 to 10) LDA MaxEnemyBirdCountLUT,X STA MaxEnemyBirdCount LDA EggWaveEnemyTypeLUT,X STA EggWaveEnemyType DEC Level JMP FinalizeWaveSetupAndInitPlatforms ProcessNonEggWaveSetup LDA #$00 STA IsEggWave LDX #$01 LDA Level CMP #$04 BMI CheckForTeamWave AND #$03 CMP #$02 BNE CheckForTeamWave LDY Difficulty BEQ CheckForTeamWave STX PterryWave LDA #$05 ; "Pterry Wave" JSR DisplayGameMessage JMP MessageDisplayDone CheckForTeamWave LDY P0Lives BMI CheckForSurvivalWave LDY P1Lives BMI CheckForSurvivalWave CMP #$01 BNE CheckForGladiatorWave STX PlayersWereATeam STX TeamWaveFlag LDA #$07 ; "Team Wave" JSR DisplayGameMessage JMP MessageDisplayDone CheckForGladiatorWave CMP #$03 BNE MessageDisplayDone STX PlayerWasGladiator STX GladiatorWaveFlag LDA #$04 ; "Gladiator Wave" JSR DisplayGameMessage JMP MessageDisplayDone CheckForSurvivalWave CMP #$01 BNE MessageDisplayDone STX LevelWasSurvived STX SurvivalWaveFlag LDA #$06 ; "Survival Wave" JSR DisplayGameMessage MessageDisplayDone LDA #$08 STA MaxEnemyBirdCount LDX Level LDA PlatformsInLevelLUT,X STA PlatformsInLevel LDY #$00 LDA Difficulty ASL ASL CLC ADC Level TAX STA Temp5E LDA EnemyWaveDataLUT_A,X JSR PopulateEnemyTypesForWave LDX Temp5E LDA EnemyWaveDataLUT_B,X JSR PopulateEnemyTypesForWave FindNextValidEnemyTypeInWaveData DEY LDA EnemyBirdTypesForLevel,Y CMP #$03 BEQ FindNextValidEnemyTypeInWaveData STY MaxActiveEnemyIndex FinalizeWaveSetupAndInitPlatforms LDA #$14 STA ESRoutineIndex+$11 LDA #$00 STA PlatformPresentBitmask LDA PlatformsInLevel CLC AND #$08 BEQ SetupPlatformsProcessTopWrapBit SEC SetupPlatformsProcessTopWrapBit ROL PlatformPresentBitmask SEC ROL PlatformPresentBitmask SEC ROL PlatformPresentBitmask SEC ROL PlatformPresentBitmask CLC LDA PlatformsInLevel AND #$02 STA SpawnPlatformDissolved3 BEQ SetupPlatformsProcessTopCenterPlatform SEC SetupPlatformsProcessTopCenterPlatform ROL PlatformPresentBitmask CLC LDA PlatformsInLevel AND #$01 BEQ SetupPlatformsProcessBottomLeftWrapBit SEC SetupPlatformsProcessBottomLeftWrapBit ROL PlatformPresentBitmask CLC LDA PlatformsInLevel AND #$01 BEQ SetupPlatformsProcessBottomRightWrapBit SEC SetupPlatformsProcessBottomRightWrapBit ROL PlatformPresentBitmask LDA PlatformPresentBitmask AND #$40 BEQ HandlePlatform0Removal LDA OldPlatformPresentBitmask AND #$40 BNE ContinuePlatformSetupCheckPlatform4 LDA #$C0 STA $1D45 LDA #$37 STA Platform0XCoordinate LDA #$17 STA Platform0PaletteWidth LDA #$17 STA Platform0GfxLo JMP ContinuePlatformSetupCheckPlatform4 HandlePlatform0Removal LDA OldPlatformPresentBitmask AND #$40 BEQ ContinuePlatformSetupCheckPlatform4 LDA #SFX_PlatformDissolve JSR ScheduleSFX LDA #$3E STA ESRoutineIndex+$10 ContinuePlatformSetupCheckPlatform4 LDA PlatformPresentBitmask AND #$04 BEQ HandlePlatform4RemovalOrNoChange LDA OldPlatformPresentBitmask AND #$04 BNE SetupPlatformsContinueAfterPlatform4 LDA #$A8 STA $1A6F LDA #$2E STA Platform4XCoordinate LDA #$14 STA Platform4PaletteWidth LDA #$AA STA Platform4GfxLo JMP SetupPlatformsContinueAfterPlatform4 HandlePlatform4RemovalOrNoChange LDA OldPlatformPresentBitmask AND #$04 BEQ SetupPlatformsContinueAfterPlatform4 LDA #SFX_PlatformDissolve JSR ScheduleSFX LDA #$1C STA ESRoutineIndex+$0E SetupPlatformsContinueAfterPlatform4 LDA PlatformPresentBitmask AND #$02 BEQ SetupPlatforms_HandleTopWrappedPlatformRemoval LDA OldPlatformPresentBitmask AND #$02 BNE FinalizeWavePlatformSetup LDA #$A0 STA $1A15 LDA #$00 STA Platform5XCoordinate LDA #$1B STA Platform56PaletteWidth LDA #$FB STA Platform56GfxLo JMP FinalizeWavePlatformSetup SetupPlatforms_HandleTopWrappedPlatformRemoval LDA OldPlatformPresentBitmask AND #$02 BEQ FinalizeWavePlatformSetup LDA #SFX_PlatformDissolve JSR ScheduleSFX LDA #$2D STA ESRoutineIndex+$0F FinalizeWavePlatformSetup LDA PlatformPresentBitmask STA OldPlatformPresentBitmask RTS PopulateEnemyTypesForWave STA Temp5F LDX #$03 UnpackEnemyTypeDataLoop LDA #$00 ASL Temp5F ROL ASL Temp5F ROL STA EnemyBirdTypesForLevel,Y INY DEX BPL UnpackEnemyTypeDataLoop RTS ClearRamMuteAudio ; zero ZP $60 to $FF LDA #$00 LDX #$A0 ClearMoreZPRamLoop STA $5F,X DEX BNE ClearMoreZPRamLoop ; zero $140 to $1F7 LDA #$00 LDX #$B8 ClearRamMuteAudioLoop1 STA $013F,X DEX BNE ClearRamMuteAudioLoop1 LDA #$18 STA Temp5F LDA #$00 STA Temp5E ; ($5E) = $1800 LDA #$00 ; value to store in LDX #$08 ; 8 pages of ram. JSR MemSet ; ie. zero ram from $1800 to $1FFF ; zero $2000 to $203F LDA #$00 LDX #$40 ClearRamMuteAudioLoop2 STA $1FFF,X DEX BNE ClearRamMuteAudioLoop2 ; zero $2100 to $213F LDA #$00 LDX #$40 ClearRamMuteAudioLoop3 STA $20FF,X DEX BNE ClearRamMuteAudioLoop3 LDA #$22 STA Temp5F LDA #$00 STA Temp5E ; ($5E) = $2200 LDA #$00 ; value to store in LDX #$05 ; 5 pages of ram. JSR MemSet ; i.e. zero ram from $2200 to $26FF LDA #$FF STA P0CurrentFire JSR MuteAudio RTS SystemHardwareInit LDA #$00 LDX #$20 ; zero $40-$5F... ClearSomeZPLoop STA $3F,X DEX BNE ClearSomeZPLoop LDA #$27 STA Temp5F LDA #$00 STA Temp5E ; ($5E) = $2700 LDA #$00 ; value to store in LDX #$01 ; 1 page of ram. JSR MemSet ; ie. zero ram from $1800 to $18FF JSR ClearRamMuteAudio JSR InitializeFinalDisplayListPointers LDA #$00 STA SWACNT STA SWBCNT STA $0284 LDA #$C8 STA CHARBASE LDA #$01 STA Difficulty STA INPTCTRL RTS ResetMessageDisplayFlags LDA #$FF LDX #$07 ResetMessageFlagsLoop STA $2038,X DEX BPL ResetMessageFlagsLoop RTS InitializeSpawnPlatformStates LDA #$01 STA SpawnPlatformDissolved0 STA SpawnPlatformDissolved1 STA SpawnPlatformDissolved2 STA SpawnPlatformDissolved3 RTS LoadGamePalette LDX #$17 LoadGamePaletteLoop LDA GamePalette,X STA PaletteInRam,X DEX BPL LoadGamePaletteLoop RTS LoadTitlePalette LDX #$17 LoadTitlePaletteLoop LDA TitlePalette,X STA PaletteInRam,X DEX BPL LoadTitlePaletteLoop RTS ClearScores LDX #$02 LDA #$00 ClearScoresLoop STA P0Score,X STA P1Score,X DEX BPL ClearScoresLoop RTS MemSet LDY #$00 MemSetLoop STA (Temp5E),Y DEY BNE MemSetLoop INC Temp5F DEX BNE MemSetLoop RTS InitializeWave LDA #$00 STA P0EggPointLevel STA P1EggPointLevel JSR UpdatePterryRespawnTimer LDX #$03 ClearPlayerWaveStartVariablesLoop STA UnusedPlayerStateArray,X STA TempSpawnUnsafeCounter,X DEX BPL ClearPlayerWaveStartVariablesLoop LDA #$01 LDX #$02 ResetPterryWaveAggressionFlagsLoop STA PterryAgressionFlag,X DEX BPL ResetPterryWaveAggressionFlagsLoop LDA IsEggWave BEQ SetupStandardEnemyWave RTS SetupStandardEnemyWave LDX MaxActiveEnemyIndex STX EnemyBirdCount INC EnemyBirdCount SpawnNextEnemyBirdLoop LDA EnemyBirdTypesForLevel,X INX INX STA ObjectBirdLevelAndType,X JSR SpawnNewBird DEX DEX DEX BPL SpawnNextEnemyBirdLoop LDA PterryWave BEQ FinalizeStandardWaveSetup LDA #$05 STA PterryCountdownLo LDA #$00 STA PterryCountdownHi LDA #$02 STA PterryAgressionFlag LDA Level CMP #$0F BCC FinalizeStandardWaveSetup LDA #$02 STA PterryAgressionFlag+1 FinalizeStandardWaveSetup RTS SpawnInitialPlayerBirds LDX PlayerCount SpawnNextPlayerBirdLoop LDA DemoMode BNE SetInitialPlayerBirdTypeForDemo LDA #$03 JMP StoreInitialPlayerBirdType SetInitialPlayerBirdTypeForDemo LDA #$01 StoreInitialPlayerBirdType STA ObjectBirdLevelAndType,X JSR SpawnNewBird LDA DemoMode BEQ SetPlayerSpawnPositionAndState LDA #$FF STA GameObjectAITimerHi,X SetPlayerSpawnPositionAndState LDA PlayerStartXLUT,X STA GameObjectXCoordHi,X LDA #$A0 ; Players start on the STA GameObjectYCoordHi,X ; the bottom platform. LDA #$04 ; Set alive state STA GameObjectState,X LDA #$00 STA P0FireDebounce,X DEX BPL SpawnNextPlayerBirdLoop RTS PlayerStartXLUT .byte $46, $78 UpdatePterryRespawnTimer LDA DemoMode BEQ SetPterryRespawnTimerNormalPlay LDA #$B0 STA PterryCountdownLo LDA #$01 STA PterryCountdownHi RTS SetPterryRespawnTimerNormalPlay JSR CalculateLevelDifficultyRandomTimer ROL Temp5E ROL Temp5F LDA Temp5E ADC #$80 STA PterryCountdownLo LDA Temp5F ADC #$00 STA PterryCountdownHi RTS UpdateAllGameObjects LDA P0SkidDirection ORA P1SkidDirection BNE ProcessGameObjectsMain LDA #$0F ; skid sound effect JSR SilenceSFXIfPlaying ProcessGameObjectsMain JSR RunPterryCountdown LDX #$18 ; last egg object EggProcessingLoop JSR RunEggObjectProcessing DEX CPX #$0D ; first egg object BCS EggProcessingLoop ; X is holding $0C, the last ptery object index PterryProcessingLoop JSR RunPterryProcessing DEX CPX #$0A ; first ptero object BCS PterryProcessingLoop LDX #$09 AllBirdsProcessingLoop ; (player and enemy birds) JSR RunAllBirdsProcessing DEX BPL AllBirdsProcessingLoop JSR TrollAiLogic RTS SpawnNewBird LDA InitialBirdDirection,X STA GameObjectDirection,X LDA #$00 STA GameObjectChargingTimer,X STA GameObjectFootstepAnimTimer,X STA GameObjectFootstepAnimIndex,X STA GameObjectYVelocityLo,X STA GameObjectYVelocityHi,X STA GameObjectYCoordLo,X STA GameObjectXCoordLo,X STA GameObjectXVelocity,X STA GameObjectInAir,X STA GameObjectPlatformSkipState,X STA GameObjectSkidDirection,X STA GameObjectXCoordHi,X STA GameObjectYCoordHi,X STA GameObjectAITargetDelayTimer,X LDA #$02 STA GameObjectAnimationFrame,X LDA ObjectBirdLevelAndType,X ; A = 0 to 2 (excluding pterry) ASL ; A = 0 to 4 ASL ; A = 0 to 8 CLC ADC Difficulty ; A = 0 to 11 TAY LDA AIModeByBirdTypeAndDifficultyLUT,Y CMP Level BCS StoreCalculatedAIMode LDA #$00 StoreCalculatedAIMode STA GameObjectAIMode,X LDA #$01 STA GameObjectAlive,X LDA #$03 STA GameObjectTimerResetValue,X STA GameObjectEventTimer1,X LDA #$03 ; state=born1 STA GameObjectState,X LDA #$1E STA GameObjectCountdownLo,X LDA Level CMP #$40 BCC ClampLevelTo64 LDA #$40 ClampLevelTo64 LSR CLC ADC Difficulty STA Temp66 CMP #$04 BCC ClampTurnTimerIndex LDA #$03 ClampTurnTimerIndex STA TempCollisionOverlap LDA ObjectBirdLevelAndType,X ASL ASL CLC ADC TempCollisionOverlap STA GameObjectTurnTimerIndex,X TAY JSR ReturnRandInA AND #$7F CLC ADC TurnCheckTimerValuesLoLUT,Y STA GameObjectTurnCheckTimerLo,X LDA TurnCheckTimerValuesHiLUT,Y ADC #$00 STA GameObjectTurnCheckTimerHi,X LDA Temp66 CMP #$08 BCC StoreCalculatedAITimers LDA #$07 StoreCalculatedAITimers TAY LDA AITimerByBirdTypeAndDifficultyLoLUT,Y STA GameObjectAITimerLo,X LDA AITimerByBirdTypeAndDifficultyHiLUT,Y STA GameObjectAITimerHi,X RTS RunAllBirdsProcessing LDA GameObjectState,X BNE BirdIsAlive RTS BirdIsAlive CMP #$03 ; ** 3 is the bird init first state "born1" BNE BirdIsPastInit DEC GameObjectCountdownLo,X ; ** delay before next init state BPL ExitAllBirdsProcessing1 LDA #$07 ; ** 7 is the bird init second state "born2" STA GameObjectState,X ExitAllBirdsProcessing1 RTS BirdIsPastInit LDA GameObjectInAir,X BNE NOPBranch ; pointless NOPBranch LDA GameObjectState,X CMP #$06 ; Is bird invincible? BNE BirdIsntInvincible JMP BirdBorn1Processing BirdIsntInvincible CMP #$07 ; Is bird on second init stage? BNE BirdIsntInit2 JMP BirdBorn2Processing BirdIsntInit2 ; if we're here, the bird state must be regular(4) or riderless($14) CPX #$02 ; players are the first 2 objects BCC PlayerBirdLogic ; If it's an Enemy Bird then fall-through JSR AutoPilotBirdLogic JMP ProcessCommonBirdPhysicsAndCollisions PlayerBirdLogic JSR PlayerHitLogic LDA GameObjectAlive,X BEQ ProcessBirdPhysicsCommon JSR HandlePlayerVsPterry ProcessCommonBirdPhysicsAndCollisions LDA GameObjectAlive,X BEQ ProcessBirdPhysicsCommon JSR ProcessBirdToBirdCollisionLoop ProcessBirdPhysicsCommon JSR ProcessBirdPlatformInteraction JSR UpdateAirborneObjectPhysics LDA GameObjectInAir,X BEQ ProcessOnPlatformBirdLogic RTS ProcessOnPlatformBirdLogic LDA GameObjectSkidDirection,X BEQ ProcessOnPlatformMovement JMP ProcessSkidDeceleration ProcessOnPlatformMovement LDA GameObjectXVelocity,X BNE ProcessFootstepAnimation STA GameObjectFootstepAnimIndex,X RTS ProcessFootstepAnimation LDA GameObjectFootstepAnimTimer,X BEQ AdvanceFootstepAnimation DEC GameObjectFootstepAnimTimer,X RTS AdvanceFootstepAnimation LDA GameObjectXVelocity,X CLC BMI CalculateFootstepTimerFromAbsXVel EOR #$FF CLC ADC #$01 CalculateFootstepTimerFromAbsXVel ADC #$02 BMI AdvanceFootstepAnimSlowestSpeed STA GameObjectFootstepAnimTimer,X INC GameObjectFootstepAnimIndex,X LDA GameObjectFootstepAnimIndex,X CMP #$04 BCC FinishFootstepAnimationCycle LDA #SFX_PlayerFootstep JSR SilenceSFXIfPlaying LDA #SFX_PlayerFootstep JSR ScheduleSFX LDA #$00 STA GameObjectFootstepAnimIndex,X FinishFootstepAnimationCycle RTS AdvanceFootstepAnimSlowestSpeed CMP #$FF BNE FootstepAnim_Slow_DoubleFrameIncrement LDA #$00 STA GameObjectFootstepAnimTimer,X INC GameObjectFootstepAnimIndex,X LDA GameObjectFootstepAnimIndex,X CMP #$02 BNE FootstepAnim_Slowest_CheckCycleEnd INC GameObjectFootstepAnimIndex,X LDA GameObjectFootstepAnimIndex,X FootstepAnim_Slowest_CheckCycleEnd CMP #$04 BCC FootstepAnim_Slowest_FinishFrame LDA #SFX_PlayerFootstep JSR SilenceSFXIfPlaying LDA #SFX_PlayerFootstep JSR ScheduleSFX LDA #$00 STA GameObjectFootstepAnimIndex,X FootstepAnim_Slowest_FinishFrame RTS FootstepAnim_Slow_DoubleFrameIncrement LDA #$00 STA GameObjectFootstepAnimTimer,X INC GameObjectFootstepAnimIndex,X INC GameObjectFootstepAnimIndex,X LDA GameObjectFootstepAnimIndex,X CMP #$04 BCC FootstepAnim_Slow_FinishFrame LDA #SFX_PlayerFootstep JSR SilenceSFXIfPlaying LDA #SFX_PlayerFootstep JSR ScheduleSFX LDA #$00 STA GameObjectFootstepAnimIndex,X FootstepAnim_Slow_FinishFrame RTS ProcessSkidDeceleration LDA GameObjectChargingTimer,X BEQ ApplySkidDeceleration DEC GameObjectChargingTimer,X RTS ApplySkidDeceleration LDA GameObjectXVelocity,X BMI ApplyNegativeVelocitySkidDeceleration DEC GameObjectXVelocity,X JMP ContinueSkidDeceleration ApplyNegativeVelocitySkidDeceleration INC GameObjectXVelocity,X ContinueSkidDeceleration LDA GameObjectXVelocity,X BEQ FinalizeSkidBirdStopped LDA #$04 STA GameObjectChargingTimer,X RTS FinalizeSkidBirdStopped JSR ClearSkidStateAndSound RTS BirdBorn1Processing DEC BirdInvulnerable,X BMI StartSpawnAnimationSequence RTS StartSpawnAnimationSequence LDY GameObjectHunterIndex,X LDA BirdSpawnInvulnAnimStateSequence_TypeA,Y CMP #$00 BNE DispatchSpawnAnimationState DEC GameObjectYCoordHi,X JMP AdvanceSpawnAnimationState DispatchSpawnAnimationState CMP #$01 BNE PlayerAirSteering CPX #$02 BCS HandleEnemyBirdSpawnAnimationState ; branch if non-player enemy bird LDA #SFX_Invulnerable JSR ScheduleSFX JMP AdvanceSpawnAnimationState HandleEnemyBirdSpawnAnimationState LDA #$00 STA EnemyIsSpawning JMP SpawnAnim_FinalizeAndSetStateNormal ProcessSpawnAnimationOrPlayerSteering JSR SpawnAnim_FinalizeAndSetStateNormal JMP PlayerBirdLogic PlayerAirSteering LDA P0CurrentFire,X BPL ProcessSpawnAnimationOrPlayerSteering ; Only when the player bird flaps LDA SWCHA CPX #$00 BEQ SkipJoystickShift ASL ASL ; Shift the lower j1 nibble into ASL ; the higher j0 nibble postition ASL SkipJoystickShift ASL BCC ProcessSpawnAnimationOrPlayerSteering ; Right ASL BCC ProcessSpawnAnimationOrPlayerSteering ; Left ASL BCC ProcessSpawnAnimationOrPlayerSteering ; Down ASL BCC ProcessSpawnAnimationOrPlayerSteering ; Up LDA BirdSpawnInvulnAnimStateSequence_TypeA,Y CMP #$02 BNE CheckSpawnAnimState3 JSR SetPlayerSpawnInvulnerablePalette LDA #$9C STA Temp60PaletteAndWidth LDA #$BA STA Temp61 LDA #$7E STA Temp62 LDA BirdPaletteAndWidthLUT,X STA Temp63 JSR UpdatePlatformDLWithSpawnedBirdGfx JMP AdvanceSpawnAnimationState CheckSpawnAnimState3 CMP #$03 BNE SpawnAnimCheckState4 JSR SetPlayerPaletteInRam LDA #$9C STA Temp60PaletteAndWidth LDA #$BA STA Temp61 LDA RiderPaletteAndWidthLUT,X STA Temp62 LDA BirdPaletteAndWidthLUT,X STA Temp63 JSR UpdatePlatformDLWithSpawnedBirdGfx JMP AdvanceSpawnAnimationState SpawnAnimCheckState4 CMP #$04 BNE SpawnAnim_CheckState5 JSR SetPlayerSpawnInvulnerablePalette LDA #$7C STA Temp60PaletteAndWidth LDA SpawnRiderPaletteAndWidthLUT,X STA Temp61 LDA BirdPaletteAndWidthLUT,X STA Temp62 STA Temp63 JSR UpdatePlatformDLWithSpawnedBirdGfx JMP AdvanceSpawnAnimationState SpawnAnim_CheckState5 CMP #$05 BNE SpawnAnim_CheckState6 JSR SetPlayersSpawnPalette LDA #$9C STA Temp60PaletteAndWidth LDA #$BA STA Temp61 LDA RiderPaletteAndWidthLUT,X STA Temp62 LDA BirdPaletteAndWidthLUT,X STA Temp63 JSR UpdatePlatformDLWithSpawnedBirdGfx JMP AdvanceSpawnAnimationState SpawnAnim_CheckState6 CMP #$06 BNE SpawnAnim_FinalizeAndSetStateNormal JSR SetPlayerSpawnInvulnerablePalette LDA #$5C STA Temp60PaletteAndWidth LDA #$BA STA Temp61 LDA BirdPaletteAndWidthLUT,X STA Temp62 STA Temp63 JSR UpdatePlatformDLWithSpawnedBirdGfx JMP AdvanceSpawnAnimationState SpawnAnim_FinalizeAndSetStateNormal CPX #$02 BCS FinalizeBirdSpawnAndSetState ; branch if non-player enemy bird LDA #$0A ; player invulnerable sound effect JSR SilenceSFXIfPlaying FinalizeBirdSpawnAndSetState LDA #$04 STA GameObjectState,X LDA P0CurrentFire,X EOR #$FF STA P0FireDebounce,X LDA #$00 STA GameObjectYVelocityLo,X STA GameObjectYVelocityHi,X JSR SetPlayersSpawnPalette LDA #$5C STA Temp60PaletteAndWidth LDA #$BA STA Temp61 LDA RiderPaletteAndWidthLUT,X STA Temp62 LDA BirdPaletteAndWidthLUT,X STA Temp63 JMP UpdatePlatformDLWithSpawnedBirdGfx AdvanceSpawnAnimationState LDA BirdSpawnInvulnAnimStateSequence_TypeB,Y STA BirdInvulnerable,X INC GameObjectHunterIndex,X RTS BirdBorn2Processing CPX #$02 BCC PlayerBorn2 ; branch if it's a player bird LDA EnemyIsSpawning BEQ CheckForPterryBeforeSpawning DelaySpawnIfAnotherEnemySpawning RTS PlayerBorn2 LDA P0Lives,X BPL ProceedWithSpawnSafetyCheck RTS CheckForPterryBeforeSpawning LDA PterryState1 ORA PterryState2 ORA PterryState3 BEQ ProceedWithSpawnSafetyCheck RTS ProceedWithSpawnSafetyCheck JSR SpawnPointSafetyCheck LDA Temp60 BMI DelaySpawnIfAnotherEnemySpawning CPX #$02 BCC SpawnPlayerBird ; branch if it's a player bird LDA #$01 STA EnemyIsSpawning SpawnPlayerBird LDA #$01 STA GameObjectAlive,X LDA $60 STA GameObjectSpawnPlatformIndex,X TAY LDA PlayerRespawnX,Y STA GameObjectXCoordHi,X LDA PlayerRespawnY,Y STA GameObjectYCoordHi,X LDA #$06 STA GameObjectState,X LDA #$00 STA GameObjectInAir,X STA GameObjectHunterIndex,X STA GameObjectXVelocity,X STA BirdInvulnerable,X LDA BirdBornSFXType,X ; different sounds for birds being born, JSR ScheduleSFX ; depending on it being a player or enemy. JSR SetPlayerPaletteInRam LDA SpawnPlatformPaletteAndWidthLUT,X STA Temp60PaletteAndWidth LDA SpawnRiderPaletteAndWidthLUT,X STA Temp61 LDA SpawnBirdPaletteAndWidthLUT,X STA Temp62 STA Temp63 UpdatePlatformDLWithSpawnedBirdGfx LDY GameObjectSpawnPlatformIndex,X LDA SpawnPlatformDLObjectLoLUT,Y STA Temp5EGfxDataLo LDA SpawnPlatformDLObjectHiLUT,Y STA Temp5FGfxDataHi LDY #$01 LDA Temp60PaletteAndWidth STA (Temp5E),Y DEY LDA Temp61 STA (Temp5E),Y LDA Temp62 STA RiderObjectPaletteAndWidth,X LDA Temp63 STA BirdObjectPaletteAndWidth,X RTS SetPlayerPaletteInRam CPX #$00 BNE SetPlayer1Palette LDA #$1E STA P5C1_Ram STA P5C2_Ram STA P5C3_Ram JMP UpdatePlayerLivesDisplayed SetPlayer1Palette CPX #$01 BNE SetPaletteHandleEnemyBird LDA #$BC STA P6C1_Ram STA P6C2_Ram STA P6C3_Ram JMP UpdatePlayerLivesDisplayed SetPaletteHandleEnemyBird LDA #$0D STA P4C1_Ram STA P4C3_Ram RTS SetPlayerSpawnInvulnerablePalette LDA #$0D CPX #$00 BNE SetSpawnInvulnPalette_HandlePlayer1 STA P5C1_Ram STA P5C2_Ram STA P5C3_Ram RTS SetSpawnInvulnPalette_HandlePlayer1 STA P6C1_Ram STA P6C2_Ram STA P6C3_Ram RTS SetPlayersSpawnPalette CPX #$00 BNE SetPlayer1SpawnPalette SetPlayer0SpawnPalette LDA #$15 STA P5C1_Ram LDA #$A9 STA P5C2_Ram LDA #$85 STA P5C3_Ram RTS SetPlayer1SpawnPalette CPX #$01 BNE SetEnemySpawnPalette LDA #$0D STA P6C1_Ram LDA #$1C STA P6C2_Ram LDA #$44 STA P6C3_Ram RTS SetEnemySpawnPalette LDA #$39 STA P4C1_Ram LDA #$33 STA P4C3_Ram RTS PlayerHitLogic LDA P0Lives,X BPL ProcessActivePlayerLogic LDA GameObjectState,X CMP #$05 BEQ ProcessActivePlayerLogic LDA #$00 STA GameObjectState,X RTS ProcessActivePlayerLogic LDA GameObjectAlive,X BNE ProcessActivePlayerCollisionsAndInput JMP AutoPilotBirdLogic ProcessActivePlayerCollisionsAndInput JSR CheckPlayerEggCollision LDA DemoMode BEQ ProcessPlayerInput JMP AutoPilotBirdLogic ProcessPlayerInput LDA #$00 STA Temp5E LDA P0CurrentFire,X STA Temp5F CMP P0FireDebounce,X BEQ ProcessPlayerJoystickInput STA P0FireDebounce,X LDA Temp5F BMI PlayerNoFlapResetAnimation LDA #$01 STA Temp5E LDY ObjectBirdLevelAndType,X JSR ApplyFlapPhysics LDA GameObjectSkidDirection,X BEQ ContinuePlayerInputAfterFlap JSR ClearSkidStateAndSound ContinuePlayerInputAfterFlap JMP ProcessPlayerJoystickInput PlayerNoFlapResetAnimation LDA #$00 STA GameObjectAnimationFrame,X ProcessPlayerJoystickInput LDA GameObjectInAir,X BNE ProcessAirbornePlayerInput LDA P0JoyDelay,X BEQ ResetOnPlatformJoyDelay DEC P0JoyDelay,X RTS ResetOnPlatformJoyDelay LDA #$04 STA P0JoyDelay,X ProcessAirbornePlayerInput LDA SWCHA CPX #$00 BEQ ProcessNormalizedJoystickInput ASL ASL ASL ASL ProcessNormalizedJoystickInput ASL BCC HandlePlayerJoyRight_PlatformOrAir ASL BCC HandlePlayerJoyLeft_PlatformOrAir RTS ;------------------------------------------------------------------------------ ; Player On-Platform Horizontal Movement & Airborne Steering Logic ; ; This section handles player joystick input (Left/Right). Its behavior differs ; based on whether the bird is on a platform or airborne. ; ; - Airborne: The joystick changes the bird's facing direction. If the fire ; button is also pressed (flapping), it applies horizontal acceleration. ; ; - On-Platform: The joystick controls walking. If the player reverses direction ; while moving above a certain speed, a "skid" is initiated. Pressing the ; opposite direction again will cancel the skid. ; ; Input: ; X = CurrentPlayer index (0 or 1) ; Temp5E (from outer context): Holds 1 if fire button was pressed this frame ; (flapping), 0 otherwise. ;------------------------------------------------------------------------------ HandlePlayerJoyLeft_PlatformOrAir LDA GameObjectInAir,X BEQ PlayerOnPlatform_JoyLeft_CheckVelocity ; If on platform, jump to on-platform logic. ; Bird is AIRBORNE with joystick LEFT LDA #Direction_Left ; Face left. STA GameObjectDirection,X LDY Temp5E ; Temp5E holds 1 if flapping, 0 if not. BEQ PlatformMovementOrAirborne_RTS1 ; If not flapping, just steer and exit. ; Fall through to accelerate if flapping in air. AccelerateBirdLeft_PlatformOrAir ; Shared target for airborne left flap & on-platform left acceleration. DEC GameObjectXVelocity,X ; Decrease X-velocity (move more left or less right). PlatformMovementOrAirborne_RTS1 RTS PlayerOnPlatform_JoyLeft_CheckVelocity ; On Platform, Joy Left: Check current X Velocity LDA GameObjectXVelocity,X BEQ BirdStopped_Platform_JoyLeft ; If X-velocity is 0, bird is stopped. BPL BirdMovingRight_Platform_JoyLeft ; If >0, bird moving/skidding right. ; Bird is already moving/skidding left (X-velocity is negative). BNE BirdMovingOrSkiddingLeft_Platform_JoyLeft ; Always taken if XVel < 0. BirdStopped_Platform_JoyLeft LDA GameObjectDirection,X ; Bird was stationary. Get current facing direction. BMI AccelerateBirdLeft_PlatformOrAir ; If already facing left ($FF), try to accelerate left. ; Else, was facing right ($01). LDA #Direction_Left ; Change direction to Left ($FF). STA GameObjectDirection,X PlatformMovementOrAirborne_RTS2 ; Also used as common RTS for some skid conditions. RTS BirdMovingRight_Platform_JoyLeft ; Bird was moving/skidding right, joystick now left. CMP #SKID_VELOCITY_THRESHOLD_RIGHT ; Compare current X-velocity with skid threshold. BCC BirdMovingOrSkiddingLeft_Platform_JoyLeft ; If VelX < Threshold (moving slowly right), don't skid. ; Attempt to move left (effectively braking then accelerating). ; Bird is moving right quickly enough to skid if direction changes. LDA GameObjectSkidDirection,X ; Is bird already skidding? BNE PlatformMovementOrAirborne_RTS2 ; Yes, already skidding (likely right): let skid resolve. RTS. ; Not skidding, but moving right quickly and joystick is left: Initiate SKID to the RIGHT. INC GameObjectYCoordHi,X ; Visual effect: bird hops up slightly when skidding starts. LDA #Direction_Right ; Set skid direction to RIGHT ($01) because we were moving right. STA GameObjectSkidDirection,X LDA #SKID_ANIMATION_FRAME ; Set animation to skid frame. STA GameObjectFootstepAnimIndex,X LDA #SFX_Skid ; Schedule skid sound effect. JMP ScheduleSFX BirdMovingOrSkiddingLeft_Platform_JoyLeft ; Arrived here if: (XVel < 0) OR (XVel > 0 but < SKID_THRESHOLD_RIGHT) LDA GameObjectSkidDirection,X ; Check if already skidding. BEQ AccelerateBirdLeft_PlatformOrAir ; Not skidding: try to accelerate left. ; Already skidding. BPL PlatformMovementOrAirborne_RTS2 ; Skidding right ($01), joy left (anti-skid): RTS. ; Skidding left ($FF), joy left (reinforce skid). JSR ClearSkidStateAndSound ; Clear the skid state (was skidding left, now actively moving left). JMP AccelerateBirdLeft_PlatformOrAir ; And try to accelerate left. HandlePlayerJoyRight_PlatformOrAir LDA GameObjectInAir,X BEQ PlayerOnPlatform_JoyRight_CheckVelocity ; If on platform, jump to on-platform logic. ; Bird is AIRBORNE with joystick RIGHT LDA #Direction_Right ; Face right. STA GameObjectDirection,X LDY Temp5E ; Temp5E has flap status (1 if flapping). BEQ PlatformMovementOrAirborne_RTS1 ; If not flapping, just steer and exit. ; Fall through to accelerate if flapping in air. AccelerateBirdRight_PlatformOrAir ; Shared target for airborne right flap & on-platform right acceleration. INC GameObjectXVelocity,X ; Increase X-velocity (move more right or less left). RTS PlayerOnPlatform_JoyRight_CheckVelocity ; On Platform, Joy Right: Check current X Velocity LDA GameObjectXVelocity,X BMI BirdMovingLeft_Platform_JoyRight ; If <0, bird moving/skidding left. BNE BirdMovingOrSkiddingRight_Platform_JoyRight ; If >0 (and non-zero), bird moving/skidding right. ; Bird is stopped (X-velocity is 0). BirdStopped_Platform_JoyRight LDA GameObjectDirection,X ; Get current facing direction. BPL AccelerateBirdRight_PlatformOrAir ; If already facing right ($01), try to accelerate right. ; Else, was facing left ($FF). LDA #Direction_Right ; Change direction to Right ($01). STA GameObjectDirection,X PlatformMovementOrAirborne_RTS4 ; Also used as common RTS for some skid conditions. RTS BirdMovingLeft_Platform_JoyRight ; Bird was moving/skidding left, joystick now right. CMP #SKID_VELOCITY_THRESHOLD_LEFT ; Compare current X-velocity with skid threshold (-2). BCS BirdMovingOrSkiddingRight_Platform_JoyRight ; If VelX >= Threshold (moving slowly left), don't skid. ; Attempt to move right (effectively braking then accelerating). ; Bird is moving left quickly enough to skid. LDA GameObjectSkidDirection,X ; Is bird already skidding? BNE PlatformMovementOrAirborne_RTS4 ; Yes, already skidding (likely left): let skid resolve. RTS. ; Not skidding, but moving left quickly and joystick is right: Initiate SKID to the LEFT. INC GameObjectYCoordHi,X ; Visual hop. LDA #Direction_Left ; Set skid direction to LEFT ($FF) because we were moving left. STA GameObjectSkidDirection,X LDA #SKID_ANIMATION_FRAME STA GameObjectFootstepAnimIndex,X LDA #SFX_Skid JMP ScheduleSFX BirdMovingOrSkiddingRight_Platform_JoyRight ; Arrived here if: (XVel > 0) OR (XVel < 0 but > SKID_THRESHOLD_LEFT) LDA GameObjectSkidDirection,X ; Check if already skidding. BEQ AccelerateBirdRight_PlatformOrAir ; Not skidding: try to accelerate right. ; Already skidding. BMI PlatformMovementOrAirborne_RTS4 ; Skidding left ($FF), joy right (anti-skid): RTS. ; Skidding right ($01), joy right (reinforce skid). JSR ClearSkidStateAndSound ; Clear skid state, now actively moving right. JMP AccelerateBirdRight_PlatformOrAir ; And try to accelerate right. EnemyBirdIsSeekingRider LDY GameObjectPreyIndex,X CMP #$14 BNE HunterBirdAICheckPrepareToSlideState LDA GameObjectDirection,X CMP GameObjectXVelocity,X BEQ HunterBirdAIContinueAfterVelocityUpdate ASL STA GameObjectXVelocity,X HunterBirdAIContinueAfterVelocityUpdate JSR DetermineAIActionBasedOnProximity LDY GameObjectPreyIndex,X LDA GameObjectYVelocityHi,X BEQ UpdateHunterBirdYPosition BMI HunterBirdMoveUpward LDA #$01 STA GameObjectYVelocityHi,X JMP UpdateHunterBirdYPosition HunterBirdMoveUpward LDA #$FF STA GameObjectYVelocityHi,X LDA GameObjectYVelocityLo,X BMI UpdateHunterBirdYPosition LDA #$80 STA GameObjectYVelocityLo,X UpdateHunterBirdYPosition LDA GameObjectYCoordHi,X CLC ADC #$06 CMP GameObjectYCoordHi,Y BCC HunterBirdDescendTowardRider DEC GameObjectYCoordHi,X HunterBirdDescendTowardRider LDY GameObjectPreyIndex,X LDA GameObjectXCoordHi,Y SEC SBC GameObjectXCoordHi,X BPL HunterBirdCheckXProximityToRider EOR #$FF CLC ADC #$01 HunterBirdCheckXProximityToRider CMP #$03 BCS HunterAIContinueSeekingRider LDA #$15 STA GameObjectState,X LDA #$0A STA GameObjectEventTimer1,X HunterAIContinueSeekingRider RTS HunterBirdAICheckPrepareToSlideState CMP #$15 BNE HunterBirdHandleSlidingState LDA GameObjectYCoordHi,Y SEC SBC #$06 CMP GameObjectYCoordHi,X BCS HunterBirdInitiateSlide HunterBirdRepositionAfterSlideFail LDA GameObjectDirection,X EOR #$FF CLC ADC #$01 STA GameObjectDirection,X LDA #$00 STA GameObjectTimerResetValue,X STA GameObjectEventTimer1,X LDA #$14 STA GameObjectState,X RTS HunterBirdInitiateSlide LDA #$0A STA GameObjectEventTimer1,X LDA GameObjectInAir,X BNE SkipHunterBirdSlideInitiation LDA #$16 STA GameObjectState,X LDA GameObjectDirection,X STA GameObjectSkidDirection,X INC GameObjectYCoordHi,X LDA #$04 ; riderless bird time to slide toward rider STA GameObjectChargingTimer,X SkipHunterBirdSlideInitiation RTS HunterBirdHandleSlidingState CMP #$16 BNE HunterBirdFinalApproach LDA GameObjectYCoordHi,Y SEC SBC #$06 CMP GameObjectYCoordHi,X BCS HunterSlideVerticalAlignOK JMP HunterBirdRepositionAfterSlideFail HunterSlideVerticalAlignOK LDA #$0A STA GameObjectEventTimer1,X LDA GameObjectXCoordHi,Y CMP GameObjectXCoordHi,X BNE HunterSlideContinueApproach JMP HunterBirdReachedRider HunterSlideContinueApproach LDA GameObjectSkidDirection,X BNE HunterSlideMaintainSkidDirection LDA GameObjectDirection,X EOR #$FF CLC ADC #$01 STA GameObjectDirection,X STA GameObjectXVelocity,X LDA #$17 STA GameObjectState,X HunterSlideMaintainSkidDirection RTS HunterBirdFinalApproach LDA GameObjectYCoordHi,Y SEC SBC #$06 CMP GameObjectYCoordHi,X BCS HunterBirdTargetStillValidContinueApproach JMP HunterBirdRepositionAfterSlideFail HunterBirdTargetStillValidContinueApproach LDA #$0A STA GameObjectEventTimer1,X LDA GameObjectDirection,X STA GameObjectXVelocity,X LDA GameObjectXCoordHi,Y CMP GameObjectXCoordHi,X BNE HunterBirdFinishRiderPickup HunterBirdReachedRider LDA #$FF STA GameObjectPreyIndex,X LDA #$01 STA GameObjectAlive,X LDA #$04 STA GameObjectState,X LDA #$0A STA GameObjectEventTimer1,X LDA #$04 STA GameObjectTimerResetValue,X LDA #$00 STA GameObjectXVelocity,X STA GameObjectAITimerLo,X STA GameObjectAITimerHi,X STA.w GameObjectState,Y DEC EggsPresentCount HunterBirdFinishRiderPickup RTS ;------------------------------------------------------------------------------ ; AutoPilotBirdLogic ; Handles AI for non-player-controlled birds (enemy birds, demo mode player birds). ; This is the main entry point for their AI processing each game cycle relevant ; to this logic. ; Input: X = GameObject index (bird) ;------------------------------------------------------------------------------ AutoPilotBirdLogic LDA GameObjectState,X CMP #State_BirdSeekingRider ; Is bird in State_BirdSeekingRider ($14)? ; This is a special state where an unridden enemy bird ; is actively seeking a hatched rider. BCC EnemyBirdHasRider_Or_IsNormalAI ; If state < $14, proceed to general AI or rider-attached logic. JSR EnemyBirdIsSeekingRider ; If state is $14 (or potentially higher, though unlikely), ; jump to its specialized AI handler. EnemyBirdHasRider_Or_IsNormalAI ; This label implies the bird either has a rider (and thus uses general AI) ; or is an AI bird not in the special "seeking rider" state. ; Check if the bird is on a platform and has stopped skidding or moving. LDA GameObjectInAir,X ; Is the bird in the air? BNE BirdAI_FlightPathAltitudeCheck ; - Yes, skip platform-specific idle movement. ; Bird is ON a PLATFORM. LDA GameObjectXVelocity,X ; Get current X velocity. BEQ BirdAI_OnPlatform_Stopped ; - If X velocity is zero, bird is stopped. LDA GameObjectSkidDirection,X ; Check if bird is skidding. BEQ BirdAI_FlightPathAltitudeCheck ; - If not skidding (but moving), proceed to altitude checks. ; This implies moving non-skidding birds on platforms still use some airborne AI logic. RTS ; - Bird is skidding on a platform, AI takes no further action this frame. BirdAI_OnPlatform_Stopped ; Bird is on a platform and X-velocity is zero. ; Make it pace back and forth slightly if it's an AI bird. LDA GameObjectXVelocity,X ; Re-load X-velocity (will be $00 here). CLC ADC GameObjectDirection,X ; Add current facing direction to X-velocity. ; (e.g., if facing right ($01), XVel becomes $01; if left ($FF), XVel becomes $FF) STA GameObjectXVelocity,X ; Store new X-velocity to start slight movement. BirdAI_FlightPathAltitudeCheck LDA GameObjectYCoordHi,X ; Get current Y position. CMP #$A2 ; Is bird very low (near bottom of typical play area)? BCC BirdAI_CheckMidAltitudeRange ; - If higher than $A2, check next range. ; Bird is very low (Y >= $A2). LDA #$00 ; Set a fast timer value for GameObjectTimerResetValue. STA GameObjectEventTimer1,X ; Force next event (flap) quickly to gain altitude. JMP BirdAI_CheckEventTimer ; Proceed to main AI timer logic. BirdAI_CheckMidAltitudeRange CMP #$92 ; Is bird in the lower-mid section of screen? BCC BirdAI_CheckUpperAltitudeRange ; - If higher than $92, check upper range. ; Bird is in lower-mid range ($92 <= Y < $A2). LDA GameObjectYVelocityHi,X ; Check Y velocity. BMI BirdAI_CheckUpperAltitudeRange ; - If moving up, it might be correcting, check upper range logic. CMP #$01 ; Is bird moving down (YVel >= $01)? BCC BirdAI_CheckUpperAltitudeRange ; - If not moving down (YVel == $00), proceed to upper range logic. ; This means if stationary or moving slowly down in this zone, it's fine. ; Bird is in lower-mid range AND moving down significantly (YVel >= $01). LDY ObjectBirdLevelAndType,X ; Get bird type. LDA AITimerDistantAggressive_ByType,Y ; Load a type-specific timer reset value (from "slow reaction" table). ; This likely makes the bird react/flap sooner to correct downward movement. STA GameObjectTimerResetValue,X ; Store it to influence next flap time. JMP BirdAI_CheckEventTimer BirdAI_CheckUpperAltitudeRange CMP #$88 ; Is bird in the mid-upper section of screen? BCC BirdAI_CheckEventTimer ; - If higher than $88 (i.e. Y < $88, near top), go to standard event timer. ; Bird is in mid-upper range ($88 <= Y < $92). LDA GameObjectYVelocityHi,X ; Check Y velocity. BMI BirdAI_CheckEventTimer ; - If moving up, behavior is fine, go to standard event timer. CMP #$02 ; Is bird moving down significantly (YVel >= $02)? BCC BirdAI_CheckEventTimer ; - If not (YVel < $02), behavior is fine. ; Bird is in mid-upper range AND moving down significantly (YVel >= $02). LDY ObjectBirdLevelAndType,X ; Get bird type. LDA AITimerDistantAggressive_ByType,Y ; Load a type-specific timer reset value (from "slow reaction" table). STA GameObjectTimerResetValue,X ; Store it to influence next flap time. ; Fall through to BirdAI_CheckEventTimer ; Bird Animation Frames: ; $00: Gliding / Standing on platform ; $01: Wings up (during flap) ; $02: Wings mid-stroke (specific flapping/landing animation phase) ; $03: Wings down (during flap) BirdAI_CheckEventTimer LDA GameObjectEventTimer1,X ; Load the bird's short-term event timer. BEQ BirdAI_EventTimerExpired ; If timer is zero, process the event. DEC GameObjectEventTimer1,X ; Otherwise, decrement the timer. JMP BirdAI_CheckMainAIDecisionTimer ; Proceed to check the longer-term AI decision timer. BirdAI_EventTimerExpired ; Short-term event timer has expired. LDA GameObjectAnimationFrame,X ; Get current animation frame. ; Frames $00 (glide/stand) and $02 (mid-flap/land) ; seem to be key decision points for initiating a flap. BEQ BirdAI_FlapOrTakeAction ; If frame $00 (gliding/standing), time to flap/act. CMP #$02 ; Is animation frame $02? BEQ BirdAI_FlapOrTakeAction ; If frame $02, also time to flap/act. BirdAI_SetAnimationToGlideOrStand ; Current animation is likely $01 (wings up) or $03 (wings down). ; Reset animation to the default non-flapping state. LDA #$00 ; Set animation frame to $00 (gliding/standing). STA GameObjectAnimationFrame,X LDA GameObjectTimerResetValue,X ; Reload short-term event timer from its dynamic reset value. ; This value is often set by altitude adjustment logic. STA GameObjectEventTimer1,X JMP BirdAI_CheckMainAIDecisionTimer ; Proceed to check the longer-term AI decision timer. BirdAI_FlapOrTakeAction ; Time to perform a primary action, usually flapping. LDA GameObjectTimerResetValue,X ; Reload short-term event timer. STA GameObjectEventTimer1,X JSR BirdFlapOrAction ; Execute the flap: changes Y-velocity, updates animation frame. BirdAI_CheckMainAIDecisionTimer ; Check the 16-bit main AI decision timer. LDA GameObjectState,X ; Get current bird state. CMP #State_BirdSeekingRider ; Is bird in "State_BirdSeekingRider" ($14)? BCS BirdAI_ExitThisAutopilot ; If state is >= $14 (SeekingRider or unknown higher), ; this general autopilot logic does not apply. Exit. ; State_BirdSeekingRider has its own specialized AI routines. ; Bird is in a state managed by this general autopilot (e.g., normal flight, attacking player). ; Decrement the 16-bit AI decision timer (GameObjectAITimerHi/Lo). SEC LDA GameObjectAITimerLo,X SBC #$01 STA GameObjectAITimerLo,X LDA GameObjectAITimerHi,X BMI BirdAI_DecisionTimerExpired_HandleTargeting ; If Hi byte was already negative, timer had expired. SBC #$00 ; Subtract carry (if Lo underflowed). STA GameObjectAITimerHi,X BMI BirdAI_DecisionTimerExpired_HandleTargeting ; If Hi byte is now negative, timer just expired. BirdAI_DecisionTimerStillActive ; Main AI decision timer has not expired yet. ; Bird continues with its current general behavior. JSR AdjustBirdYBasedOnAltitude ; Make minor adjustments to Y velocity based on altitude zones. ; The return value in A is used to set the next flap timer. STA GameObjectTimerResetValue,X ; Store the altitude-influenced value. This determines ; how soon GameObjectEventTimer1 will expire for the next flap. RTS ; Done with autopilot for this frame. BirdAI_DecisionTimerExpired_HandleTargeting ; Main AI decision timer has expired. ; Time for a more significant AI decision. LDA GameObjectAlive,X ; Is the bird currently considered "alive"? BNE BirdAI_Alive_MakeDecision ; If alive, proceed to make a decision (re-target, turn, etc.). ; Bird is NOT alive (GameObjectAlive,X is $00), but its AI is still being processed. ; This can happen for unridden enemy birds that are flying off-screen after their ; rider has been defeated (they are in state $05 "hit" but Alive is $00). JMP AdjustBirdYBasedOnAltitudeAndResetEventTimer ; Adjust Y for its off-screen path and set event timer. BirdAI_Alive_MakeDecision ; Bird is alive, and its main AI timer has expired. JMP BirdAI_ReTargetOrYAdjust ; Jump to the core AI decision logic: ; find a target, adjust Y-velocity towards it, or turn. BirdAI_ExitThisAutopilot ; Bird is in a state (e.g. SeekingRider) not handled by this general autopilot. RTS BirdFlapOrAction LDA GameObjectState,X CMP #$08 BEQ ExitFlapPhysics CLC LDA GameObjectXVelocity,X ADC GameObjectDirection,X STA GameObjectXVelocity,X ApplyFlapPhysics LDA GameObjectState,X CMP #$08 BEQ ExitFlapPhysics LDY ObjectBirdLevelAndType,X SEC LDA GameObjectYVelocityLo,X SBC BirdFlapLiftFactorLoLUT,Y STA GameObjectYVelocityLo,X LDA GameObjectYVelocityHi,X SBC BirdFlapLiftFactorHiLUT,Y STA GameObjectYVelocityHi,X LDA GameObjectInAir,X BNE FinalizeFlapState DEC GameObjectYCoordHi,X FinalizeFlapState LDA #$01 STA GameObjectAnimationFrame,X STA GameObjectInAir,X LDA #$00 STA GameObjectPlatformSkipState,X CPX #$02 BCS ExitFlapPhysics ; branch if non-player enemy bird LDA #SFX_PlayerBirdFlap JMP ScheduleSFX ExitFlapPhysics RTS ClearSkidStateAndSound LDA GameObjectSkidDirection,X BEQ BirdNotSkidding2 DEC GameObjectYCoordHi,X LDA #$00 STA GameObjectSkidDirection,X STA GameObjectFootstepAnimIndex,X LDA #$0F ; skid sound effect JMP SilenceSFXIfPlaying BirdNotSkidding2 RTS AdjustBirdYBasedOnAltitudeAndResetEventTimer JSR AdjustBirdYBasedOnAltitude STA GameObjectTimerResetValue,X RTS ; BirdAI_ReTargetOrYAdjust ; This routine is called when a bird's main AI decision timer has expired. ; It handles re-targeting, turn timers, and then determines the bird's next ; short-term event timer (GameObjectTimerResetValue,X) based on proximity to its ; target and its current AI mode. This timer controls flap/action frequency. ; Input: X = bird's GameObject index BirdAI_ReTargetOrYAdjust LDA GameObjectPreyIndex,X ; Check if bird already has a prey BPL TargetAcquired_Or_AITargetDelayActive ; If prey index is valid (0 or positive), proceed JSR FindBestTargetForGameObject ; No valid prey, try to find one LDA GameObjectPreyIndex,X ; Check again if a prey was found BPL PreyFound_ProceedToProximityCalc ; If prey now valid, proceed ; Still no prey after trying to find one JSR AdjustBirdYBasedOnAltitude ; Adjust Y velocity based on current altitude STA GameObjectTimerResetValue,X ; Set next event timer based on altitude adjustment RTS ; No target, no further complex AI decision TargetAcquired_Or_AITargetDelayActive LDA GameObjectAITargetDelayTimer,X ; Check if AI target re-evaluation is on cooldown BEQ AITargetDelayExpired_ForceRetarget ; If timer is zero, cooldown expired, force re-target DEC GameObjectAITargetDelayTimer,X ; Otherwise, decrement cooldown timer JMP PreyFound_ProceedToProximityCalc ; Proceed with current prey AITargetDelayExpired_ForceRetarget LDA EnemyAITargetDelayBase ; Cooldown expired, load base delay value STA GameObjectAITargetDelayTimer,X ; Reset the cooldown timer JSR FindBestTargetForGameObject ; Force re-evaluation of the best target PreyFound_ProceedToProximityCalc ; Bird has a prey (either existing or newly acquired) JSR DecrementAndProcessBirdTurnTimer ; Handle turn timer (may cause bird to turn around) DetermineAIActionBasedOnProximity JSR CalculateProximityCategoryIndexForAI ; A -> index based on Y dist/vel to prey. Y reg gets this index. TAY ; Y = Proximity Category Index (0-2, 4-6, 8-A) LDA BirdAIActionCategoryByProximityLUT,Y ; Get AI Action Category ($00-$04, $FF) LDY ObjectBirdLevelAndType,X ; Y = Bird Type (0:Bounder, 1:Hunter, 2:ShadowLord, 3:Player) CMP #AIActionCat_CloseDefensive ; Is category $00 (Close/Defensive)? BEQ SelectTimer_Cat00_Path ; If so, branch CMP #AIActionCat_OptimalAttack ; Is category $01 (Optimal Attack)? BEQ SelectTimer_Cat01_Path ; If so, branch CMP #AIActionCat_ModerateEngage ; Is category $02 (Moderate Engage)? BEQ SelectTimer_Cat02_Path ; If so, branch CMP #AIActionCat_FarApproach ; Is category $03 (Far Approach)? BEQ SelectTimer_Cat03_Path ; If so, branch ; Fall-through: Category is $04 (VeryFar) or $FF (NoTarget/Maintain current behavior) LDA GameObjectAIMode,X ; Check AI Mode (0=Passive, NonZero=Aggressive) BEQ Branch_CatFF04_AIMode0 ; If Mode 0 (Passive) ; AIMode is 1 (Aggressive) for Cat $04/$FF LDA AITimerDistantAggressive_ByType,Y ; Mode 1 ; Fall-through to StoreCalculatedTimerAndExitAIAction StoreCalculatedTimerAndExitAIAction ; Common exit point for storing timer and returning. STA GameObjectTimerResetValue,X RTS Branch_CatFF04_AIMode0 ; Category $04/$FF, AI Mode 0 (Passive) LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y ; Use shared table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit SelectTimer_Cat03_Path ; Category $03 (Far Approach) LDA GameObjectAIMode,X BEQ Branch_Cat03_AIMode0 ; If Mode 0 (Passive) ; AI Mode is 1 (Aggressive) for Cat $03 LDA AITimerDistantPassive_Or_ApproachAggressive_ByType,Y ; Mode 1: Use shared table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit Branch_Cat03_AIMode0 ; Category $03 (Far Approach), AI Mode 0 (Passive) LDA AITimerApproachPassive_ByType,Y ; Use Cat03_AIMode0 table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit SelectTimer_Cat00_Path ; Category $00 (Close/Defensive) LDA AITimerCloseDefensive_ByType,Y ; This category uses one table regardless of AI mode JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit SelectTimer_Cat02_Path ; Category $02 (Moderate Engage) LDA GameObjectAIMode,X BEQ Branch_Cat02_AIMode0 ; If Mode 0 (Passive) ; AI Mode is 1 (Aggressive) for Cat $02 LDA AITimerMixedEngageAttack_ByType,Y ; Mode 1: Use shared table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit Branch_Cat02_AIMode0 ; Category $02 (Moderate Engage), AI Mode 0 (Passive) LDA AITimerEngagePassive_ByType,Y ; Use Cat02_AIMode0 table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit SelectTimer_Cat01_Path ; Category $01 (Optimal Attack) LDA GameObjectAIMode,X BEQ Branch_Cat01_AIMode0 ; If Mode 0 (Passive) ; AI Mode is 1 (Aggressive) for Cat $01 LDA AITimerAttackAggressive_ByType,Y ; Mode 1: Use Cat01_AIMode1 table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit Branch_Cat01_AIMode0 ; Category $01 (Optimal Attack), AI Mode 0 (Passive) LDA AITimerMixedEngageAttack_ByType,Y ; Mode 0: Use shared table JMP StoreCalculatedTimerAndExitAIAction ; Jump to common exit AdjustBirdYBasedOnAltitude LDA GameObjectYCoordHi,X SEC SBC #$94 BPL AltitudeCheckGotAbsYDistFromLowBoundary EOR #$FF CLC ADC #$01 AltitudeCheckGotAbsYDistFromLowBoundary CMP #$02 BCS BirdAI_CheckDistanceFromMidAltitudeBoundary SetFlapTimerForLowAltitude LDY ObjectBirdLevelAndType,X LDA AITimerCloseDefensive_ByType,Y RTS BirdAI_CheckDistanceFromMidAltitudeBoundary STA Temp65 LDA GameObjectYCoordHi,X SEC SBC #$52 BPL CheckDistanceFromMidAltitude EOR #$FF CLC ADC #$01 CheckDistanceFromMidAltitude CMP #$02 BCC SetFlapTimerForLowAltitude STA Temp66 LDA GameObjectYCoordHi,X SEC SBC #$15 BPL CompareAltitudeDistancesAndSelectTimer EOR #$FF CLC ADC #$01 CompareAltitudeDistancesAndSelectTimer CMP #$02 BCC SetFlapTimerForLowAltitude CMP Temp66 BCS BirdAI_CheckMidAltitudePosition CMP Temp65 BCS BirdAI_CompareAltitudeDistances LDA GameObjectYCoordHi,X CMP #$15 BCS SetFlapTimerForHighAltitude SetFlapTimerForMidAltitudePassive LDY ObjectBirdLevelAndType,X LDA AITimerEngagePassive_ByType,Y RTS BirdAI_CheckMidAltitudePosition LDA Temp66 CMP Temp65 BCS BirdAI_CompareAltitudeDistances LDA GameObjectYCoordHi,X CMP #$52 BCS SetFlapTimerForHighAltitude JMP SetFlapTimerForMidAltitudePassive BirdAI_CompareAltitudeDistances LDA GameObjectYCoordHi,X CMP #$94 BCC SetFlapTimerForMidAltitudePassive SetFlapTimerForHighAltitude LDY ObjectBirdLevelAndType,X LDA AITimerApproachPassive_ByType,Y RTS CalculateProximityMetric LDA #$00 STA Temp60 LDA GameObjectXCoordHi,X SEC SBC GameObjectXCoordHi,Y BPL CalculateProximityMetricXDone EOR #$FF CLC ADC #$01 CalculateProximityMetricXDone LSR LSR STA Temp5F LDA GameObjectYCoordHi,X SEC SBC GameObjectYCoordHi,Y BPL AddXDistanceToProximityMetric EOR #$FF CLC ADC #$01 AddXDistanceToProximityMetric CLC ADC Temp5F STA Temp5E RTS FindBestTargetForGameObject CPX #$02 BCS FindTargetForEnemyBird ; branch if non-player enemy bird LDA #$02 STA Temp62 LDY #$18 JMP FindTargetInitializeSearch FindTargetForEnemyBird LDA #$00 STA Temp62 LDY #$01 FindTargetInitializeSearch LDA #$FF STA Temp61 STA GameObjectPreyIndex,X FindTargetCheckNextObjectLoop LDA.w GameObjectState,Y BEQ FindTargetCheckNextObject CMP #$04 BEQ TargetStateIsValidCalculateDistance BCC TargetStateIsValidCalculateDistance CMP #$14 BCS FindTargetCheckNextObject CMP #$0A BCC FindTargetCheckNextObject TargetStateIsValidCalculateDistance JSR CalculateProximityMetric LDA Temp5E CMP Temp61 BCS FindTargetCheckNextObject STA Temp61 TYA STA GameObjectPreyIndex,X FindTargetCheckNextObject DEY CPY Temp62 BPL FindTargetCheckNextObjectLoop RTS CalculateProximityCategoryIndexForAI LDY GameObjectPreyIndex,X LDA GameObjectYCoordHi,X CPY #$0D BCS CalculateProximityForEggOrPterry SEC SBC #$02 CMP GameObjectYCoordHi,Y BCC SetProximityBaseIndexTargetIsBelow SEC SBC #$06 CMP GameObjectYCoordHi,Y BCS SetProximityCategoryToOptimalAttack JMP SetProximityCategoryFarApproach CalculateProximityForEggOrPterry SEC SBC #$F2 CMP GameObjectYCoordHi,Y BCC SetProximityBaseIndexTargetIsBelow SEC SBC #$02 CMP GameObjectYCoordHi,Y BCS SetProximityCategoryToOptimalAttack SetProximityCategoryFarApproach LDA #$04 JMP StoreProximityBaseIndexAndAddVelocityBias SetProximityBaseIndexTargetIsBelow LDA #$08 JMP StoreProximityBaseIndexAndAddVelocityBias SetProximityCategoryToOptimalAttack LDA #$00 StoreProximityBaseIndexAndAddVelocityBias STA Temp5E LDA GameObjectYVelocityHi,X BEQ CalculateProximityIndex_BirdStationary BPL AddDownwardVelocityBiasToProximityIndex CMP #$FF BEQ CalculateProximityIndex_BirdStationary AddDownwardVelocityBiasToProximityIndex LDA Temp5E CLC ADC #$02 RTS CalculateProximityIndex_BirdStationary LDA Temp5E CLC ADC #$01 RTS LDA Temp5E RTS ConvertKilledBirdToEgg LDA GameObjectSkidDirection,X BEQ PlayBirdDeathExplosionSFXTurnIntoEgg LDA #SFX_Skid JSR SilenceSFXIfPlaying PlayBirdDeathExplosionSFXTurnIntoEgg LDA #SFX_BirdExplosion JSR ScheduleSFX LDA #$00 STA GameObjectAlive,X LDA #$05 STA GameObjectState,X LDY ObjectBirdLevelAndType,X LDA AITimerCloseDefensive_ByType,Y STA GameObjectTimerResetValue,X INC EggsPresentCount LDY #$0D FindAvailableEggSlot LDA.w GameObjectState,Y BEQ FoundAvailableEggSlotInitialize INY CPY #$19 BNE FindAvailableEggSlot FoundAvailableEggSlotInitialize LDA #$01 STA.w GameObjectState,Y LDA #$01 STA GameObjectInAir,Y STA GameObjectDirection,Y LDA GameObjectXVelocity,X STA GameObjectXVelocity,Y LDA GameObjectYVelocityLo,X STA GameObjectYVelocityLo,Y LDA GameObjectYVelocityHi,X STA GameObjectYVelocityHi,Y LDA GameObjectYCoordLo,X STA GameObjectYCoordLo,Y LDA GameObjectYCoordHi,X CLC ADC #$0B STA GameObjectYCoordHi,Y LDA GameObjectXCoordLo,X STA GameObjectXCoordLo,Y LDA GameObjectXCoordHi,X STA GameObjectXCoordHi,Y LDA ObjectBirdLevelAndType,X STX Temp5E TAX LDA NextEnemyBirdLevel,X ; check what the next upgraded enemy is LDX Temp5E STA ObjectBirdLevelAndType,Y LDA #$00 STA ObjectWiggleAnimation,Y RTS StartPlayerDeath LDA PterryCountdownHi BNE SkipPterryCountdown LDA #$01 STA PterryCountdownHi SkipPterryCountdown LDA #$00 STA LevelWasSurvived LDA #$00 STA Temp61ScoreAdd LDA #$05 STA Temp62ScoreAdd JSR UpdatePlayerScoreAndBonus LDA GameObjectSkidDirection,X BEQ PlayPlayerDeathExplosionSFX LDA #SFX_Skid JSR SilenceSFXIfPlaying PlayPlayerDeathExplosionSFX LDA #SFX_BirdExplosion JSR ScheduleSFX JSR DeadPlayerChecks LDA GameObjectState,X BEQ SetupPlayerRespawn ; state = 0:dead LDA #$05 ; state = 5:player was hit STA GameObjectState,X LDY ObjectBirdLevelAndType,X LDA AITimerCloseDefensive_ByType,Y STA GameObjectTimerResetValue,X LDA #$00 STA GameObjectAlive,X LDA GameObjectYCoordHi,X JMP StorePlayerExplosionCoordinates SetupPlayerRespawn LDA #$03 ; state = 3:born1 STA GameObjectState,X LDA #$1E STA GameObjectCountdownLo,X LDA GameObjectYCoordHi,X SEC SBC #$08 ; Explosion should be a bit higher than the bird StorePlayerExplosionCoordinates STA PlayerExplosionYCoord,X LDA GameObjectXCoordHi,X STA PlayerExplosionXCoord,X LDA #$16 STA ESRoutineIndex+5,X LDA #$00 ; Clear the death state STA P0DeathState,X TYA PHA LDY #$0A SetPterrysToLeavingOnDeathLoop LDA.w GameObjectState,Y BEQ CheckNextPterryOnPlayerDeath CMP #$0D BEQ CheckNextPterryOnPlayerDeath LDA PterryDefeatedFlag,Y CMP #$01 BNE CheckNextPterryOnPlayerDeath LDA #$0C STA.w GameObjectState,Y LDA GameObjectDirection,Y BPL SetPterryLeavingVelocityRight LDA #$FB JMP StorePterryLeavingVelocity SetPterryLeavingVelocityRight LDA #$05 StorePterryLeavingVelocity STA GameObjectXVelocity,Y CheckNextPterryOnPlayerDeath INY CPY #$0D BCC SetPterrysToLeavingOnDeathLoop PLA TAY RTS DecrementAndProcessBirdTurnTimer SEC LDA GameObjectTurnCheckTimerLo,X SBC #$01 STA GameObjectTurnCheckTimerLo,X LDA GameObjectTurnCheckTimerHi,X BMI BirdTurnTimerExpired SBC #$00 STA GameObjectTurnCheckTimerHi,X BMI BirdTurnTimerExpired RTS BirdTurnTimerExpired LDA GameObjectDirection,X EOR #$FF CLC JMP SetBirdRandomTurnTimers ; This rom is a bit weird in that the last 2 8k blocks are identical, ; including the cart vectors and encryption key. ; ; block 1: the graphics and code are live/used, except for the ; brief "jmp $B000" located at DF7A. The encryption key, BIOS bytes, ; and 6502 vectors are dead/unused. ; ; block 2: the graphics and code are dead/unused, except for the ; brief "jmp $B000" located at FF7A. The encryption key, BIOS bytes, ; and 6502 vectors are used. ; ; So... Joust has just under 8K unused in block 2, ready and waiting ; for rom hacks. ; ; This is block 1 of 2... SpriteGFX2 ; C000-C7FF .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $2A, $A0, $2A, $80, $2A, $20, $AA, $00 .byte $A8, $00, $AA, $00, $AA, $00, $AA, $80 .byte $AA, $A0, $AA, $A0, $AA, $A0, $AA, $A0 .byte $2A, $A0, $2A, $A0, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $11, $48, $22, $8C, $33, $C8, $AA, $AA .byte $EA, $54, $00, $10, $6A, $AA, $A8, $A0 .byte $AA, $AA, $95, $56, $AB, $7A, $A9, $57 .byte $00, $D0, $6A, $AA, $A5, $5A, $AA, $AA .byte $AA, $A0, $00, $00, $00, $15, $55, $56 .byte $AA, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $03, $00, $33 .byte $00, $C0, $33, $00, $C0, $0C, $C0, $CC .byte $30, $00, $00, $C0, $00, $00, $00, $00 .byte $00, $0C, $00, $00, $00, $00, $0C, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $0A, $A0, $0A, $AA, $56 .byte $9A, $90, $36, $A9, $6A, $AA, $80, $00 .byte $55, $AA, $00, $09, $7A, $A6, $A5, $FE .byte $A5, $A9, $54, $D6, $A5, $AA, $BD, $66 .byte $56, $AB, $70, $00, $00, $00, $A0, $00 .byte $02, $A0, $00, $00, $A8, $02, $AA, $02 .byte $A0, $00, $00, $AA, $00, $44, $F0, $81 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $FF, $EB, $CF, $FF, $00, $00, $00 .byte $00, $00, $00, $0F, $CF, $00, $00, $00 .byte $00, $FF, $A0, $00, $00, $00, $00, $00 .byte $2A, $80, $2A, $80, $2A, $00, $AA, $00 .byte $AA, $00, $AA, $00, $AA, $00, $AA, $80 .byte $AA, $80, $AA, $A0, $AA, $A0, $AA, $80 .byte $AA, $A0, $2A, $A0, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $04, $48, $08, $8C, $0C, $C8, $2A, $AA .byte $AA, $94, $00, $10, $AA, $AA, $A8, $A0 .byte $AA, $AA, $95, $56, $AB, $FE, $A9, $57 .byte $00, $D0, $6A, $AA, $A5, $56, $AA, $AA .byte $AA, $A0, $00, $00, $00, $00, $55, $55 .byte $AA, $80, $00, $00, $2A, $AB, $F4, $00 .byte $00, $00, $00, $AA, $80, $00, $00, $00 .byte $00, $2A, $AA, $A8, $00, $5A, $AA, $A0 .byte $00, $00, $00, $00, $00, $00, $00, $0A .byte $AA, $A0, $00, $00, $00, $03, $30, $0C .byte $00, $C0, $0C, $00, $C0, $0F, $00, $CC .byte $30, $00, $00, $30, $00, $00, $00, $00 .byte $03, $FF, $FF, $FF, $FF, $FF, $F0, $0F .byte $FC, $03, $F3, $C3, $CF, $00, $00, $FC .byte $03, $00, $F0, $28, $28, $02, $A9, $5A .byte $9E, $90, $36, $A9, $5A, $AA, $40, $00 .byte $01, $5A, $A0, $0A, $FA, $A6, $A5, $FA .byte $A5, $6A, $54, $D6, $A6, $AA, $D7, $A6 .byte $A5, $AB, $FA, $80, $00, $0A, $AB, $C0 .byte $0A, $A9, $00, $02, $AA, $86, $AA, $0A .byte $A8, $00, $7A, $AA, $B0, $0C, $F0, $63 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $FA, $BF, $FF, $EA, $BE, $F3, $FF, $C0 .byte $00, $00, $00, $EA, $FB, $EA, $FF, $00 .byte $03, $FA, $BF, $FA, $80, $00, $00, $00 .byte $0A, $80, $0A, $80, $2A, $80, $2A, $80 .byte $2A, $80, $AA, $80, $AA, $80, $AA, $80 .byte $2A, $80, $AA, $80, $2A, $80, $AA, $80 .byte $AA, $80, $AA, $80, $AA, $A8, $AF, $A8 .byte $AE, $A8, $AA, $A8, $2A, $A8, $2A, $A8 .byte $2A, $A8, $2A, $A8, $AA, $A8, $AA, $A8 .byte $AA, $A8, $2A, $A8, $2A, $A8, $2A, $A8 .byte $04, $48, $08, $8C, $0C, $C8, $0A, $AA .byte $AA, $94, $00, $10, $AA, $AA, $A8, $20 .byte $AA, $AA, $55, $4A, $AA, $7E, $A9, $57 .byte $00, $D0, $6A, $AA, $A5, $56, $AA, $AA .byte $AA, $80, $00, $00, $00, $00, $05, $55 .byte $6A, $A0, $00, $00, $AA, $AA, $BF, $D0 .byte $00, $00, $A0, $AA, $AB, $40, $00, $00 .byte $00, $AA, $AA, $AA, $30, $5A, $AA, $A0 .byte $01, $56, $A8, $00, $00, $00, $70, $AA .byte $AA, $AA, $B0, $00, $00, $03, $0C, $00 .byte $00, $C0, $00, $03, $00, $0C, $C0, $CF .byte $F0, $00, $00, $0F, $FC, $00, $00, $00 .byte $00, $0C, $00, $00, $00, $00, $00, $30 .byte $03, $0C, $0C, $3C, $30, $C0, $F3, $03 .byte $03, $03, $0C, $80, $08, $00, $55, $4A .byte $AE, $90, $06, $AA, $16, $A9, $00, $00 .byte $00, $00, $00, $0A, $BA, $A5, $A9, $DA .byte $A5, $6A, $54, $D6, $A6, $AA, $FD, $A6 .byte $AA, $AA, $AA, $00, $00, $2A, $AA, $7F .byte $2A, $AA, $F0, $02, $AA, $A6, $AA, $6A .byte $AA, $3F, $6A, $AA, $A0, $00, $12, $91 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $FF, $AA, $AA, $BA, $AB, $FA, $EE, $A0 .byte $00, $00, $02, $AA, $AB, $FF, $FF, $00 .byte $3F, $EB, $FF, $AB, $FA, $C0, $00, $00 .byte $0A, $80, $0A, $80, $0A, $80, $0A, $80 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $80 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $80 .byte $2A, $80, $AA, $80, $BB, $A8, $BA, $A8 .byte $AE, $E8, $BA, $AB, $BE, $A8, $BA, $A0 .byte $3B, $A8, $3A, $A8, $BE, $A8, $3A, $A8 .byte $BA, $A8, $3B, $E8, $3A, $E8, $3A, $A8 .byte $45, $48, $8A, $8C, $CF, $C8, $02, $AA .byte $AA, $94, $00, $10, $AA, $A8, $00, $20 .byte $AA, $A9, $54, $0A, $AA, $BE, $A9, $57 .byte $00, $D0, $6A, $AA, $A8, $55, $AA, $AA .byte $AA, $00, $00, $00, $00, $00, $00, $05 .byte $52, $A8, $00, $0A, $AA, $AA, $AF, $FD .byte $40, $00, $A0, $AA, $AA, $F4, $00, $00 .byte $02, $AA, $AA, $AA, $90, $5A, $AA, $A0 .byte $15, $AA, $AA, $A0, $00, $07, $E0, $AA .byte $AA, $AA, $A8, $00, $00, $00, $C3, $00 .byte $00, $C0, $00, $0C, $00, $0C, $30, $00 .byte $30, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $C0 .byte $03, $0C, $0C, $0C, $C0, $33, $0F, $03 .byte $03, $03, $03, $00, $00, $00, $00, $0A .byte $A6, $90, $06, $AA, $00, $00, $00, $00 .byte $00, $00, $00, $0A, $AA, $A5, $A9, $5A .byte $95, $6A, $50, $D6, $A6, $AA, $76, $A6 .byte $AA, $AA, $A8, $00, $00, $AA, $AA, $5D .byte $EA, $AA, $FF, $0A, $AA, $AA, $A9, $AA .byte $AA, $BF, $AA, $AA, $A8, $00, $12, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $FE, $FF, $FF, $FF, $FF, $EA, $BA, $A8 .byte $00, $00, $0E, $EE, $AF, $FF, $FF, $00 .byte $AF, $EF, $EE, $BF, $FA, $AF, $C0, $00 .byte $0A, $80, $0A, $80, $0A, $80, $0A, $80 .byte $0A, $80, $0A, $80, $2A, $00, $2A, $80 .byte $2A, $80, $2A, $80, $2A, $80, $2A, $00 .byte $2A, $20, $2A, $80, $AE, $A8, $AE, $A0 .byte $AA, $A0, $AB, $A0, $AF, $A0, $AF, $A0 .byte $AF, $A0, $2E, $A8, $2F, $A8, $AB, $B8 .byte $2B, $A8, $2F, $E8, $AE, $A8, $2B, $A8 .byte $15, $48, $2A, $8C, $3F, $C8, $00, $2A .byte $AA, $A4, $00, $00, $AA, $00, $00, $00 .byte $2A, $95, $00, $0A, $AA, $BF, $A9, $57 .byte $00, $10, $6A, $AA, $A8, $05, $AA, $AA .byte $A8, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $2A, $AA, $AA, $A9, $5F .byte $FC, $02, $A0, $AA, $AA, $7F, $C0, $00 .byte $02, $AA, $AA, $AA, $A0, $5A, $AA, $81 .byte $5A, $AA, $AA, $AA, $0F, $FF, $60, $AA .byte $AA, $AA, $AA, $80, $00, $30, $03, $00 .byte $3F, $FF, $FF, $F0, $00, $0C, $00, $00 .byte $30, $00, $00, $0F, $C0, $FC, $03, $C0 .byte $FC, $00, $15, $55, $55, $54, $00, $C0 .byte $FF, $0C, $0C, $0F, $00, $0C, $03, $03 .byte $03, $03, $03, $00, $00, $00, $00, $02 .byte $AB, $94, $06, $AA, $00, $00, $00, $00 .byte $00, $00, $00, $00, $AA, $A9, $AA, $AA .byte $95, $6A, $50, $D6, $AA, $AA, $BA, $A6 .byte $AA, $AA, $A0, $00, $02, $AA, $AA, $97 .byte $AA, $AA, $9D, $FA, $AA, $AA, $A9, $AA .byte $AA, $B5, $AA, $AA, $AA, $0B, $B0, $38 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $FE, $FD, $55, $55, $57, $AA, $EA, $AB .byte $C0, $00, $FF, $EF, $AB, $BF, $FF, $03 .byte $EB, $FA, $BF, $FF, $EB, $FF, $FF, $A8 .byte $2A, $00, $8A, $00, $0A, $00, $02, $80 .byte $02, $A0, $0A, $A0, $0A, $80, $0A, $80 .byte $2A, $00, $2A, $00, $2A, $00, $2A, $20 .byte $2A, $00, $2A, $00, $BB, $A0, $AB, $A0 .byte $AB, $A0, $AE, $80, $AE, $80, $AE, $80 .byte $AB, $A0, $AE, $A0, $AF, $EB, $AF, $A8 .byte $2F, $E8, $AB, $A8, $AB, $E8, $AB, $E8 .byte $05, $50, $0A, $A0, $0F, $F0, $00, $0A .byte $AA, $A8, $00, $00, $80, $00, $00, $00 .byte $00, $00, $00, $2A, $AA, $AF, $AA, $57 .byte $00, $10, $6A, $AA, $A8, $00, $02, $AA .byte $80, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $AA, $AA, $AA, $AA, $55 .byte $FF, $CA, $A0, $AA, $AA, $97, $FD, $00 .byte $0A, $AA, $AA, $AA, $A0, $5A, $AA, $85 .byte $6A, $AA, $AA, $AA, $BF, $FD, $60, $AA .byte $AA, $AA, $AA, $A0, $00, $30, $03, $00 .byte $00, $C0, $00, $00, $00, $0C, $00, $C0 .byte $30, $00, $00, $30, $33, $03, $0C, $33 .byte $03, $00, $AA, $AA, $AA, $AA, $00, $C0 .byte $00, $03, $F0, $0C, $00, $0C, $00, $FC .byte $FC, $FC, $03, $00, $00, $00, $00, $00 .byte $2A, $A4, $0A, $AA, $00, $00, $00, $00 .byte $00, $00, $00, $00, $0A, $A9, $6A, $AA .byte $95, $DA, $50, $36, $A9, $AA, $AA, $A6 .byte $AA, $AA, $80, $00, $02, $AA, $AA, $9F .byte $AA, $AA, $B7, $EA, $AA, $AA, $AD, $AA .byte $AA, $A6, $AA, $AA, $AA, $3D, $F2, $FE .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $55, $75, $55, $55, $55, $D5, $AF, $FF .byte $FC, $03, $FF, $FF, $EA, $BF, $FF, $FF .byte $FA, $FF, $FF, $FF, $BF, $FF, $FF, $AF .byte $28, $00, $28, $00, $08, $00, $02, $80 .byte $02, $A0, $02, $A0, $02, $A0, $0A, $A0 .byte $28, $A0, $28, $20, $AA, $00, $28, $20 .byte $28, $28, $A8, $80, $AA, $A0, $AE, $A0 .byte $AE, $80, $AA, $80, $AA, $00, $AA, $00 .byte $AA, $80, $AB, $A0, $AF, $A0, $AA, $E0 .byte $AB, $A0, $2B, $A0, $AB, $A0, $AE, $A0 .byte $01, $08, $02, $0C, $03, $08, $00, $00 .byte $AA, $A8, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $0A, $AA, $A7, $AA, $57 .byte $00, $10, $6A, $AA, $A8, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $AA, $AA, $AA, $AA, $57 .byte $F7, $EA, $A0, $AA, $AA, $AD, $FF, $F0 .byte $0A, $AA, $AA, $AA, $A0, $9A, $AA, $B5 .byte $AA, $AA, $AA, $AA, $AF, $FD, $A0, $AA .byte $AA, $AA, $AA, $A8, $00, $0C, $0C, $00 .byte $00, $00, $00, $00, $00, $CC, $00, $00 .byte $33, $00, $00, $C0, $0C, $00, $F0, $0C .byte $00, $C0, $00, $00, $00, $00, $00, $C0 .byte $00, $00, $00, $00, $00, $0C, $00, $00 .byte $00, $00, $03, $00, $00, $00, $00, $00 .byte $0A, $A4, $0A, $80, $00, $00, $00, $00 .byte $00, $00, $00, $00, $02, $A9, $6A, $AA .byte $96, $DA, $50, $36, $A9, $AA, $AA, $A1 .byte $5A, $AA, $A0, $00, $0A, $AA, $AA, $95 .byte $AA, $AA, $95, $EA, $AA, $AA, $AD, $AA .byte $AA, $AE, $AA, $AA, $AA, $2A, $A0, $89 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF .byte $55, $D5, $55, $55, $55, $75, $55, $55 .byte $55, $15, $55, $55, $55, $55, $55, $55 .byte $55, $55, $55, $55, $55, $55, $55, $55 .byte $88, $00, $08, $00, $08, $00, $00, $00 .byte $00, $20, $00, $20, $00, $20, $00, $88 .byte $02, $00, $28, $80, $A0, $00, $00, $00 .byte $22, $08, $A0, $20, $AA, $A0, $AA, $A0 .byte $AA, $80, $AE, $00, $AE, $00, $BA, $00 .byte $AA, $00, $AA, $80, $AA, $A0, $AA, $A0 .byte $AA, $80, $2A, $A0, $2A, $A0, $AA, $80 .byte $05, $08, $0A, $0C, $0F, $08, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $02, $AA, $AB, $EA, $54 .byte $00, $10, $6A, $AA, $A8, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $02, $AA, $AA, $AA, $AA, $95 .byte $77, $EA, $A0, $AA, $AA, $A5, $DF, $FF .byte $2A, $AA, $AA, $AA, $A0, $AA, $AA, $95 .byte $AA, $AA, $AA, $AA, $AF, $75, $A0, $AA .byte $AA, $AA, $AA, $AA, $00, $03, $F0, $00 .byte $00, $00, $00, $00, $03, $00, $00, $00 .byte $00, $C0, $03, $00, $33, $00, $C0, $33 .byte $00, $C0, $0C, $30, $CF, $F0, $00, $C0 .byte $00, $00, $00, $00, $00, $0C, $00, $00 .byte $00, $00, $03, $00, $00, $00, $00, $00 .byte $00, $A8, $08, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $2A, $2A, $AA .byte $56, $DA, $50, $36, $A9, $6A, $AA, $A0 .byte $05, $56, $A8, $00, $2A, $AA, $AA, $A6 .byte $AA, $6A, $AF, $EA, $AA, $AA, $AD, $AA .byte $AA, $AA, $AA, $A5, $6A, $2E, $A1, $D0 ; C800 CharacterSet ; comprised of... ; 000000000000000011111111111111112222222222222222 ; 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; _0123456789@0123456789@ABCDEGHIJLMNPRSTUVWXYZK() **then the title border and logo chars .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $AA, $AA, $6A, $5A, $96, $A5, $A9, $AA .byte $90, $A0, $A0, $A0, $A0, $A0, $60, $50 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00 .byte $0A, $97, $7F, $EA, $AA, $AA, $A7, $5D .byte $7F, $EA, $95, $AA, $AF, $75, $AA, $AA .byte $AA, $02, $AA, $AA, $AA, $95, $AA, $AA .byte $55, $55, $AA, $95, $57, $0F, $50, $9A .byte $AA, $9D, $AA, $5A, $A0, $AA, $AA, $AA .byte $A8, $00, $02, $95, $7F, $A9, $5A, $50 .byte $7F, $FE, $95, $5A, $55, $5F, $3F, $56 .byte $AA, $BF, $D7, $5A, $50, $56, $AA, $AF .byte $D5, $40, $00, $00, $00, $00, $6A, $A9 .byte $70, $5D, $FF, $A5, $6A, $5F, $FD, $AB .byte $F5, $56, $AA, $A9, $5D, $55, $AA, $A8 .byte $00, $00, $55, $A9, $50, $55, $57, $A5 .byte $57, $5D, $50, $6A, $A9, $55, $DD, $55 .byte $5A, $A9, $60, $A0, $02, $AA, $95, $55 .byte $A5, $95, $55, $55, $A0, $AB, $55, $AA .byte $95, $D5, $6A, $AA, $96, $95, $55, $55 .byte $56, $2A, $AA, $A5, $9A, $A0, $5A, $95 .byte $FE, $AA, $AA, $AA, $AA, $D5, $6A, $AA .byte $AA, $AA, $9A, $A5, $AA, $05, $5A, $A6 .byte $A5, $56, $A5, $A9, $55, $56, $A5, $F5 .byte $6A, $A5, $6A, $80, $2A, $A9, $EA, $A6 .byte $A9, $5A, $A7, $EA, $AA, $AA, $AD, $AA .byte $AA, $AA, $AA, $95, $5A, $00, $E0, $85 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $10, $10 .byte $AA, $6A, $5A, $96, $A5, $A9, $AA, $AA .byte $A0, $A0, $A0, $A0, $A0, $60, $50, $90 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00 .byte $0A, $A5, $5F, $AA, $AA, $AA, $A9, $DD .byte $DF, $AA, $95, $AA, $A9, $D6, $AA, $AA .byte $AA, $00, $2A, $AA, $AA, $95, $AA, $A9 .byte $55, $57, $AA, $95, $57, $03, $D0, $96 .byte $AA, $AA, $AA, $5A, $A0, $AA, $AA, $AA .byte $A8, $00, $02, $A7, $5F, $A9, $5A, $70 .byte $FD, $DE, $95, $5A, $55, $5F, $3F, $5A .byte $AA, $75, $75, $6A, $A0, $55, $AA, $AB .byte $DD, $55, $40, $00, $00, $00, $6A, $A9 .byte $70, $5D, $7F, $A5, $6A, $5F, $FD, $AB .byte $F7, $56, $AA, $A5, $D5, $D5, $AA, $A8 .byte $00, $00, $00, $A9, $50, $D5, $75, $A5 .byte $57, $FD, $50, $6A, $A9, $7D, $D7, $55 .byte $6A, $A5, $60, $A0, $02, $AA, $95, $55 .byte $A5, $95, $55, $55, $60, $AB, $55, $AA .byte $75, $55, $6A, $AA, $56, $95, $55, $40 .byte $00, $AA, $AA, $55, $56, $90, $5A, $95 .byte $7A, $AA, $AA, $AA, $AA, $D5, $6A, $AA .byte $AA, $AA, $9A, $A5, $6A, $00, $5A, $A6 .byte $A5, $56, $A5, $A9, $55, $56, $AF, $55 .byte $6A, $95, $6A, $80, $AA, $A5, $7A, $A6 .byte $A9, $5A, $A5, $AA, $AA, $AA, $AD, $AA .byte $AA, $AA, $AA, $95, $5A, $00, $B0, $01 .byte $00, $54, $54, $54, $54, $04, $54, $54 .byte $10, $54, $04, $00, $A8, $A8, $A8, $A8 .byte $08, $A8, $A8, $20, $A8, $08, $00, $88 .byte $A0, $28, $A0, $A8, $A8, $88, $A8, $20 .byte $A8, $88, $88, $80, $88, $A8, $20, $A8 .byte $20, $88, $88, $20, $A8, $88, $41, $04 .byte $6A, $5A, $96, $A5, $A9, $AA, $AA, $AA .byte $A0, $A0, $A0, $A0, $60, $50, $90, $A0 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00 .byte $2A, $A5, $DF, $AA, $AA, $AA, $A9, $D5 .byte $DD, $AA, $D5, $AA, $AB, $56, $AA, $AA .byte $AA, $00, $02, $AA, $AA, $95, $6A, $A9 .byte $55, $57, $6A, $A5, $57, $03, $D0, $96 .byte $AA, $AA, $AA, $5A, $A0, $AA, $AA, $AA .byte $A8, $00, $02, $A9, $DF, $AA, $5A, $50 .byte $5F, $DA, $95, $56, $95, $5F, $3F, $5A .byte $AB, $D7, $5D, $AA, $A0, $95, $6A, $AB .byte $FF, $FD, $80, $00, $00, $01, $6A, $A9 .byte $50, $7F, $7F, $A5, $5A, $7F, $CF, $AA .byte $D5, $5A, $AA, $AD, $55, $55, $AA, $AA .byte $40, $00, $00, $AB, $50, $57, $57, $A5 .byte $DF, $FD, $50, $6A, $AB, $FF, $75, $55 .byte $6A, $A7, $60, $A0, $00, $AA, $55, $55 .byte $A5, $95, $55, $55, $60, $AB, $D5, $AA .byte $57, $55, $AA, $AA, $56, $95, $00, $00 .byte $00, $AA, $A9, $55, $56, $90, $5A, $95 .byte $7A, $AA, $AA, $AA, $AA, $D5, $6A, $AA .byte $AA, $AA, $9A, $A5, $6A, $00, $0A, $A6 .byte $A5, $56, $A5, $A9, $55, $56, $AF, $D5 .byte $AA, $B5, $6A, $80, $2A, $95, $5A, $A6 .byte $A5, $56, $A5, $AA, $AA, $AA, $A5, $AA .byte $5A, $AA, $AA, $55, $56, $80, $30, $EB .byte $00, $44, $10, $40, $04, $04, $04, $44 .byte $10, $44, $04, $54, $88, $20, $80, $08 .byte $08, $08, $88, $20, $88, $08, $A8, $A8 .byte $88, $80, $88, $80, $88, $88, $20, $88 .byte $80, $88, $A8, $80, $A0, $08, $20, $88 .byte $20, $A8, $88, $20, $80, $88, $44, $04 .byte $5A, $96, $A5, $A9, $AA, $AA, $AA, $6A .byte $A0, $A0, $A0, $60, $50, $90, $A0, $A0 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $00 .byte $AA, $A5, $57, $AA, $AA, $AA, $AA, $77 .byte $5D, $AA, $D5, $AA, $AA, $DA, $AA, $AA .byte $AA, $00, $00, $AA, $AA, $95, $6A, $A9 .byte $55, $77, $6A, $A5, $57, $03, $D0, $96 .byte $AA, $AA, $AA, $55, $50, $AA, $AA, $5A .byte $AA, $00, $02, $AA, $77, $AA, $56, $90 .byte $F5, $DA, $95, $56, $95, $5F, $3F, $5A .byte $AB, $75, $D5, $AA, $A0, $AA, $AA, $AA .byte $FE, $AA, $80, $00, $00, $05, $6A, $AA .byte $50, $7F, $FE, $A5, $5A, $5F, $FD, $AA .byte $D5, $6A, $AA, $97, $5D, $55, $AA, $AA .byte $00, $00, $00, $A9, $50, $5D, $77, $A5 .byte $5F, $FD, $D0, $6A, $AB, $FF, $57, $55 .byte $AA, $95, $60, $A0, $00, $AA, $55, $55 .byte $A5, $95, $55, $55, $60, $AB, $55, $A9 .byte $D5, $55, $AA, $AA, $56, $90, $00, $00 .byte $00, $AA, $A9, $55, $55, $90, $5A, $95 .byte $5A, $AA, $AA, $AA, $AB, $D5, $6A, $AA .byte $A6, $AA, $9A, $95, $6A, $00, $0A, $A6 .byte $A5, $5E, $A5, $A9, $55, $56, $AD, $D6 .byte $AA, $55, $6A, $80, $2A, $95, $5A, $A6 .byte $A5, $56, $A5, $AA, $95, $AA, $A5, $A9 .byte $56, $AA, $AA, $55, $56, $80, $A2, $14 .byte $00, $44, $10, $54, $14, $54, $54, $54 .byte $10, $54, $54, $54, $88, $20, $A8, $28 .byte $A8, $A8, $A8, $20, $A8, $A8, $A8, $88 .byte $A0, $80, $88, $A0, $88, $A8, $20, $08 .byte $80, $88, $A8, $A8, $A8, $20, $20, $88 .byte $88, $88, $20, $20, $20, $A0, $44, $04 .byte $96, $A5, $A9, $AA, $AA, $AA, $6A, $5A .byte $A0, $A0, $60, $50, $90, $A0, $A0, $A0 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $02 .byte $AA, $A5, $76, $AA, $AA, $AA, $AA, $75 .byte $7D, $AA, $D5, $6A, $AA, $DA, $AA, $AA .byte $AA, $00, $00, $0A, $AA, $A5, $6A, $A9 .byte $55, $9F, $6A, $A5, $57, $03, $D0, $95 .byte $AA, $AA, $AA, $03, $50, $55, $55, $56 .byte $AA, $00, $02, $AA, $9E, $AA, $56, $90 .byte $5F, $5A, $55, $56, $95, $5F, $0F, $5A .byte $AB, $DD, $D6, $AA, $A0, $AA, $AA, $AA .byte $AA, $AA, $00, $00, $00, $57, $6A, $AA .byte $70, $77, $5E, $A5, $5A, $5C, $FD, $AA .byte $D5, $6A, $AA, $75, $55, $55, $6A, $AA .byte $40, $00, $00, $A9, $50, $D5, $F7, $A5 .byte $5F, $CD, $50, $6A, $AB, $FF, $F5, $56 .byte $AA, $9D, $60, $A0, $00, $2A, $55, $55 .byte $A5, $55, $55, $D5, $50, $AB, $55, $A9 .byte $75, $55, $AA, $A9, $56, $80, $00, $00 .byte $00, $2A, $A5, $55, $55, $50, $56, $95 .byte $5A, $AA, $AA, $AA, $AB, $55, $6A, $AA .byte $55, $AA, $9A, $95, $5A, $00, $0A, $A6 .byte $A5, $7E, $A5, $A9, $55, $56, $AD, $5A .byte $AA, $75, $5A, $80, $0A, $95, $5A, $A6 .byte $A5, $56, $A5, $AA, $55, $6A, $A5, $A9 .byte $D6, $AA, $AA, $55, $56, $A8, $04, $06 .byte $00, $44, $50, $04, $04, $44, $40, $40 .byte $04, $44, $44, $F4, $88, $A0, $08, $08 .byte $88, $80, $80, $08, $88, $88, $F8, $88 .byte $88, $80, $88, $80, $80, $88, $20, $08 .byte $80, $A8, $A8, $88, $88, $80, $20, $88 .byte $88, $88, $88, $88, $08, $A0, $44, $04 .byte $A5, $A9, $AA, $AA, $AA, $6A, $5A, $96 .byte $A0, $60, $50, $90, $A0, $A0, $A0, $A0 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $0A .byte $AA, $A9, $56, $AA, $AA, $AA, $AA, $55 .byte $DE, $AA, $D5, $6A, $AA, $DA, $AA, $95 .byte $5A, $00, $00, $00, $AA, $A5, $4A, $A9 .byte $56, $9F, $7A, $A5, $57, $00, $D0, $95 .byte $AA, $AA, $AA, $00, $10, $55, $55, $55 .byte $AA, $80, $02, $AA, $AA, $AA, $56, $A0 .byte $77, $6A, $55, $56, $95, $5F, $0F, $FA .byte $AB, $77, $5A, $AA, $A0, $AA, $AA, $AA .byte $AA, $A0, $00, $00, $05, $7F, $6A, $AA .byte $70, $75, $DE, $A5, $5A, $5F, $FD, $AA .byte $D5, $AA, $A9, $F7, $75, $55, $6A, $AA .byte $94, $00, $00, $A9, $50, $5D, $77, $A5 .byte $5F, $FD, $50, $6A, $AB, $F7, $55, $5A .byte $AA, $95, $50, $A0, $00, $2A, $55, $55 .byte $A5, $55, $55, $55, $50, $AB, $D5, $A7 .byte $55, $56, $AA, $A9, $55, $80, $00, $00 .byte $00, $2A, $A5, $55, $55, $50, $56, $A5 .byte $5A, $AA, $96, $AA, $AB, $55, $6A, $A9 .byte $D5, $6A, $9A, $95, $5A, $00, $0A, $A6 .byte $A5, $7E, $A5, $A9, $55, $56, $AD, $6A .byte $AB, $55, $5A, $A0, $0A, $55, $5A, $A6 .byte $A5, $56, $A5, $AA, $55, $5A, $AD, $A5 .byte $5A, $A9, $AA, $55, $00, $80, $F9, $5F .byte $00, $54, $10, $54, $54, $44, $54, $54 .byte $54, $54, $54, $54, $A8, $20, $A8, $A8 .byte $88, $A8, $A8, $A8, $A8, $A8, $A8, $20 .byte $A0, $28, $A0, $A8, $A8, $88, $A8, $08 .byte $80, $88, $88, $A8, $A8, $A8, $A8, $88 .byte $88, $88, $88, $88, $A8, $88, $41, $04 .byte $A9, $AA, $AA, $AA, $6A, $5A, $96, $A5 .byte $60, $50, $90, $A0, $A0, $A0, $A0, $A0 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $0A .byte $AA, $A9, $56, $AA, $95, $AA, $AA, $5D .byte $DE, $AA, $D5, $6A, $AA, $9A, $AA, $55 .byte $56, $00, $00, $00, $0A, $A9, $0A, $A5 .byte $56, $AF, $7A, $A5, $57, $00, $D0, $A5 .byte $6A, $AA, $A8, $00, $00, $55, $55, $55 .byte $6A, $A0, $02, $AA, $AA, $AA, $56, $A0 .byte $77, $6A, $55, $55, $95, $57, $0F, $5A .byte $AB, $5F, $5A, $AA, $A0, $AA, $AA, $AA .byte $AA, $80, $00, $00, $55, $5F, $5A, $AA .byte $70, $5F, $FE, $A5, $5A, $5F, $CD, $AA .byte $55, $AA, $A9, $F7, $D6, $55, $5A, $AA .byte $B5, $00, $00, $A9, $70, $55, $FF, $A5 .byte $7C, $FF, $50, $5A, $AB, $F5, $D5, $6A .byte $AA, $75, $50, $AB, $00, $09, $55, $57 .byte $A5, $55, $57, $55, $50, $AB, $55, $AD .byte $55, $56, $AA, $A9, $55, $80, $00, $00 .byte $00, $0A, $95, $55, $55, $50, $56, $A5 .byte $6A, $A9, $55, $5A, $AB, $55, $AA, $A5 .byte $55, $6A, $9A, $95, $5A, $00, $5A, $A6 .byte $A5, $FE, $A5, $A9, $55, $56, $AD, $6A .byte $A5, $55, $5A, $A0, $02, $55, $5A, $A6 .byte $A5, $56, $A5, $A9, $55, $5A, $A5, $A5 .byte $5A, $A5, $AA, $50, $00, $A8, $10, $90 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $10, $10 .byte $AA, $AA, $AA, $6A, $5A, $96, $A5, $A9 .byte $50, $90, $A0, $A0, $A0, $A0, $A0, $60 .byte $AA, $A0, $A9, $5A, $55, $6A, $50, $2A .byte $AA, $A9, $76, $AA, $55, $6A, $AA, $95 .byte $7E, $AA, $D5, $6A, $AA, $9A, $A9, $55 .byte $55, $00, $00, $00, $00, $A8, $02, $A5 .byte $56, $AF, $7A, $A5, $57, $00, $D0, $A5 .byte $6A, $AA, $A8, $00, $00, $05, $55, $55 .byte $5A, $A8, $00, $2A, $AA, $AA, $55, $A0 .byte $9D, $AA, $55, $55, $95, $57, $0F, $9A .byte $AA, $77, $6A, $AA, $A0, $AA, $AA, $AA .byte $AA, $00, $00, $02, $55, $DF, $5A, $AA .byte $50, $F7, $7E, $95, $5A, $5F, $3F, $AA .byte $56, $AA, $AD, $DD, $DA, $59, $56, $AA .byte $AD, $50, $00, $A9, $50, $75, $DF, $A5 .byte $5F, $FD, $50, $5A, $AB, $FD, $55, $AA .byte $AA, $55, $50, $A8, $00, $00, $00, $77 .byte $A5, $55, $75, $75, $50, $AB, $D5, $95 .byte $D5, $5A, $AA, $A9, $55, $80, $00, $00 .byte $00, $0A, $95, $55, $55, $50, $56, $A5 .byte $6A, $A5, $55, $55, $AB, $55, $AA, $9D .byte $55, $6A, $96, $95, $56, $05, $7A, $A6 .byte $A5, $FE, $A5, $A9, $57, $D6, $A5, $AA .byte $AD, $D5, $56, $AD, $02, $55, $5A, $A6 .byte $A5, $56, $A5, $A9, $55, $5A, $A5, $B5 .byte $5A, $A5, $AA, $00, $00, $00, $D0, $28 ; ORG $D000 MenuUpdateCounter LDA EasterEggJoyDownCount ; easter egg phase 2: if the first phase completed successfully ; the left press counter is allowed to increment. CMP #53 BNE SkipCounting2ndEasterEggPhase INC EasterEggJoyLeftCount SkipCounting2ndEasterEggPhase JMP MenuTextUpdate MenuSelectTwoPlayers LDA #$01 STA PlayerCount BNE SkipCounting1stEasterEggPhase MenuSelectOnePlayer ; (the joystick was pressed down in the title menu) LDA #$00 STA PlayerCount ; easter egg phase 1: if the second phase isn't in progress the ; down press counter is allowed to increment. LDA EasterEggJoyLeftCount BNE SkipCounting1stEasterEggPhase INC EasterEggJoyDownCount JMP MenuTextUpdate SkipCounting1stEasterEggPhase LDA #$00 STA EasterEggJoyDownCount STA EasterEggJoyLeftCount BEQ MenuTextUpdate MenuHandlingAndUpdate LDA SWCHB AND #$02 BEQ MenuSelectPressed LDA #$00 STA MenuSelectDebounceTimer BPL SkipMenuRedraw MenuSelectPressed DEC MenuSelectDebounceTimer BPL SkipMenuRedraw JSR SetMenuSelectDebounceTimerTo20 JSR ChangeDifficulty MenuTextUpdate JSR SetMenuResetTimer JSR SetupGameOptionsText SkipMenuRedraw ; implement a ~18 minute timer that just resets the stack and demo mode. ; I'm thinking they had a slow stack leak during development. LDA TimerHi CMP MenuResetTimer BNE ContinueMenuLoop JMP ResetStackAndStartGameInDemoMode ContinueMenuLoop LDA TimerLo MenuWaitForNextFrame CMP TimerLo BEQ MenuWaitForNextFrame JMP GameOptionsMenuLoop SetMenuJoyDebounceTimerTo20 LDA #$20 STA MenuJoyDebounceTimer RTS SetMenuSelectDebounceTimerTo20 LDA #$20 STA MenuSelectDebounceTimer RTS SetMenuResetTimer LDX TimerHi DEX STX MenuResetTimer RTS ChangeDifficulty INC Difficulty LDA Difficulty CMP #$04 BMI FinalizeDifficultyChange LDA #$00 STA Difficulty LDA PlayerCount EOR #$01 STA PlayerCount FinalizeDifficultyChange JMP ClearScores SetupGameOptionsText LDX PlayerCount LDA HideOrShowTwoPlayerText,X STA MenuTwoPlayerTextXCoord ; set X coordinate of upper DL object = 160 or 48, to hide or display "two player" LDA HideOrShowOnePlayerText,X STA MenuOnePlayerTextXCoord ; set X coordinate of lower DL object = 48 or 160, to display of hide "one player" LDA Difficulty TAX ASL ASL ASL ASL ; A = Difficulty * 16 CLC ADC #<DifficultyText STA Temp5E LDA #$00 ADC ##>DifficultyText STA Temp5F ; ($5E) = current difficulty name LDY #$0F ; copy over 16 characters CopyDifficultyNameLoop LDA (Temp5E),Y STA DifficultyLevelCharBuffer,Y DEY BPL CopyDifficultyNameLoop LDA DifficultyTextXCoordinate,X ; set X coordinate of mid DL object (difficulty level text) STA MenuDifficultyTextXCoord ; differently, depending on the difficulty level. LDA EasterEggJoyLeftCount ; easter egg phase 3: check if phase 2 (left 41 times) is done. ; if so, set us up the egg! CMP #41 BNE ExitMenuEasterEggCheck LDA TimerLo AND #$03 CMP #$03 BNE ExitMenuEasterEggCheck DEC EasterEggXCoordinate1 DEC EasterEggXCoordinate2 DEC EasterEggXCoordinate3 LDA #$01 STA DisplayEasterEggFlag ExitMenuEasterEggCheck RTS CheckMenuFireButtonAndStartGame LDA P0CurrentFire BPL ResetStackAndStartGameInDemoMode_Short LDA PrevResetState BNE MenuUpdateResetButtonState LDA SWCHB LSR BCS ExitMenuEasterEggCheck LDA #$01 STA PrevResetState ResetStackAndStartGameInDemoMode_Short JMP RestartGameFromMenu MenuUpdateResetButtonState JMP UpdatePrevResetStateFlag HandleDemoModeJoyInput LDA P0CurrentFire CheckForAttractModeExit BPL ResetStackAndStartGameInDemoMode_Short LDA SWCHA CMP #$F0 BCS CheckResetSwitch JMP ResetStackAndDisplayGameOptions ;------------------------------------------------------------------------------ ; HandleConsoleSwitches ; Checks the state of Pause, Reset, and Select console switches and acts accordingly. ; This routine is typically called during active gameplay. ;------------------------------------------------------------------------------ HandleConsoleSwitches LDA DemoMode BNE HandleDemoModeJoyInput ; If in demo mode, only check for joystick/fire to exit demo ; Fall-through if not in Demo Mode CheckPauseSwitch LDA PrevPausedState ; Get previous state of Pause switch (was it already pressed?) BNE UpdatePauseSwitchState ; If it was pressed, go update its current debounced state ; Pause switch was not previously pressed, check if it's pressed now LDA SWCHB ; Read console switch register B AND #SWCHB_Pause_Mask ; Isolate Pause switch bit (Bit 3) BNE CheckResetSwitch ; If Pause bit is high (not pressed), check Reset switch ; Pause switch is now pressed (bit 3 is low) LDA #$01 ; Mark that Pause has been latched as pressed STA PrevPausedState BNE EnterPauseSequence ; Branch always (Pause switch was just pressed, so enter pause logic) UpdatePauseSwitchState ; Pause switch was previously latched as pressed LDA SWCHB AND #SWCHB_Pause_Mask ; Isolate Pause bit EOR #SWCHB_Pause_Mask ; Invert Pause bit (so $00=released this cycle, $08=still held) STA PrevPausedState ; Update debounced state CheckResetSwitch LDA PrevResetState ; Get previous state of Reset switch BNE CheckResetSwitchAndCheckSelect ; If it was pressed, go update its current debounced state ; Reset switch was not previously pressed, check if it's pressed now LDA SWCHB LSR ; Shift Reset bit (Bit 0) into Carry BCS CheckSelectSwitch_Direct ; If Carry is set (Reset bit was high, not pressed), check Select ; Reset switch is now pressed (Bit 0 was low) LDA #$01 ; Mark that Reset has been latched as pressed STA PrevResetState BNE ResetStackAndStartGameInDemoMode_Short ; Branch always (Reset was just pressed) CheckResetSwitchAndCheckSelect JSR UpdatePrevResetStateFlag ; Update PrevResetState based on current SWCHB_Reset_Mask state ; Falls through to CheckSelectSwitch_Direct CheckSelectSwitch_Direct LDA PrevSelectState ; Get previous state of Select switch BNE UpdateSelectSwitchStateAndFinish ; If it was pressed, go update its current debounced state ; Select switch was not previously pressed, check if it's pressed now LDA SWCHB AND #SWCHB_Select_Mask ; Isolate Select switch bit (Bit 1) BNE FinishSwitchHandling ; If Select bit is high (not pressed), we're done ; Select switch is now pressed (Bit 1 is low) LDA #$01 ; Mark that Select has been latched as pressed STA PrevSelectState JMP ResetStackAndDisplayGameOptions ; Go to game options screen UpdateSelectSwitchStateAndFinish LDA SWCHB AND #SWCHB_Select_Mask EOR #SWCHB_Select_Mask ; Invert Select bit STA PrevSelectState ; Update debounced state ; Falls through to FinishSwitchHandling FinishSwitchHandling RTS ;------------------------------------------------------------------------------ ; EnterPauseSequence / PauseGameAndWaitForInput ; Handles the game pause state. Waits for Pause to be released or other inputs. ; Mutes audio, saves timers, and monitors switches. ;------------------------------------------------------------------------------ EnterPauseSequence LDA TimerHi PHA ; Save current game timers LDA TimerLo PHA TXA ; Save X register (usually current player index) PHA LDX #$01 STX DemoMode ; Temporarily set DemoMode to 1 (likely to alter some behaviors) DEX ; X is now 0 STX AUDV0 ; Mute audio channel 0 STX AUDV1 ; Mute audio channel 1 LDX TimerHi ; Use current TimerHi for a short timeout/loop mechanism DEX ; X = TimerHi - 1 PauseLoop JSR CheckResetSwitch ; Allow Reset/Select to break out of pause. This will RTS if no action. CPX TimerHi ; Compare saved TimerHi-1 with current TimerHi BNE PauseLoop_CheckPlayerInput ; If TimerHi has incremented, skip DMA off LDA #CTRL_DMA_OFF STA CTRL PauseLoop_CheckPlayerInput LDA SWCHA ; Read Player 1 Joystick/Difficulty Switches CMP #$F0 ; Check if all P1 joystick directions are high (neutral) BCS PauseLoop_CheckP1Fire ; If neutral or invalid, check P1 fire JSR DisableDMAOnTimeout ; If joystick active & timeout, potentially change CTRL PauseLoop_CheckP1Fire LDA P0CurrentFire ; Check Player 1 fire button state BMI PauseLoop_ProcessPauseButtonState ; If fire pressed, proceed JSR DisableDMAOnTimeout ; If fire not pressed & timeout, potentially change CTRL PauseLoop_ProcessPauseButtonState LDA PrevPausedState ; Get latched/debounced state of Pause BEQ PauseLoop_IfPreviouslyReleasedCheckCurrent ; If PrevPausedState is 0 (was seen as released) ; PrevPausedState is non-zero (was latched as pressed, or seen as still held) LDA SWCHB ; Read current physical switch state AND #SWCHB_Pause_Mask ; Isolate Pause bit EOR #SWCHB_Pause_Mask ; Invert Pause bit (result $00 if physically RELEASED now, $08 if HELD) STA PrevPausedState ; Update internal debounced state BPL PauseLoop ; If $00 (just released) or $08 (still held), continue pause loop PauseLoop_IfPreviouslyReleasedCheckCurrent LDA SWCHB AND #SWCHB_Pause_Mask ; Isolate current physical Pause bit BNE PauseLoop ; If Pause button is high (physically RELEASED), continue pause loop. ; Loop until Pause is physically PRESSED AGAIN. ; Fall-through: Pause button is now physically PRESSED again (value is $00 after AND) ; This is the condition to EXIT the pause state. ResumeGameFromPause PLA TAX ; Restore X register PLA STA TimerLo ; Restore game timers PLA STA TimerHi LDA #$01 ; Set PrevPausedState to 1. This indicates the pause cycle is complete ; and the pause button is considered "up" for the next check in HandleConsoleSwitches. STA PrevPausedState LSR ; A = 0 (from $01 LSR) STA DemoMode ; Clear the temporary DemoMode set during pause LDA #CTRL_DMA_ON_160AB STA CTRL RTS SetupTitleScrText ; The Titlescreen border in Joust has a bunch of slanty angle characters ; that scroll. The following code just sets up the initial slanty char ; indexes in each string. SetupTitleColumns LDA #$30 STA TitleBorderStr0 LDA #$38 STA TitleBorderStr1 LDA #$36 STA TitleBorderStr2 LDA #$3E STA TitleBorderStr3 LDX #$1E SetupTitleRowLoop LDA #$30 STA TitleBorderStr4,X LDA #$34 STA TitleBorderStr5,X DEX DEX BPL SetupTitleRowLoop LDX #$1C STX TitleColorIndex LDA TitleColors,X STA $0191 LDA DelayBetweenTitleColorChanges,X STA TitleColorChangeCountdown LDX #$1C CopyrghtToBuffer LDA StringCopyright,X STA TitleCopyrightCharBuffer,X DEX BPL CopyrghtToBuffer ; Copy character set values that make up most of the JOUST logo. ; The very top and bottom of the logo aren't part of this. LDX #$E7 CopyMiddleTitleLogoDataToRamLoop LDA MiddleTitleLogoDataCharsLUT,X STA TitleScreenLogoCharBuffer,X DEX BNE CopyMiddleTitleLogoDataToRamLoop SetDemoPalette LDX #$0B STX EggsPresentCount LDA PaletteFadeInRed,X STA $01A5 STA P7C1 LDA PaletteFadeInYellow,X STA $01A6 STA P7C2 LDA PaletteFadeInBrown,X STA $01A7 STA P7C3 LDA TitleScreenColorChangeDelayLUT,X STA EnemyBirdCount RTS AnimateTitleScreenFrame DEC TitleColorChangeCountdown BPL DoTitleFrameAnimation DEC TitleColorIndex BPL WrapTitleColorIndex LDA #$1C STA TitleColorIndex WrapTitleColorIndex LDX TitleColorIndex LDA TitleColors,X STA $0191 LDA DelayBetweenTitleColorChanges,X STA TitleColorChangeCountdown DoTitleFrameAnimation INC TitleBorderStr0 ; left-most char in left column LDA TitleBorderStr0 CMP #$38 BCC SkipCharResetStr0 LDA #$30 STA TitleBorderStr0 SkipCharResetStr0 INC TitleBorderStr2 ; left-most char in right column LDA TitleBorderStr2 CMP #$38 BCC SkipCharResetStr2 LDA #$30 STA TitleBorderStr2 SkipCharResetStr2 INC TitleBorderStr1 ; right-most char in left column LDA TitleBorderStr1 CMP #$40 BCC SkipCharResetStr1 LDA #$38 STA TitleBorderStr1 SkipCharResetStr1 INC TitleBorderStr3 ; right-most char in right column LDA TitleBorderStr3 CMP #$40 BCC SkipCharResetStr3 LDA #$38 STA TitleBorderStr3 SkipCharResetStr3 LDX #$1F AnimateTitleFrameColumnsLoop INC TitleBorderStr4,X ; top row and bottom row of 32 characters LDA TitleBorderStr4,X CMP #$38 BCC SkipCharResetStr4plus LDA #$30 STA TitleBorderStr4,X SkipCharResetStr4plus DEX BPL AnimateTitleFrameColumnsLoop CycleTitleScreenPaletteAndCounters LDA ColorChangeTimer BMI CycleColorExit DEC ColorChangeTimer BPL CycleColorExit DEC ColorCycleIndex BPL CycleIndexStillPositive LDA #$0B STA ColorCycleIndex CycleIndexStillPositive LDX ColorCycleIndex LDA PaletteFadeInRed,X STA $01A5 STA P7C1 LDA PaletteFadeInYellow,X STA $01A6 STA P7C2 LDA PaletteFadeInBrown,X STA $01A7 STA P7C3 LDA TitleScreenColorChangeDelayLUT,X STA ColorChangeTimer CycleColorExit RTS UpdatePrevResetStateFlag LDA SWCHB AND #$01 EOR #$01 STA PrevResetState RTS DisableDMAOnTimeout LDA #$40 STA CTRL LDX TimerHi DEX RTS HideOrShowTwoPlayerText .byte 160 ; off-screen HideOrShowOnePlayerText .byte 48 ; on-screen .byte 160 ; off-screen ; 000000000000000011111111111111112222222222222222 ; 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; _0123456789@0123456789@ABCDEGHIJLMNPRSTUVWXYZK() **then the title border and logo chars DifficultyTextXCoordinate .byte $00 .byte $20 .byte $45 .byte $62 DifficultyText .byte $00 .byte $00 .byte $00 .byte $00 .byte $18 ; 'B' .byte $1B ; 'E' .byte $1C ; 'G' .byte $1E ; 'I' .byte $22 ; 'N' .byte $22 ; 'N' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $1E ; 'I' .byte $22 ; 'N' .byte $26 ; 'T' .byte $1B ; 'E' .byte $24 ; 'R' .byte $21 ; 'M' .byte $1B ; 'E' .byte $1A ; 'D' .byte $1E ; 'I' .byte $17 ; 'A' .byte $26 ; 'T' .byte $1B ; 'E' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $17 ; 'A' .byte $0C ; '0' .byte $28 ; 'V' .byte $17 ; 'A' .byte $22 ; 'N' .byte $19 ; 'C' .byte $1B ; 'E' .byte $1A ; 'D' .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $1B ; 'E' .byte $2A ; 'X' .byte $23 ; 'P' .byte $1B ; 'E' .byte $24 ; 'R' .byte $26 ; 'T' .byte $00 .byte $00 StringOnePlayer .byte $00 ; \ These 3 bytes are also .byte $00 ; > part of the "EXPERT" string .byte $00 ; / post-padding. .byte $0C ; '0' .byte $22 ; 'N' .byte $1B ; 'E' .byte $00 ; .byte $23 ; 'P' .byte $20 ; 'L' .byte $17 ; 'A' .byte $2B ; 'Y' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $00 .byte $00 StringTwoPlayer .byte $00 .byte $00 .byte $00 .byte $26 ; 'T' .byte $29 ; 'W' .byte $0C ; '0' .byte $00 .byte $23 ; 'P' .byte $20 ; 'L' .byte $17 ; 'A' .byte $2B ; 'Y' .byte $1B ; 'E' .byte $24 ; 'R' .byte $00 .byte $00 MiddleTitleLogoDataCharsLUT .byte $00, $59, $5A, $5B, $5C, $5D, $5E, $41 .byte $40, $40, $5F, $60, $61, $62, $63, $64 .byte $65, $66, $43, $40, $67, $68, $40, $69 .byte $40, $6A, $6B, $6C, $6D, $6E, $6F, $70 .byte $71, $72, $73, $74, $40, $75, $76, $40 .byte $77, $78, $79, $40, $7A, $7B, $40, $7C .byte $7D, $7E, $46, $43, $40, $7F, $40, $80 .byte $81, $82, $83, $43, $84, $85, $86, $87 .byte $88, $89, $8A, $8B, $8C, $8D, $40, $42 .byte $8E, $8F, $90, $91, $92, $40, $93, $43 .byte $40, $44, $95, $96, $46, $43, $97, $98 .byte $99, $40, $9A, $9B, $9C, $9D, $46, $9E .byte $9F, $A0, $A1, $A2, $40, $42, $45, $A3 .byte $A4, $A5, $A6, $40, $A7, $45, $40, $44 .byte $A8, $A9, $AA, $AB, $AC, $AD, $AE, $AF .byte $B0, $40, $B1, $44, $B2, $40, $B3, $B4 .byte $B5, $B6, $44, $44, $40, $42, $45, $42 .byte $46, $44, $B7, $40, $B8, $45, $40, $B9 .byte $BA, $BB, $BC, $40, $BD, $BE, $BF, $C0 .byte $C1, $C2, $C3, $C4, $41, $40, $C5, $C6 .byte $C7, $C8, $C9, $40, $CA, $CB, $CC, $40 .byte $42, $43, $40, $CD, $44, $CE, $40, $CF .byte $D0, $40, $D1, $D2, $D3, $41, $40, $D4 .byte $D5, $D6, $D7, $D8, $D9, $40, $DA, $41 .byte $40, $DB, $44, $44, $DC, $47, $48, $40 .byte $40, $40, $40, $49, $4A, $4B, $41, $4C .byte $4D, $4E, $4F, $50, $51, $40, $40, $40 .byte $41, $40, $40, $52, $53, $40, $40, $40 .byte $54, $55, $41, $40, $56, $57, $58, $40 DelayBetweenTitleColorChanges .byte $3C, $03, $03, $3C, $03, $03, $03 .byte $03, $03, $3C, $03, $03, $03, $03 .byte $03, $03, $3C, $03, $03, $03, $3C .byte $03, $03, $03, $03, $03, $03, $03 .byte $03 TitleColors .byte $24, $15, $06, $F7, $D6, $C5, $B5 .byte $A5, $95, $85, $76, $67, $58, $49 .byte $3A, $2B, $1D, $1C, $1B, $0C, $0D .byte $0C, $0B, $1A, $19, $28, $27, $26 .byte $25 PaletteFadeInRed .byte $33 .byte $33 .byte $33 .byte $33 .byte $33 .byte $33 .byte $33 .byte $32 .byte $22 .byte $11 .byte $10 .byte $00 PaletteFadeInYellow .byte $1F .byte $1E .byte $1D .byte $1C .byte $1B .byte $1A .byte $18 .byte $16 .byte $22 .byte $11 .byte $10 .byte $00 PaletteFadeInBrown .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $10 .byte $00 TitleScreenColorChangeDelayLUT .byte $FF .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 MuteAudio LDA #$FF STA SFXChannel0Index STA SFXChannel1Index LDA #$00 STA AUDV0 STA AUDV1 RTS SilenceSFXIfPlaying ; Check if this particular sound effect is playing on channel 0 CMP SFXChannel0Index BNE SilenceSFXIfPlayingChannel1 ; yes? then silence it and mark the channel index as available LDA #$00 STA AUDV0 LDA #$FF STA SFXChannel0Index RTS SilenceSFXIfPlayingChannel1 ; Check if this particular sound effect is playing on channel 1 SEC SBC SFXChannel1Index BNE EarlyReturn1 ; yes? then silence it and mark the channel index as available STA AUDV1 LDA #$FF STA SFXChannel1Index EarlyReturn1 RTS ScheduleSFX STA Temp6ASFXIndex LDA GameActiveFlag BNE EarlyReturn1 LDA DemoMode BNE EarlyReturn1 TYA PHA TXA PHA LDY #$01 LDX Temp6ASFXIndex FindFreeSFXChannelLoop LDA.w SFXChannel0Index,Y CMP #$FF BEQ ScheduleSFXChannelY DEY BPL FindFreeSFXChannelLoop ; If we're here there was no free sound effect channel. Instead we'll ; look for a sound effect in the same "interrupt group" and interrupt ; it. LDA SFXChannel1Index AND #$7F TAY LDA SFXInterruptGroups,X CMP SFXInterruptGroups,Y LDY #$01 BCS ScheduleSFXChannelY LDA SFXChannel0Index AND #$7F TAY LDA SFXInterruptGroups,X CMP SFXInterruptGroups,Y BCC SkipScheduleSFX LDY #$00 ScheduleSFXChannelY TXA ORA #$80 STA.w SFXChannel0Index,Y SkipScheduleSFX PLA TAX PLA TAY EarlyReturn2 RTS ServiceSFX LDA DemoMode BNE EarlyReturn2 LDX #$01 ServiceSFXLoop LDY SFXChannel0Index,X INY ; FF is the voice not-in-use flag. FF+1=0 BNE ServiceSFXDoVoice GoServiceSFXVoiceDone JMP ServiceSFXVoiceDone ServiceSFXDoVoice DEY ; undo the previous INY BPL PlaySoundSlice ; If the SFX index top bit it set, the sound was just scheduled. ; We need to do some init. TYA AND #$7F ; clear the "just scheduled" bit STA SFXChannel0Index,X TAY LDA #$01 STA $2100,X LDA #$FF STA $2102,X STA $2104,X STA $2106,X PlaySoundSlice LDA SFX_FreqAndControlDataPtrLoLUT,Y STA $5C LDA SFX_FreqAndControlDataPtrHiLUT,Y STA $5D DEC $2100,X BNE GoServiceSFXVoiceDone LDA SFX_SampleDurationLUT,Y STA $2100,X LDY $2102,X INC $2104,X INC $2106,X INY LDA ($5C),Y CMP #$FF ; sound EOD marker BNE SFXIsStillPlaying STA SFXChannel0Index,X LDA #$00 STA AUDV0,X BEQ GoServiceSFXVoiceDone SFXIsStillPlaying CMP #$FE BEQ SFX_HandleResetAndContinueCommand CMP #$FD BNE SFX_ProcessStandardPitchData INY LDA ($5C),Y STA SFXChannel0Index,X TAY LDA SFX_FreqAndControlDataPtrLoLUT,Y STA $5C LDA SFX_FreqAndControlDataPtrHiLUT,Y STA $5D SFX_HandleResetAndContinueCommand LDY #$00 TYA STA $2104,X STA $2106,X LDA ($5C),Y SFX_ProcessStandardPitchData BPL SFX_ProcessPitchDataFlags INY LDA ($5C),Y STA $2100,X DEY LDA ($5C),Y INY JMP SFX_SetChannelPitch SFX_ProcessPitchDataFlags ASL BPL SFX_ProcessPitchNoiseFlag LSR AND #$BF STA $2100,X TYA STA $2102,X DEC $2106,X DEC $2104,X LDA #$00 STA AUDV0,X BEQ ServiceSFXVoiceDone SFX_ProcessPitchNoiseFlag LSR SFX_SetChannelPitch STA AUDF0,X TYA STA $2102,X LDY SFXChannel0Index,X LDA SFX_VolumeDataPtrLoLUT,Y STA $5C LDA SFX_VolumeDataPtrHiLUT,Y STA $5D LDY $2106,X LDA ($5C),Y BPL SFX_SetChannelVolume DEY SFX_SetChannelVolume STA AUDV0,X TYA STA $2106,X LDY SFXChannel0Index,X LDA SFX_DistortionDataPtrLoLUT,Y STA $5C LDA SFX_DistortionDataPtrHiLUT,Y STA $5D LDY $2104,X LDA ($5C),Y BPL SFX_SetChannelDistortion DEY SFX_SetChannelDistortion STA AUDC0,X TYA STA $2104,X ServiceSFXVoiceDone DEX BMI ExitSFXServiceLoop JMP ServiceSFXLoop ExitSFXServiceLoop RTS SFX_FreqAndControlDataPtrLoLUT .byte <SFX_00_CoinDropAUDF .byte <SFX_01_FreeBirdAUDF .byte <SFX_02_PickupEggAUDF .byte <SFX_03_GameStartAUDF .byte <SFX_04_BirdPlatformBounceAUDF .byte <SFX_05_BirdBirdBounceAUDF .byte <SFX_06_PlayerFootstepAUDF .byte <SFX_07_PterryDefeatedAUDF .byte <SFX_08_PterryChargingAUDF .byte <SFX_09_PlayerBornAUDF .byte <SFX_0A_InvulnerableAUDF .byte <SFX_0B_EggWigglingAUDF .byte <SFX_0C_EnemyBirdBornAUDF .byte <SFX_0D_TrollJumpingAUDF .byte <SFX_0E_PlatformDissolveAUDF .byte <SFX_0F_SkidAUDF .byte <SFX_10_BirdExplosionAUDF .byte <SFX_11_CheepCheepAUDF .byte <SFX_12_PlayerBirdFlapAUDF SFX_VolumeDataPtrLoLUT .byte <SFX_00_CoinDropAUDV .byte <SFX_01_FreeBirdAUDV .byte <SFX_02_PickupEggAUDV .byte <SFX_03_GameStartAUDV .byte <SFX_04_BirdPlatformBounceAUDV .byte <SFX_05_BirdBirdBounceAUDV .byte <SFX_06_PlayerFootstepAUDV .byte <SFX_07_PterryDefeatedAUDV .byte <SFX_08_PterryChargingAUDV .byte <SFX_09_PlayerBornAUDV .byte <SFX_0A_InvulnerableAUDV .byte <SFX_0B_EggWigglingAUDV .byte <SFX_0C_EnemyBirdBornAUDV .byte <SFX_0D_TrollJumpingAUDV .byte <SFX_0E_PlatformDissolveAUDV .byte <SFX_0F_SkidAUDV .byte <SFX_10_BirdExplosionAUDV .byte <SFX_11_CheepCheepAUDV .byte <SFX_12_PlayerBirdFlapAUDV SFX_DistortionDataPtrLoLUT .byte <SFX_00_CoinDropAUDC .byte <SFX_01_FreeBirdAUDC .byte <SFX_02_PickupEggAUDC .byte <SFX_03_GameStartAUDC .byte <SFX_04_BirdPlatformBounceAUDC .byte <SFX_05_BirdBirdBounceAUDC .byte <SFX_06_PlayerFootstepAUDC .byte <SFX_07_PterryDefeatedAUDC .byte <SFX_08_PterryChargingAUDC .byte <SFX_09_PlayerBornAUDC .byte <SFX_0A_InvulnerableAUDC .byte <SFX_0B_EggWigglingAUDC .byte <SFX_0C_EnemyBirdBornAUDC .byte <SFX_0D_TrollJumpingAUDC .byte <SFX_0E_PlatformDissolveAUDC .byte <SFX_0F_SkidAUDC .byte <SFX_10_BirdExplosionAUDC .byte <SFX_11_CheepCheepAUDC .byte <SFX_12_PlayerBirdFlapAUDC SFX_DistortionDataPtrHiLUT .byte >SFX_00_CoinDropAUDC .byte >SFX_01_FreeBirdAUDC .byte >SFX_02_PickupEggAUDC .byte >SFX_03_GameStartAUDC .byte >SFX_04_BirdPlatformBounceAUDC .byte >SFX_05_BirdBirdBounceAUDC .byte >SFX_06_PlayerFootstepAUDC .byte >SFX_07_PterryDefeatedAUDC .byte >SFX_08_PterryChargingAUDC .byte >SFX_09_PlayerBornAUDC .byte >SFX_0A_InvulnerableAUDC .byte >SFX_0B_EggWigglingAUDC .byte >SFX_0C_EnemyBirdBornAUDC .byte >SFX_0D_TrollJumpingAUDC .byte >SFX_0E_PlatformDissolveAUDC .byte >SFX_0F_SkidAUDC .byte >SFX_10_BirdExplosionAUDC .byte >SFX_11_CheepCheepAUDC .byte >SFX_12_PlayerBirdFlapAUDC SFX_VolumeDataPtrHiLUT .byte >SFX_00_CoinDropAUDV .byte >SFX_01_FreeBirdAUDV .byte >SFX_02_PickupEggAUDV .byte >SFX_03_GameStartAUDV .byte >SFX_04_BirdPlatformBounceAUDV .byte >SFX_05_BirdBirdBounceAUDV .byte >SFX_06_PlayerFootstepAUDV .byte >SFX_07_PterryDefeatedAUDV .byte >SFX_08_PterryChargingAUDV .byte >SFX_09_PlayerBornAUDV .byte >SFX_0A_InvulnerableAUDV .byte >SFX_0B_EggWigglingAUDV .byte >SFX_0C_EnemyBirdBornAUDV .byte >SFX_0D_TrollJumpingAUDV .byte >SFX_0E_PlatformDissolveAUDV .byte >SFX_0F_SkidAUDV .byte >SFX_10_BirdExplosionAUDV .byte >SFX_11_CheepCheepAUDV .byte >SFX_12_PlayerBirdFlapAUDV SFX_FreqAndControlDataPtrHiLUT .byte >SFX_00_CoinDropAUDF .byte >SFX_01_FreeBirdAUDF .byte >SFX_02_PickupEggAUDF .byte >SFX_03_GameStartAUDF .byte >SFX_04_BirdPlatformBounceAUDF .byte >SFX_05_BirdBirdBounceAUDF .byte >SFX_06_PlayerFootstepAUDF .byte >SFX_07_PterryDefeatedAUDF .byte >SFX_08_PterryChargingAUDF .byte >SFX_09_PlayerBornAUDF .byte >SFX_0A_InvulnerableAUDF .byte >SFX_0B_EggWigglingAUDF .byte >SFX_0C_EnemyBirdBornAUDF .byte >SFX_0D_TrollJumpingAUDF .byte >SFX_0E_PlatformDissolveAUDF .byte >SFX_0F_SkidAUDF .byte >SFX_10_BirdExplosionAUDF .byte >SFX_11_CheepCheepAUDF .byte >SFX_12_PlayerBirdFlapAUDF SFX_SampleDurationLUT .byte $02, $01, $02, $01, $01, $01, $01, $04 .byte $02, $04, $07, $02, $04, $02, $0E, $01 .byte $02, $01, $01 SFXInterruptGroups .byte $00 ; 00:?coin drop sfx? .byte $09 ; 01:free bird notification sfx .byte $05 ; 02:pickup egg sfx .byte $09 ; 03:game start sfx .byte $02 ; 04:bird bounced off platform sfx .byte $04 ; 05:bird bounced off bird sfx .byte $02 ; 06:player footstep sfx .byte $08 ; 07:pterry defeated sfx .byte $04 ; 08:pterry charging sfx .byte $05 ; 09:player born on platform sfx .byte $05 ; 0A:player invulnerable sfx .byte $00 ; 0B:egg wiggling sfx .byte $03 ; 0C:enemy bird born sfx .byte $04 ; 0D:troll jumping sfx .byte $06 ; 0E:platform dissolve sfx .byte $03 ; 0F:skid sfx .byte $07 ; 10:bird died explosion sfx .byte $00 ; 11:cheep cheep sfx .byte $02 ; 12:player bird flap sfx SFX_00_CoinDropAUDF .byte $0B .byte $0B .byte $11 .byte $11 .byte $0F .byte $0F .byte $17 .byte $17 .byte $00 .byte $00 .byte $00 .byte $00 .byte $0B .byte $0B .byte $11 .byte $11 .byte $0B .byte $0B .byte $11 .byte $11 .byte $0F .byte $0F .byte $17 .byte $17 .byte $00 .byte $00 .byte $FF SFX_00_CoinDropAUDV .byte $04 .byte $00 .byte $03 .byte $00 .byte $02 .byte $00 .byte $01 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $04 .byte $00 .byte $03 .byte $00 .byte $04 .byte $00 .byte $03 .byte $00 .byte $02 .byte $00 .byte $01 .byte $00 .byte $00 .byte $00 SFX_00_CoinDropAUDC .byte $04 .byte $04 .byte $04 .byte $04 .byte $0D .byte $0D .byte $0D .byte $0D .byte $0D .byte $0D .byte $0D .byte $0D .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $8D SFX_01_FreeBirdAUDF .byte $0C .byte $0E .byte $11 .byte $16 .byte $0C .byte $0E .byte $11 .byte $16 .byte $0C .byte $0E .byte $11 .byte $16 .byte $0C .byte $0E .byte $11 .byte $16 .byte $0C .byte $0E .byte $11 .byte $16 .byte $0C .byte $0E .byte $11 .byte $16 .byte $FF SFX_01_FreeBirdAUDV .byte $0B .byte $0B .byte $0B .byte $0B .byte $09 .byte $09 .byte $09 .byte $09 .byte $07 .byte $07 .byte $07 .byte $07 .byte $06 .byte $06 .byte $06 .byte $06 .byte $04 .byte $04 .byte $04 .byte $04 .byte $02 .byte $02 .byte $02 .byte $02 SFX_02_PickupEggAUDF .byte $18 .byte $16 .byte $14 .byte $11 .byte $0F .byte $0D .byte $0B .byte $FF SFX_02_PickupEggAUDV .byte $0B .byte $0A .byte $09 .byte $09 .byte $07 .byte $06 .byte $05 SFX_03_GameStartAUDF .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $07 .byte $FF SFX_03_GameStartAUDV .byte $0F .byte $0F .byte $0A .byte $09 .byte $07 .byte $06 .byte $05 .byte $0E .byte $0E .byte $0A .byte $09 .byte $07 .byte $06 .byte $05 .byte $0C .byte $0C .byte $09 .byte $08 .byte $07 .byte $06 .byte $05 .byte $0B .byte $0B .byte $09 .byte $08 .byte $07 .byte $06 .byte $05 .byte $0A .byte $0A .byte $08 .byte $07 .byte $06 .byte $05 .byte $04 .byte $09 .byte $08 .byte $07 .byte $06 .byte $05 .byte $04 .byte $03 .byte $08 .byte $06 .byte $05 .byte $04 .byte $03 .byte $02 .byte $02 .byte $07 .byte $06 .byte $05 .byte $04 .byte $03 .byte $02 .byte $02 .byte $06 .byte $05 .byte $04 .byte $03 .byte $03 .byte $02 .byte $02 .byte $05 .byte $05 .byte $04 .byte $04 .byte $03 .byte $02 .byte $02 .byte $04 .byte $04 .byte $03 .byte $03 .byte $02 .byte $02 .byte $01 .byte $03 .byte $03 .byte $03 .byte $02 .byte $02 .byte $02 .byte $02 SFX_04_BirdPlatformBounceAUDF .byte $0F .byte $10 .byte $11 .byte $12 .byte $1F .byte $FF SFX_05_BirdBirdBounceAUDF .byte $0F .byte $10 .byte $11 .byte $12 .byte $0F .byte $10 .byte $11 .byte $12 .byte $0F .byte $10 .byte $11 .byte $12 .byte $0F .byte $10 .byte $11 .byte $12 .byte $FF SFX_05_BirdBirdBounceAUDV .byte $08 .byte $08 .byte $08 .byte $08 .byte $06 .byte $06 .byte $06 .byte $06 .byte $04 .byte $04 .byte $04 .byte $04 .byte $02 .byte $02 .byte $02 .byte $02 SFX_06_PlayerFootstepAUDF .byte $04 .byte $FF SFX_07_PterryDefeatedAUDF .byte $0F .byte $14 .byte $18 .byte $1F .byte $0F .byte $14 .byte $18 .byte $1F .byte $0F .byte $14 .byte $18 .byte $1F .byte $0F .byte $14 .byte $18 .byte $1F .byte $18 .byte $1A .byte $1C .byte $1E .byte $1F .byte $FF SFX_08_PterryChargingAUDF .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $07 .byte $08 .byte $09 .byte $0A .byte $0B .byte $0C .byte $0D .byte $0E .byte $0F .byte $FF SFX_08_PterryChargingAUDV .byte $0A .byte $0A .byte $0A .byte $0A .byte $0A .byte $0A .byte $0A .byte $0A .byte $09 .byte $09 .byte $09 .byte $09 .byte $08 .byte $07 .byte $06 .byte $05 .byte $04 SFX_09_PlayerBornAUDF .byte $1F .byte $12 .byte $00 .byte $1E .byte $11 .byte $00 .byte $1D .byte $10 .byte $FF SFX_09_PlayerBornAUDV .byte $08 .byte $08 .byte $00 .byte $08 .byte $08 .byte $00 .byte $08 .byte $08 SFX_0A_InvulnerableAUDF .byte $1F .byte $1F .byte $1E .byte $1E .byte $1D .byte $1C .byte $1B .byte $1A .byte $19 .byte $18 .byte $17 .byte $16 .byte $15 .byte $14 .byte $13 .byte $12 .byte $11 .byte $10 .byte $0F .byte $0E .byte $0D .byte $0C .byte $0B .byte $0A .byte $FF SFX_0A_InvulnerableAUDV .byte $0A .byte $0A .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $08 .byte $07 .byte $06 .byte $05 .byte $04 .byte $03 .byte $02 SFX_0B_EggWigglingAUDF .byte $0D .byte $0B .byte $09 .byte $00 .byte $0D .byte $0B .byte $09 .byte $00 .byte $0D .byte $0B .byte $09 .byte $FF SFX_0B_EggWigglingAUDV .byte $06 .byte $07 .byte $08 .byte $00 .byte $06 .byte $06 .byte $06 .byte $00 .byte $04 .byte $04 .byte $04 SFX_0C_EnemyBirdBornAUDF .byte $1F .byte $1F .byte $1E .byte $1D .byte $1C .byte $1B .byte $1A .byte $19 .byte $18 .byte $17 .byte $16 .byte $15 .byte $14 .byte $13 .byte $12 .byte $11 .byte $FF SFX_0C_EnemyBirdBornAUDV .byte $0A .byte $0A .byte $07 .byte $07 .byte $88 SFX_0D_TrollJumpingAUDF .byte $03 .byte $03 .byte $03 .byte $03 .byte $FF SFX_0D_TrollJumpingAUDV .byte $08 .byte $07 .byte $06 .byte $05 SFX_0E_PlatformDissolveAUDF .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $04 .byte $FF SFX_0E_PlatformDissolveAUDV .byte $04 .byte $05 .byte $06 .byte $07 .byte $07 .byte $07 .byte $05 .byte $04 .byte $03 .byte $01 SFX_0F_SkidAUDF .byte $14 .byte $14 .byte $14 .byte $14 .byte $16 .byte $14 .byte $17 .byte $15 .byte $16 .byte $14 .byte $17 .byte $15 .byte $17 .byte $14 .byte $15 .byte $14 .byte $14 .byte $16 .byte $14 .byte $15 .byte $17 .byte $14 .byte $17 .byte $15 .byte $16 .byte $14 .byte $17 .byte $15 .byte $17 .byte $14 .byte $15 .byte $14 .byte $FE SFX_10_BirdExplosionAUDF .byte $0F .byte $11 .byte $13 .byte $15 .byte $17 .byte $19 .byte $1B .byte $1D .byte $1E .byte $1F .byte $FF SFX_10_BirdExplosionAUDV .byte $09 .byte $09 .byte $08 .byte $07 .byte $06 .byte $05 .byte $04 .byte $03 .byte $02 .byte $01 SFX_11_CheepCheepAUDF .byte $0F .byte $0E .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $0F .byte $0E .byte $0D .byte $0C .byte $0B .byte $0A .byte $09 .byte $08 .byte $00 .byte $00 .byte $FF SFX_12_PlayerBirdFlapAUDF .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $18 .byte $FF SFX_12_PlayerBirdFlapAUDV .byte $03 .byte $03 .byte $03 .byte $06 .byte $06 .byte $06 .byte $05 .byte $05 .byte $05 .byte $02 SFX_07_PterryDefeatedAUDC SFX_0B_EggWigglingAUDC SFX_0D_TrollJumpingAUDC SFX_0E_PlatformDissolveAUDC SFX_10_BirdExplosionAUDC SFX_12_PlayerBirdFlapAUDC .byte $88 SFX_01_FreeBirdAUDC SFX_03_GameStartAUDC SFX_04_BirdPlatformBounceAUDC SFX_05_BirdBirdBounceAUDC SFX_0F_SkidAUDC SFX_11_CheepCheepAUDC .byte $84 SFX_08_PterryChargingAUDC SFX_0A_InvulnerableAUDC .byte $87 SFX_02_PickupEggAUDC SFX_09_PlayerBornAUDC .byte $8D SFX_06_PlayerFootstepAUDC .byte $86 SFX_0C_EnemyBirdBornAUDC .byte $83 SFX_06_PlayerFootstepAUDV SFX_0F_SkidAUDV .byte $88 SFX_04_BirdPlatformBounceAUDV .byte $84 SFX_07_PterryDefeatedAUDV .byte $8A SFX_11_CheepCheepAUDV .byte $82 DoHscStatusCheck JSR InitForHsc LDA #$00 STA $250E JSR $3FF7 ; HSCSTAT check status of HSC and some cart init RTS DoHscAttractMode JSR InitForHsc JSR $3FFA ; HSCATRCT - attract mode score display RestoreCharbaseAndExit LDA #$C8 STA CHARBASE LDA #$00 STA NMIModeFlag RTS DoHscScoreEntry LDA Difficulty STA Temp62 ; save difficulty JSR InitForHsc LDA PlayerCount BEQ HscScoreEntryHandlePlayer1 LDA CurrentPlayer BNE HscScoreEntryHandlePlayer1 STA $250E HscScoreEntryHandlePlayer1 JSR $3FFD ; HSC score entry routine JMP RestoreCharbaseAndExit InitForHsc LDA $3900 ; Check two bytes of the HSC rom to ensure it's CMP #$C6 ; plugged in. BNE AbortUsingHSC LDA $3904 CMP #$FE BNE AbortUsingHSC LDX #$0F CopyArgsToRamLoop LDA HscLUTArgumentBlock-1,X STA $24FF,X DEX BNE CopyArgsToRamLoop LDX #$28 CopyLogoDls LDA HscGameLogoDisplayLists-1,X STA $18B3,X DEX BNE CopyLogoDls LDA #$01 STA NMIModeFlag JSR SetDemoPalette ; update the DL text string for current player... LDA Temp62 TAX ASL ASL ORA CurrentPlayer STA $2502 ; ...and update the DL text string for the difficulty name... LDA DifficultyTextLo,X STA $2506 LDA DifficultyTextHi,X STA $2507 LDA CurrentPlayer BEQ CopyP0ScoreToHscRam CopyP1ScoreToHscRam LDA #$00 STA $27AF LDX #$03 CopyP1ScoreLoop LDA P1Score-1,X STA $27AF,X DEX BNE CopyP1ScoreLoop JMP ReturnFromHSCInit CopyP0ScoreToHscRam LDX #$03 CopyP0ScoreLoop LDA P0Score-1,X STA $27AF,X DEX BNE CopyP0ScoreLoop ReturnFromHSCInit LDX #$00 LDY #$25 RTS AbortUsingHSC PLA PLA RTS HscLUTArgumentBlock ; we copy this to ram for actual use .byte $8B,$23 ; Joust's HSC Game ID .byte $00 ; Game Difficulty .byte $00 ; Game Controller .byte $00,$00 ; Game Name (Lo,Hi) .byte $C0,$D9 ; Difficulty Name (Lo,Hi) .byte $AF,$27 ; Game Score (Lo,Hi) .byte <HscGameLogoDisplayListList, >HscGameLogoDisplayListList .byte $70,$D9 ; Sound Routine (Lo,Hi) .byte $04 ; HS Display Time HscGameLogoDisplayListList .byte $8F,$27,$CB .byte $08,$27,$CB .byte $07,$18,$B4 .byte $07,$18,$BB .byte $07,$18,$C2 .byte $07,$18,$C9 .byte $07,$18,$D0 HscGameLogoDisplayLists .byte $CD,$40,$C0,$F2,$3C .byte $00,$00 .byte $DB,$40,$C0,$EF,$30 .byte $00,$00 .byte $DD,$40,$C8,$F1,$30 .byte $00,$00 .byte $EC,$40,$C8,$EF,$2C .byte $00,$00 .byte $EC,$40,$C0,$EF,$2C .byte $EC,$80,$C0,$FF,$A0 .byte $00,$00 ; "BEGINNER" WATKINS "^" ; space $D9C0 WATKINS "^" ; space $D9C1 WATKINS "^" ; space $D9C2 WATKINS "^" ; space $D9C3 WATKINS "^" ; space $D9C4 WATKINS "^" ; space $D9C5 WATKINS "^" ; space $D9C6 WATKINS "^" ; space $D9C7 WATKINS "^" ; space $D9C8 WATKINS "B" ; $D9C9 WATKINS "E" ; $D9CA WATKINS "G" ; $D9CB WATKINS "I" ; $D9CC WATKINS "N" ; $D9CD WATKINS "N" ; $D9CE WATKINS "E" ; $D9CF WATKINS "R" ; $D9D0 WATKINS "^" ; space $D9D1 WATKINS "^" ; space $D9D2 WATKINS "^" ; space $D9D3 ; "INTERMEDIATE" WATKINS "^" ; space $D9D4 WATKINS "^" ; space $D9D5 WATKINS "^" ; space $D9D6 WATKINS "^" ; space $D9D7 WATKINS "^" ; space $D9D8 WATKINS "^" ; space $D9D9 WATKINS "I" ; $D9DA WATKINS "N" ; $D9DB WATKINS "T" ; $D9DC WATKINS "E" ; $D9DD WATKINS "R" ; $D9DE WATKINS "M" ; $D9DF WATKINS "E" ; $D9E0 WATKINS "D" ; $D9E1 WATKINS "I" ; $D9E2 WATKINS "A" ; $D9E3 WATKINS "T" ; $D9E4 WATKINS "E" ; $D9E5 ; "ADVANCED" WATKINS "^" ; space $D9E6 WATKINS "^" ; space $D9E7 WATKINS "^" ; space $D9E8 WATKINS "^" ; space $D9E9 WATKINS "^" ; space $D9EA WATKINS "^" ; space $D9EB WATKINS "^" ; space $D9EC WATKINS "^" ; space $D9ED WATKINS "^" ; space $D9EE WATKINS "A" ; $D9EF WATKINS "D" ; $D9F0 WATKINS "V" ; $D9F1 WATKINS "A" ; $D9F2 WATKINS "N" ; $D9F3 WATKINS "C" ; $D9F4 WATKINS "E" ; $D9F5 WATKINS "D" ; $D9F6 ; "EXPERT" WATKINS "^" ; space $D9F7 WATKINS "^" ; space $D9F8 WATKINS "^" ; space $D9F9 WATKINS "^" ; space $D9FA WATKINS "^" ; space $D9FB WATKINS "^" ; space $D9FC WATKINS "^" ; space $D9FD WATKINS "^" ; space $D9FE WATKINS "^" ; space $D9FF WATKINS "^" ; space $DA00 WATKINS "E" ; $DA01 WATKINS "X" ; $DA02 WATKINS "P" ; $DA03 WATKINS "E" ; $DA04 WATKINS "R" ; $DA05 WATKINS "T" ; $DA06 WATKINS "^" ; space $DA07 WATKINS "^" ; space $DA08 WATKINS "^" ; space $DA09 WATKINS "^" ; space $DA0A WATKINS "^" ; space $DA0B WATKINS "^" ; space $DA0C WATKINS "^" ; space $DA0D WATKINS "^" ; space $DA0E WATKINS "^" ; space $DA0F WATKINS "^" ; space $DA10 ; pointers to previous HSC/Watkins encoded text strings DifficultyTextLo .byte $C0 ; BEGINNER text pointer lo .byte $D4 ; INTERMEDIATE text pointer lo .byte $E6 ; ADVANCED text pointer lo .byte $F7 ; EXPERT text pointer lo DifficultyTextHi .byte $D9 ; BEGINNER text pointer hi .byte $D9 ; INTERMEDIATE text pointer hi .byte $D9 ; ADVANCED text pointer hi .byte $D9 ; EXPERT text pointer hi TitlePalette .byte $00 ; P0C1 .byte $00 ; P0C2 .byte $00 ; P0C3 .byte $FA ; P1C1 .byte $FF ; P1C2 .byte $CF ; P1C3 .byte $0D ; P2C1 .byte $0D ; P2C2 .byte $0D ; P2C3 .byte $0D ; P3C1 .byte $0D ; P3C2 .byte $0D ; P3C3 .byte $0D ; P4C1 .byte $0D ; P4C2 .byte $0D ; P4C3 .byte $0D ; P5C1 .byte $0D ; P5C2 .byte $0D ; P5C3 .byte $0D ; P6C1 .byte $0D ; P6C2 .byte $0D ; P6C3 .byte $00 ; P7C1 .byte $00 ; P7C2 .byte $00 ; P7C3 GamePalette .byte $1A ; P0C1 .byte $10 ; P0C2 .byte $14 ; P0C3 .byte $00 ; P1C1 .byte $29 ; P1C2 .byte $32 ; P1C3 .byte $46 ; P2C1 .byte $09 ; P2C2 .byte $84 ; P2C3 .byte $1E ; P3C1 .byte $BC ; P3C2 .byte $00 ; P3C3 .byte $39 ; P4C1 .byte $0D ; P4C2 .byte $33 ; P4C3 .byte $15 ; P5C1 .byte $A9 ; P5C2 .byte $85 ; P5C3 .byte $0D ; P6C1 .byte $1C ; P6C2 .byte $44 ; P6C3 .byte $16 ; P7C1 .byte $E3 ; P7C2 .byte $E8 ; P7C3 TitleScrCharacterObjectLoLUT .byte <$18FE .byte <$1958 .byte <$1C2A .byte <$18FA .byte <$1954 .byte <$1950 .byte <$194C .byte <$1C26 .byte <$1C22 .byte <$1C1E .byte <$1D93 .byte <$1DED .byte <$1E48 TitleScrCharacterObjectHiLUT .byte >$18FE .byte >$1958 .byte >$1C2A .byte >$18FA .byte >$1954 .byte >$1950 .byte >$194C .byte >$1C26 .byte >$1C22 .byte >$1C1E .byte >$1D93 .byte >$1DED .byte >$1E48 TitleScrSpriteObjectLoLUT .byte <$C05E .byte <$C067 .byte <$C082 .byte <$C064 .byte <$C068 .byte <$C072 .byte <$C07C .byte <$C08B .byte <$C095 .byte <$C09F .byte <$C0A5 .byte <$C0B2 .byte <$C0BF TitleScrSpriteObjectHiLUT .byte >$C05E .byte >$C067 .byte >$C082 .byte >$C064 .byte >$C068 .byte >$C072 .byte >$C07C .byte >$C08B .byte >$C095 .byte >$C09F .byte >$C0A5 .byte >$C0B2 .byte >$C0BF TitleScrDLAddrLoLUT .byte <$1EA1, <$1F55, <$1EFB, <$1FC1, <$1FC6, <$184E, <$1853, <$1FD7 .byte <$1FDC, <$18AD, <$18A8, <$1907, <$1902, <$1961, <$195C, <$19BB .byte <$19B6, <$1A16, <$1A11, <$1A70, <$1A6B, <$1ACA, <$1AC5, <$1B25 .byte <$1B20, <$1B7F, <$1B7A, <$1BD9, <$1BD4, <$1C33, <$1C2E, <$1C8D .byte <$1C88, <$1CE7, <$1CE2, <$1D42, <$1D3D, <$1D9C, <$1D97, <$1DF6 .byte <$1DF1, <$1E51, <$1E4C, <$1EAB, <$1EA6, <$1F05, <$1F00, <$1F5F .byte <$1F5A, <$1FBA, <$1FB5, <$1FCB, <$1FD0, <$19B1, <$19AC, <$19A7 .byte <$19A2, <$1A0C, <$1A07, <$1A02, <$19FD, <$1A66, <$1A61, <$1A5C .byte <$1A57, <$1AC0, <$1ABB, <$1AB6, <$1AB1, <$1B1B, <$1B16, <$1B11 .byte <$1B0C, <$1B75, <$1B70, <$1B6B, <$1B66, <$1BCF, <$1BCA, <$1BC5 .byte <$1BC0 TitleScrDLAddrHiLUT .byte >$1EA1, >$1F55, >$1EFB, >$1FC1, >$1FC6, >$184E, >$1853, >$1FD7 .byte >$1FDC, >$18AD, >$18A8, >$1907, >$1902, >$1961, >$195C, >$19BB .byte >$19B6, >$1A16, >$1A11, >$1A70, >$1A6B, >$1ACA, >$1AC5, >$1B25 .byte >$1B20, >$1B7F, >$1B7A, >$1BD9, >$1BD4, >$1C33, >$1C2E, >$1C8D .byte >$1C88, >$1CE7, >$1CE2, >$1D42, >$1D3D, >$1D9C, >$1D97, >$1DF6 .byte >$1DF1, >$1E51, >$1E4C, >$1EAB, >$1EA6, >$1F05, >$1F00, >$1F5F .byte >$1F5A, >$1FBA, >$1FB5, >$1FCB, >$1FD0, >$19B1, >$19AC, >$19A7 .byte >$19A2, >$1A0C, >$1A07, >$1A02, >$19FD, >$1A66, >$1A61, >$1A5C .byte >$1A57, >$1AC0, >$1ABB, >$1AB6, >$1AB1, >$1B1B, >$1B16, >$1B11 .byte >$1B0C, >$1B75, >$1B70, >$1B6B, >$1B66, >$1BCF, >$1BCA, >$1BC5 .byte >$1BC0 TitleScrCharObject_LoAddress .byte <$2685, <$2699, <$26AD, <$2244, <$2251, <$2204, <$2204, <$2204 .byte <$2204, <$2200, <$2202, <$2200, <$2202, <$2200, <$2202, <$2200 .byte <$2202, <$2200, <$2202, <$2200, <$2202, <$2200, <$2202, <$2200 .byte <$2202, <$2200, <$2202, <$2200, <$2202, <$2200, <$2202, <$2200 .byte <$2202, <$2200, <$2202, <$2200, <$2202, <$2200, <$2202, <$2200 .byte <$2202, <$2200, <$2202, <$2200, <$2202, <$2200, <$2202, <$2200 .byte <$2202, <$2200, <$2202, <$2200, <$2202, <$2261, <$2268, <$2272 .byte <$227C, <$2281, <$2289, <$2293, <$229D, <$22A3, <$22AB, <$22B5 .byte <$22BF, <$22C3, <$22C9, <$22D3, <$22DD, <$22DF, <$22E9, <$22F3 .byte <$22FD, <$2302, <$230C, <$2316, <$2320, <$2325, <$232F, <$2339 .byte <$2343 TitleScrCharObject_HiAddress .byte >$2685, >$2699, >$26AD, >$2244, >$2251, >$2204, >$2204, >$2204 .byte >$2204, >$2200, >$2202, >$2200, >$2202, >$2200, >$2202, >$2200 .byte >$2202, >$2200, >$2202, >$2200, >$2202, >$2200, >$2202, >$2200 .byte >$2202, >$2200, >$2202, >$2200, >$2202, >$2200, >$2202, >$2200 .byte >$2202, >$2200, >$2202, >$2200, >$2202, >$2200, >$2202, >$2200 .byte >$2202, >$2200, >$2202, >$2200, >$2202, >$2200, >$2202, >$2200 .byte >$2202, >$2200, >$2202, >$2200, >$2202, >$2261, >$2268, >$2272 .byte >$227C, >$2281, >$2289, >$2293, >$229D, >$22A3, >$22AB, >$22B5 .byte >$22BF, >$22C3, >$22C9, >$22D3, >$22DD, >$22DF, >$22E9, >$22F3 .byte >$22FD, >$2302, >$230C, >$2316, >$2320, >$2325, >$232F, >$2339 .byte >$2343 TitleScrCharObject_PalleteWidth .byte $90, $90, $90, $93, $90, $00, $08, $00 .byte $08, $1E, $1E, $1E, $1E, $1E, $1E, $1E .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E .byte $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E .byte $1E, $1E, $1E, $1E, $1E, $F9, $F6, $F6 .byte $FB, $F8, $F6, $F6, $FA, $F8, $F6, $F6 .byte $FC, $FA, $F6, $F6, $FE, $F6, $F6, $F6 .byte $FB, $F6, $F6, $F6, $FB, $F6, $F6, $F6 .byte $FB TitleScrCharObject_XCoordinate .byte $A0, $A0, $A0, $10, $50, $00, $80, $00 .byte $80, $00, $9A, $00, $9A, $00, $9A, $00 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00 .byte $9A, $00, $9A, $00, $9A, $00, $9A, $00 .byte $9A, $00, $9A, $00, $9A, $17, $31, $57 .byte $7D, $13, $31, $57, $7D, $13, $31, $57 .byte $7D, $1B, $31, $57, $7D, $0B, $31, $57 .byte $7D, $0B, $31, $57, $7D, $0B, $31, $57 .byte $7D DllLUT .byte $0F,$27,$CB .byte $08,$27,$CB .byte $47,$18,$4E .byte $47,$18,$A8 .byte $47,$18,$A8 .byte $47,$18,$A8 .byte $47,$18,$FA .byte $47,$19,$4C .byte $47,$19,$A2 .byte $47,$19,$FD .byte $47,$1A,$57 .byte $47,$1A,$B1 .byte $47,$1B,$0C .byte $47,$1B,$66 .byte $47,$1B,$C0 .byte $47,$1C,$1E .byte $47,$1D,$3D .byte $47,$1D,$93 .byte $47,$1D,$ED .byte $47,$1E,$48 .byte $47,$1E,$A1 .byte $47,$1E,$FB .byte $47,$1F,$55 .byte $47,$1F,$B5 .byte $47,$1F,$C1 .byte $47,$1F,$D7 .byte $0F,$27,$CB .byte $06,$27,$CB .byte $8F,$27,$CB GameDLStartLutLo .byte <$1A17, <$1A13, <$1A6D, <$1A71, <$1C30, <$1C34, <$1C8E, <$1C82 .byte <$1C86, <$1C8A, <$1D43, <$1F58, <$1F54, <$1F5C, <$1F60, <$1F50 .byte <$1F4C, <$1FAE, <$1FAA, <$1FB6, <$1FB2, <$1FA6, <$1FA2, <$1FC1 .byte <$1FC5, <$1FD1, <$1FC9, <$1FCD, <$1FD7, <$1FDB, <$1FE7, <$1FDF .byte <$1FE3 GameDLStartLutHi .byte >$1A17, >$1A13, >$1A6D, >$1A71, >$1C30, >$1C34, >$1C8E, >$1C82 .byte >$1C86, >$1C8A, >$1D43, >$1F58, >$1F54, >$1F5C, >$1F60, >$1F50 .byte >$1F4C, >$1FAE, >$1FAA, >$1FB6, >$1FB2, >$1FA6, >$1FA2, >$1FC1 .byte >$1FC5, >$1FD1, >$1FC9, >$1FCD, >$1FD7, >$1FDB, >$1FE7, >$1FDF .byte >$1FE3 BackgroundSpriteGfxLoLUT .byte <$A8A4, <$A0FB, <$A8AA, <$A8BA, <$A897, <$A8BA, <$A8A0, <$C008 .byte <$C011, <$A8BA, <$C017, <$C000, <$C000, <$A08E, <$A8BA, <$C020 .byte <$C020, <$AF8E, <$AF8E, <$A0A9, <$A8BE, <$C03C, <$C03C, <$AF8E .byte <$AF8E, <$A0C4, <$A8C0, <$A8C2, <$AF8E, <$AF8E, <$A0DE, <$A8C0 .byte <$A8C2 BackgroundSpriteGfxHiLUT .byte >$A8A4, >$A0FB, >$A8AA, >$A8BA, >$A897, >$A8BA, >$A8A0, >$C008 .byte >$C011, >$A8BA, >$C017, >$C000, >$C000, >$A08E, >$A8BA, >$C020 .byte >$C020, >$AF8E, >$AF8E, >$A0A9, >$A8BE, >$C03C, >$C03C, >$AF8E .byte >$AF8E, >$A0C4, >$A8C0, >$A8C2, >$AF8E, >$AF8E, >$A0DE, >$A8C0 .byte >$A8C2 BackgroundSpritePaletteWidthLUT .byte $1A, $1B, $14, $5C, $17, $5C, $1C, $17 .byte $1A, $5C, $17, $18, $18, $05, $5C, $3E .byte $3E, $37, $37, $05, $3F, $3E, $3E, $37 .byte $37, $06, $3F, $3F, $37, $37, $03, $3F .byte $3F BackgroundSpriteXCoordLUT .byte $88, $00, $2E, $38, $6D, $7A, $7C, $00 .byte $8B, $05, $37, $FD, $82, $19, $3B, $F7 .byte $A2, $A0, $A0, $1B, $B0, $F7, $A2, $A0 .byte $A0, $1B, $B0, $B0, $F9, $84, $15, $B0 .byte $B0 HUDCharDLAddrLoLUT .byte <$19BB .byte <$1ACA .byte <$1B7F .byte <$1DF6 .byte <$1FBA .byte <$1FEB HUDCharDLAddrHiLUT .byte >$19BB .byte >$1ACA .byte >$1B7F .byte >$1DF6 .byte >$1FBA .byte >$1FEB MsgAndHUDCharObjectStringLoLUT .byte <$2671 .byte <$2685 .byte <$2699 .byte <$26AD .byte <$2659 .byte <$2200 MsgAndHUDCharObjectStringHiLUT .byte >$2671 .byte >$2685 .byte >$2699 .byte >$26AD .byte >$2659 .byte >$2200 MsgAndHUDCharObjectPaletteAndWidthLUT .byte $90 .byte $90 .byte $90 .byte $90 .byte $68 .byte $92 MsgAndHUDCharObjectXLUT .byte $2E .byte $2E .byte $2E .byte $2E .byte $20 .byte $A8 DisplayListLoLUT .byte <$1858, <$18B2, <$190C, <$1966, <$19BB, <$1A13, <$1A6D, <$1ACA .byte <$1B2A, <$1B7F, <$1BDE, <$1C30, <$1C82, <$1CEC, <$1D43, <$1DA1 .byte <$1DF6, <$1E56, <$1EB0, <$1F0A, <$1F4C, <$1FA2, <$1FC1, <$1FD7 DisplayListHiLUT .byte >$1858, >$18B2, >$190C, >$1966, >$19BB, >$1A13, >$1A6D, >$1ACA .byte >$1B2A, >$1B7F, >$1BDE, >$1C30, >$1C82, >$1CEC, >$1D43, >$1DA1 .byte >$1DF6, >$1E56, >$1EB0, >$1F0A, >$1F4C, >$1FA2, >$1FC1, >$1FD7 ES_LavaSparkleAnimationPtrLoLUT .byte <$1FB2 .byte <$1FC9 .byte <$1FCD .byte <$1FDF .byte <$1FE3 ES_LavaSparkleAnimationPtrHiLUT .byte >$1FB2 .byte >$1FC9 .byte >$1FCD .byte >$1FDF .byte >$1FE3 SpawnPlatformDLObjectLoLUT .byte <$1F60 .byte <$1C8A .byte <$1C34 .byte <$1A71 SpawnPlatformDLObjectHiLUT .byte >$1F60 .byte >$1C8A .byte >$1C34 .byte >$1A71 SpawnRiderPaletteAndWidthLUT .byte $B6, $BA ; spawning player rider .byte $BA, $BA, $BA, $BA, $BA, $BA, $BA, $BA ; spawning enemy rider SpawnPlatformPaletteAndWidthLUT .byte $7C, $7C ; spawning platform with player bird on it .byte $9C, $9C, $9C, $9C, $9C, $9C, $9C, $9C ; spawinging platform with enemy birds SpawnBirdPaletteAndWidthLUT .byte $BE, $DE ; spawning player birds .byte $9E, $9E, $9E, $9E, $9E, $9E, $9E, $9E ; spawning enemy birds AITimerDistantAggressive_ByType .byte $02 .byte $03 .byte $01 .byte $02 .byte $FF AITimerDistantPassive_Or_ApproachAggressive_ByType .byte $03 .byte $03 .byte $02 .byte $03 PterryYVelocitySlightUp .byte $FF AITimerApproachPassive_ByType .byte $04 .byte $04 .byte $04 .byte $05 .byte $FF AITimerCloseDefensive_ByType .byte $05 .byte $06 .byte $06 .byte $07 PterryYVelocityZero .byte $00 AITimerEngagePassive_ByType .byte $08 .byte $08 .byte $09 .byte $0A .byte $01 AITimerMixedEngageAttack_ByType .byte $0A .byte $0B .byte $0C .byte $0B PterryYVelocitySlightDown .byte $01 AITimerAttackAggressive_ByType .byte $0C .byte $0C .byte $0F .byte $0E .byte $01 ; the below tables are largely involved in enemy vertical velocity calcs BirdWeightByTypeLUT .byte $0C,$14,$1E,$26,$00 BirdFlapLiftFactorLoLUT .byte $80,$00,$5A,$DC,$00 BirdFlapLiftFactorHiLUT .byte $00,$01,$01,$01,$01 BirdMaxDownVelocityByTypeLUT .byte $04,$04,$04,$04,$02 BirdMaxUpVelocityByTypeLUT .byte $FC,$FC,$FC,$FC,$FD AITimerByBirdTypeAndDifficultyLoLUT .byte $00, $00, $00, $00, $C0, $A0, $80, $40 AITimerByBirdTypeAndDifficultyHiLUT .byte $10, $04, $02, $01, $00, $00, $00, $00 AIModeByBirdTypeAndDifficultyLUT .byte $7F,$05,$04,$03,$7F,$04,$03,$02,$7F,$03,$02,$01 TurnCheckTimerValuesLoLUT .byte $00,$00,$00,$40,$00,$E0,$C0,$A0,$80,$00,$80,$40 TurnCheckTimerValuesHiLUT .byte $10,$03,$02,$01,$01,$00,$00,$00,$02,$02,$01,$01 ; 16-bit speed index tables. ; The fastest left-heading speed is the first value. ; The neutral non-moving speed is the middle value. ; The fastest right-heading speed is the last value. ; These apply to player and enemy birds. XPositionIncrementTableLoLUT .byte $20,$D0,$60,$E0,$80,$00,$80,$20,$A0,$30,$E0 XPositionIncrementTableHiLUT .byte $FD,$FD,$FE,$FE,$FF,$00,$00,$01,$01,$02,$02 BirdAIActionCategoryByProximityLUT .byte $03,$04,$04,$FF,$02,$00,$03,$FF,$01,$01,$02 TrollGrabHeight ; If a bird object is at this Y the troll will grab it (game level is index) .byte $B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B3,$B5,$B5,$B5 .byte $BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA,$BA InitialBirdDirection .byte $01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01 PlayerRespawnY .byte $A7,$67,$5F,$37 PlayerRespawnX .byte $5E,$29,$9D,$5B ObjectScreenWrapXRightEdgeLUT .byte $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE, $BE ; Birds .byte $C2, $C2, $C2 ; Pterrys .byte $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $BB ; Eggs ObjectScreenWrapXLeftEdgeLUT .byte $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A, $1A ; Birds .byte $16, $16, $16 ; Pterrys .byte $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F, $1F ; Eggs ; enemy levels are 0:red-bounder, 1:gray-hunter, 2:blue-shadowlord ; this table says enemy upgrades are 0->1, 1->2, and 2->2. NextEnemyBirdLevel .byte $01, $02, $02 PterrySpritePaletteAndWidthLUT .byte $9C .byte $9C .byte $9C .byte $1C .byte $1C .byte $1C UNUSED_TitleMenuTextAddrLoLUT .byte <$2671 .byte <$2685 .byte <$2699 .byte <$26AD UNUSED_TitleMenuTextAddrHiLUT .byte >$2671 .byte >$2685 .byte >$2699 .byte >$26AD UNUSED_TitleMenuDLZoneLUT .byte $03 .byte $08 .byte $0C .byte $10 ; packed 2-bit enemy type data, first set of 4 enemies for each wave... EnemyWaveDataLUT_A .byte $3F, $0F, $0F, $03, $03, $00, $00, $00 .byte $00, $00, $00, $54, $54, $55, $55, $55 .byte $55, $55, $55, $55, $95, $95, $95, $A5 .byte $A9, $AA, $AA, $AA, $AA, $AA, $AA, $AA .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA .byte $AA, $AA, $AA, $AA, $AA, $AA, $AA, $AA .byte $AA, $AA, $AA, $AA ; packed 2-bit enemy type data, second set of 4 enemies for each wave EnemyWaveDataLUT_B .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $3F .byte $3F, $0F, $0F, $0F, $0F, $0F, $5F, $5F .byte $03, $43, $57, $55, $5F, $5F, $5F, $5F .byte $5F, $5F, $5F, $5F, $95, $95, $5F, $95 .byte $55, $A5, $5F, $A5, $A5, $AA, $AF, $AA .byte $AA, $AA, $AF, $AA, $AA, $AA, $AF, $AA .byte $AA, $AA, $AF, $AA .byte "GCC(C)1984" ; not used by the game, just an embedded text .byte $4C .byte $00 .byte $B0 .byte $3F .byte $39 .byte $34 CART_SIGNATURE_DUPE ; DF80-DFF7 .byte $04,$C4,$76,$30,$6A,$8C,$8A,$3A,$CA,$F5,$BC,$71,$CA,$76,$08,$AB .byte $75,$58,$CD,$19,$2A,$29,$2E,$F0,$DB,$7B,$84,$98,$A4,$0E,$0A,$7C .byte $3F,$D8,$93,$8D,$59,$98,$FA,$77,$03,$FF,$E9,$9B,$70,$A8,$B3,$A5 .byte $AA,$E7,$7F,$82,$CF,$DD,$5F,$F4,$54,$79,$BA,$D7,$6D,$73,$26,$CE .byte $B3,$06,$39,$94,$BA,$74,$A1,$E7,$8F,$AF,$6C,$B2,$E2,$74,$70,$0B .byte $2E,$68,$F2,$4F,$27,$E2,$AA,$4D,$F7,$B0,$CD,$C6,$9D,$B1,$42,$59 .byte $CE,$0D,$59,$14,$13,$8E,$71,$5C,$A0,$09,$4E,$00,$85,$99,$E7,$CA .byte $E4,$A5,$D9,$A1,$2B,$47,$A4,$CE .byte $FF ; region verification. $FF=all regions .byte $E7 ; encryption check starts at $E000 .word NMI_ROUTINE .word START .word IRQ_ROUTINE ; This rom is a bit weird, in that the last 2 8k blocks are identical ; including the cart vectors and encryption key. ; ; block 1: the graphics and code are live/used, except for the ; brief "jmp $B000" located at DF7A. The encryption key, BIOS bytes, ; and 6502 vectors are dead/unused. ; ; block 2: the graphics and code are dead/unused, except for the ; brief "jmp $B000" located at FF7A. The encryption key, BIOS bytes, ; and 6502 vectors are (of course) used. ; ; I've left the dead parts of block 2 as uninterpreted byte values, ; to avoid confusion with the active code in block 1. ; ; So... Joust has just under 8K unused in block 2, ready and waiting ; for rom hacks. ; ; This is block 2 of 2... ; ORG $E000 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $2a,$a0,$2a,$80,$2a,$20,$aa,$00,$a8,$00,$aa,$00,$aa,$00,$aa,$80 .byte $aa,$a0,$aa,$a0,$aa,$a0,$aa,$a0,$2a,$a0,$2a,$a0,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$11,$48,$22,$8c,$33,$c8,$aa,$aa .byte $ea,$54,$00,$10,$6a,$aa,$a8,$a0,$aa,$aa,$95,$56,$ab,$7a,$a9,$57 .byte $00,$d0,$6a,$aa,$a5,$5a,$aa,$aa,$aa,$a0,$00,$00,$00,$15,$55,$56 .byte $aa,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$03,$00,$33,$00,$c0,$33,$00,$c0,$0c,$c0,$cc .byte $30,$00,$00,$c0,$00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$0c,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$a0,$0a,$aa,$56 .byte $9a,$90,$36,$a9,$6a,$aa,$80,$00,$55,$aa,$00,$09,$7a,$a6,$a5,$fe .byte $a5,$a9,$54,$d6,$a5,$aa,$bd,$66,$56,$ab,$70,$00,$00,$00,$a0,$00 .byte $02,$a0,$00,$00,$a8,$02,$aa,$02,$a0,$00,$00,$aa,$00,$44,$f0,$81 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$eb,$cf,$ff,$00,$00,$00 .byte $00,$00,$00,$0f,$cf,$00,$00,$00,$00,$ff,$a0,$00,$00,$00,$00,$00 .byte $2a,$80,$2a,$80,$2a,$00,$aa,$00,$aa,$00,$aa,$00,$aa,$00,$aa,$80 .byte $aa,$80,$aa,$a0,$aa,$a0,$aa,$80,$aa,$a0,$2a,$a0,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$04,$48,$08,$8c,$0c,$c8,$2a,$aa .byte $aa,$94,$00,$10,$aa,$aa,$a8,$a0,$aa,$aa,$95,$56,$ab,$fe,$a9,$57 .byte $00,$d0,$6a,$aa,$a5,$56,$aa,$aa,$aa,$a0,$00,$00,$00,$00,$55,$55 .byte $aa,$80,$00,$00,$2a,$ab,$f4,$00,$00,$00,$00,$aa,$80,$00,$00,$00 .byte $00,$2a,$aa,$a8,$00,$5a,$aa,$a0,$00,$00,$00,$00,$00,$00,$00,$0a .byte $aa,$a0,$00,$00,$00,$03,$30,$0c,$00,$c0,$0c,$00,$c0,$0f,$00,$cc .byte $30,$00,$00,$30,$00,$00,$00,$00,$03,$ff,$ff,$ff,$ff,$ff,$f0,$0f .byte $fc,$03,$f3,$c3,$cf,$00,$00,$fc,$03,$00,$f0,$28,$28,$02,$a9,$5a .byte $9e,$90,$36,$a9,$5a,$aa,$40,$00,$01,$5a,$a0,$0a,$fa,$a6,$a5,$fa .byte $a5,$6a,$54,$d6,$a6,$aa,$d7,$a6,$a5,$ab,$fa,$80,$00,$0a,$ab,$c0 .byte $0a,$a9,$00,$02,$aa,$86,$aa,$0a,$a8,$00,$7a,$aa,$b0,$0c,$f0,$63 .byte $00,$00,$00,$00,$00,$00,$00,$00,$fa,$bf,$ff,$ea,$be,$f3,$ff,$c0 .byte $00,$00,$00,$ea,$fb,$ea,$ff,$00,$03,$fa,$bf,$fa,$80,$00,$00,$00 .byte $0a,$80,$0a,$80,$2a,$80,$2a,$80,$2a,$80,$aa,$80,$aa,$80,$aa,$80 .byte $2a,$80,$aa,$80,$2a,$80,$aa,$80,$aa,$80,$aa,$80,$aa,$a8,$af,$a8 .byte $ae,$a8,$aa,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$aa,$a8,$aa,$a8 .byte $aa,$a8,$2a,$a8,$2a,$a8,$2a,$a8,$04,$48,$08,$8c,$0c,$c8,$0a,$aa .byte $aa,$94,$00,$10,$aa,$aa,$a8,$20,$aa,$aa,$55,$4a,$aa,$7e,$a9,$57 .byte $00,$d0,$6a,$aa,$a5,$56,$aa,$aa,$aa,$80,$00,$00,$00,$00,$05,$55 .byte $6a,$a0,$00,$00,$aa,$aa,$bf,$d0,$00,$00,$a0,$aa,$ab,$40,$00,$00 .byte $00,$aa,$aa,$aa,$30,$5a,$aa,$a0,$01,$56,$a8,$00,$00,$00,$70,$aa .byte $aa,$aa,$b0,$00,$00,$03,$0c,$00,$00,$c0,$00,$03,$00,$0c,$c0,$cf .byte $f0,$00,$00,$0f,$fc,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$00,$30 .byte $03,$0c,$0c,$3c,$30,$c0,$f3,$03,$03,$03,$0c,$80,$08,$00,$55,$4a .byte $ae,$90,$06,$aa,$16,$a9,$00,$00,$00,$00,$00,$0a,$ba,$a5,$a9,$da .byte $a5,$6a,$54,$d6,$a6,$aa,$fd,$a6,$aa,$aa,$aa,$00,$00,$2a,$aa,$7f .byte $2a,$aa,$f0,$02,$aa,$a6,$aa,$6a,$aa,$3f,$6a,$aa,$a0,$00,$12,$91 .byte $00,$00,$00,$00,$00,$00,$00,$00,$ff,$aa,$aa,$ba,$ab,$fa,$ee,$a0 .byte $00,$00,$02,$aa,$ab,$ff,$ff,$00,$3f,$eb,$ff,$ab,$fa,$c0,$00,$00 .byte $0a,$80,$0a,$80,$0a,$80,$0a,$80,$2a,$80,$2a,$80,$2a,$80,$2a,$80 .byte $2a,$80,$2a,$80,$2a,$80,$2a,$80,$2a,$80,$aa,$80,$bb,$a8,$ba,$a8 .byte $ae,$e8,$ba,$ab,$be,$a8,$ba,$a0,$3b,$a8,$3a,$a8,$be,$a8,$3a,$a8 .byte $ba,$a8,$3b,$e8,$3a,$e8,$3a,$a8,$45,$48,$8a,$8c,$cf,$c8,$02,$aa .byte $aa,$94,$00,$10,$aa,$a8,$00,$20,$aa,$a9,$54,$0a,$aa,$be,$a9,$57 .byte $00,$d0,$6a,$aa,$a8,$55,$aa,$aa,$aa,$00,$00,$00,$00,$00,$00,$05 .byte $52,$a8,$00,$0a,$aa,$aa,$af,$fd,$40,$00,$a0,$aa,$aa,$f4,$00,$00 .byte $02,$aa,$aa,$aa,$90,$5a,$aa,$a0,$15,$aa,$aa,$a0,$00,$07,$e0,$aa .byte $aa,$aa,$a8,$00,$00,$00,$c3,$00,$00,$c0,$00,$0c,$00,$0c,$30,$00 .byte $30,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$c0 .byte $03,$0c,$0c,$0c,$c0,$33,$0f,$03,$03,$03,$03,$00,$00,$00,$00,$0a .byte $a6,$90,$06,$aa,$00,$00,$00,$00,$00,$00,$00,$0a,$aa,$a5,$a9,$5a .byte $95,$6a,$50,$d6,$a6,$aa,$76,$a6,$aa,$aa,$a8,$00,$00,$aa,$aa,$5d .byte $ea,$aa,$ff,$0a,$aa,$aa,$a9,$aa,$aa,$bf,$aa,$aa,$a8,$00,$12,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$fe,$ff,$ff,$ff,$ff,$ea,$ba,$a8 .byte $00,$00,$0e,$ee,$af,$ff,$ff,$00,$af,$ef,$ee,$bf,$fa,$af,$c0,$00 .byte $0a,$80,$0a,$80,$0a,$80,$0a,$80,$0a,$80,$0a,$80,$2a,$00,$2a,$80 .byte $2a,$80,$2a,$80,$2a,$80,$2a,$00,$2a,$20,$2a,$80,$ae,$a8,$ae,$a0 .byte $aa,$a0,$ab,$a0,$af,$a0,$af,$a0,$af,$a0,$2e,$a8,$2f,$a8,$ab,$b8 .byte $2b,$a8,$2f,$e8,$ae,$a8,$2b,$a8,$15,$48,$2a,$8c,$3f,$c8,$00,$2a .byte $aa,$a4,$00,$00,$aa,$00,$00,$00,$2a,$95,$00,$0a,$aa,$bf,$a9,$57 .byte $00,$10,$6a,$aa,$a8,$05,$aa,$aa,$a8,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$2a,$aa,$aa,$a9,$5f,$fc,$02,$a0,$aa,$aa,$7f,$c0,$00 .byte $02,$aa,$aa,$aa,$a0,$5a,$aa,$81,$5a,$aa,$aa,$aa,$0f,$ff,$60,$aa .byte $aa,$aa,$aa,$80,$00,$30,$03,$00,$3f,$ff,$ff,$f0,$00,$0c,$00,$00 .byte $30,$00,$00,$0f,$c0,$fc,$03,$c0,$fc,$00,$15,$55,$55,$54,$00,$c0 .byte $ff,$0c,$0c,$0f,$00,$0c,$03,$03,$03,$03,$03,$00,$00,$00,$00,$02 .byte $ab,$94,$06,$aa,$00,$00,$00,$00,$00,$00,$00,$00,$aa,$a9,$aa,$aa .byte $95,$6a,$50,$d6,$aa,$aa,$ba,$a6,$aa,$aa,$a0,$00,$02,$aa,$aa,$97 .byte $aa,$aa,$9d,$fa,$aa,$aa,$a9,$aa,$aa,$b5,$aa,$aa,$aa,$0b,$b0,$38 .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$fd,$55,$55,$57,$aa,$ea,$ab .byte $c0,$00,$ff,$ef,$ab,$bf,$ff,$03,$eb,$fa,$bf,$ff,$eb,$ff,$ff,$a8 .byte $2a,$00,$8a,$00,$0a,$00,$02,$80,$02,$a0,$0a,$a0,$0a,$80,$0a,$80 .byte $2a,$00,$2a,$00,$2a,$00,$2a,$20,$2a,$00,$2a,$00,$bb,$a0,$ab,$a0 .byte $ab,$a0,$ae,$80,$ae,$80,$ae,$80,$ab,$a0,$ae,$a0,$af,$eb,$af,$a8 .byte $2f,$e8,$ab,$a8,$ab,$e8,$ab,$e8,$05,$50,$0a,$a0,$0f,$f0,$00,$0a .byte $aa,$a8,$00,$00,$80,$00,$00,$00,$00,$00,$00,$2a,$aa,$af,$aa,$57 .byte $00,$10,$6a,$aa,$a8,$00,$02,$aa,$80,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$aa,$aa,$aa,$aa,$55,$ff,$ca,$a0,$aa,$aa,$97,$fd,$00 .byte $0a,$aa,$aa,$aa,$a0,$5a,$aa,$85,$6a,$aa,$aa,$aa,$bf,$fd,$60,$aa .byte $aa,$aa,$aa,$a0,$00,$30,$03,$00,$00,$c0,$00,$00,$00,$0c,$00,$c0 .byte $30,$00,$00,$30,$33,$03,$0c,$33,$03,$00,$aa,$aa,$aa,$aa,$00,$c0 .byte $00,$03,$f0,$0c,$00,$0c,$00,$fc,$fc,$fc,$03,$00,$00,$00,$00,$00 .byte $2a,$a4,$0a,$aa,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$a9,$6a,$aa .byte $95,$da,$50,$36,$a9,$aa,$aa,$a6,$aa,$aa,$80,$00,$02,$aa,$aa,$9f .byte $aa,$aa,$b7,$ea,$aa,$aa,$ad,$aa,$aa,$a6,$aa,$aa,$aa,$3d,$f2,$fe .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$55,$75,$55,$55,$55,$d5,$af,$ff .byte $fc,$03,$ff,$ff,$ea,$bf,$ff,$ff,$fa,$ff,$ff,$ff,$bf,$ff,$ff,$af .byte $28,$00,$28,$00,$08,$00,$02,$80,$02,$a0,$02,$a0,$02,$a0,$0a,$a0 .byte $28,$a0,$28,$20,$aa,$00,$28,$20,$28,$28,$a8,$80,$aa,$a0,$ae,$a0 .byte $ae,$80,$aa,$80,$aa,$00,$aa,$00,$aa,$80,$ab,$a0,$af,$a0,$aa,$e0 .byte $ab,$a0,$2b,$a0,$ab,$a0,$ae,$a0,$01,$08,$02,$0c,$03,$08,$00,$00 .byte $aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0a,$aa,$a7,$aa,$57 .byte $00,$10,$6a,$aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$aa,$aa,$aa,$aa,$57,$f7,$ea,$a0,$aa,$aa,$ad,$ff,$f0 .byte $0a,$aa,$aa,$aa,$a0,$9a,$aa,$b5,$aa,$aa,$aa,$aa,$af,$fd,$a0,$aa .byte $aa,$aa,$aa,$a8,$00,$0c,$0c,$00,$00,$00,$00,$00,$00,$cc,$00,$00 .byte $33,$00,$00,$c0,$0c,$00,$f0,$0c,$00,$c0,$00,$00,$00,$00,$00,$c0 .byte $00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$03,$00,$00,$00,$00,$00 .byte $0a,$a4,$0a,$80,$00,$00,$00,$00,$00,$00,$00,$00,$02,$a9,$6a,$aa .byte $96,$da,$50,$36,$a9,$aa,$aa,$a1,$5a,$aa,$a0,$00,$0a,$aa,$aa,$95 .byte $aa,$aa,$95,$ea,$aa,$aa,$ad,$aa,$aa,$ae,$aa,$aa,$aa,$2a,$a0,$89 .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$55,$d5,$55,$55,$55,$75,$55,$55 .byte $55,$15,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55 .byte $88,$00,$08,$00,$08,$00,$00,$00,$00,$20,$00,$20,$00,$20,$00,$88 .byte $02,$00,$28,$80,$a0,$00,$00,$00,$22,$08,$a0,$20,$aa,$a0,$aa,$a0 .byte $aa,$80,$ae,$00,$ae,$00,$ba,$00,$aa,$00,$aa,$80,$aa,$a0,$aa,$a0 .byte $aa,$80,$2a,$a0,$2a,$a0,$aa,$80,$05,$08,$0a,$0c,$0f,$08,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$aa,$ab,$ea,$54 .byte $00,$10,$6a,$aa,$a8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$02,$aa,$aa,$aa,$aa,$95,$77,$ea,$a0,$aa,$aa,$a5,$df,$ff .byte $2a,$aa,$aa,$aa,$a0,$aa,$aa,$95,$aa,$aa,$aa,$aa,$af,$75,$a0,$aa .byte $aa,$aa,$aa,$aa,$00,$03,$f0,$00,$00,$00,$00,$00,$03,$00,$00,$00 .byte $00,$c0,$03,$00,$33,$00,$c0,$33,$00,$c0,$0c,$30,$cf,$f0,$00,$c0 .byte $00,$00,$00,$00,$00,$0c,$00,$00,$00,$00,$03,$00,$00,$00,$00,$00 .byte $00,$a8,$08,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$2a,$2a,$aa .byte $56,$da,$50,$36,$a9,$6a,$aa,$a0,$05,$56,$a8,$00,$2a,$aa,$aa,$a6 .byte $aa,$6a,$af,$ea,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$a5,$6a,$2e,$a1,$d0 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $aa,$aa,$6a,$5a,$96,$a5,$a9,$aa,$90,$a0,$a0,$a0,$a0,$a0,$60,$50 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$0a,$97,$7f,$ea,$aa,$aa,$a7,$5d .byte $7f,$ea,$95,$aa,$af,$75,$aa,$aa,$aa,$02,$aa,$aa,$aa,$95,$aa,$aa .byte $55,$55,$aa,$95,$57,$0f,$50,$9a,$aa,$9d,$aa,$5a,$a0,$aa,$aa,$aa .byte $a8,$00,$02,$95,$7f,$a9,$5a,$50,$7f,$fe,$95,$5a,$55,$5f,$3f,$56 .byte $aa,$bf,$d7,$5a,$50,$56,$aa,$af,$d5,$40,$00,$00,$00,$00,$6a,$a9 .byte $70,$5d,$ff,$a5,$6a,$5f,$fd,$ab,$f5,$56,$aa,$a9,$5d,$55,$aa,$a8 .byte $00,$00,$55,$a9,$50,$55,$57,$a5,$57,$5d,$50,$6a,$a9,$55,$dd,$55 .byte $5a,$a9,$60,$a0,$02,$aa,$95,$55,$a5,$95,$55,$55,$a0,$ab,$55,$aa .byte $95,$d5,$6a,$aa,$96,$95,$55,$55,$56,$2a,$aa,$a5,$9a,$a0,$5a,$95 .byte $fe,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$aa,$05,$5a,$a6 .byte $a5,$56,$a5,$a9,$55,$56,$a5,$f5,$6a,$a5,$6a,$80,$2a,$a9,$ea,$a6 .byte $a9,$5a,$a7,$ea,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$95,$5a,$00,$e0,$85 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$10 .byte $aa,$6a,$5a,$96,$a5,$a9,$aa,$aa,$a0,$a0,$a0,$a0,$a0,$60,$50,$90 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$0a,$a5,$5f,$aa,$aa,$aa,$a9,$dd .byte $df,$aa,$95,$aa,$a9,$d6,$aa,$aa,$aa,$00,$2a,$aa,$aa,$95,$aa,$a9 .byte $55,$57,$aa,$95,$57,$03,$d0,$96,$aa,$aa,$aa,$5a,$a0,$aa,$aa,$aa .byte $a8,$00,$02,$a7,$5f,$a9,$5a,$70,$fd,$de,$95,$5a,$55,$5f,$3f,$5a .byte $aa,$75,$75,$6a,$a0,$55,$aa,$ab,$dd,$55,$40,$00,$00,$00,$6a,$a9 .byte $70,$5d,$7f,$a5,$6a,$5f,$fd,$ab,$f7,$56,$aa,$a5,$d5,$d5,$aa,$a8 .byte $00,$00,$00,$a9,$50,$d5,$75,$a5,$57,$fd,$50,$6a,$a9,$7d,$d7,$55 .byte $6a,$a5,$60,$a0,$02,$aa,$95,$55,$a5,$95,$55,$55,$60,$ab,$55,$aa .byte $75,$55,$6a,$aa,$56,$95,$55,$40,$00,$aa,$aa,$55,$56,$90,$5a,$95 .byte $7a,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$6a,$00,$5a,$a6 .byte $a5,$56,$a5,$a9,$55,$56,$af,$55,$6a,$95,$6a,$80,$aa,$a5,$7a,$a6 .byte $a9,$5a,$a5,$aa,$aa,$aa,$ad,$aa,$aa,$aa,$aa,$95,$5a,$00,$b0,$01 .byte $00,$54,$54,$54,$54,$04,$54,$54,$10,$54,$04,$00,$a8,$a8,$a8,$a8 .byte $08,$a8,$a8,$20,$a8,$08,$00,$88,$a0,$28,$a0,$a8,$a8,$88,$a8,$20 .byte $a8,$88,$88,$80,$88,$a8,$20,$a8,$20,$88,$88,$20,$a8,$88,$41,$04 .byte $6a,$5a,$96,$a5,$a9,$aa,$aa,$aa,$a0,$a0,$a0,$a0,$60,$50,$90,$a0 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$2a,$a5,$df,$aa,$aa,$aa,$a9,$d5 .byte $dd,$aa,$d5,$aa,$ab,$56,$aa,$aa,$aa,$00,$02,$aa,$aa,$95,$6a,$a9 .byte $55,$57,$6a,$a5,$57,$03,$d0,$96,$aa,$aa,$aa,$5a,$a0,$aa,$aa,$aa .byte $a8,$00,$02,$a9,$df,$aa,$5a,$50,$5f,$da,$95,$56,$95,$5f,$3f,$5a .byte $ab,$d7,$5d,$aa,$a0,$95,$6a,$ab,$ff,$fd,$80,$00,$00,$01,$6a,$a9 .byte $50,$7f,$7f,$a5,$5a,$7f,$cf,$aa,$d5,$5a,$aa,$ad,$55,$55,$aa,$aa .byte $40,$00,$00,$ab,$50,$57,$57,$a5,$df,$fd,$50,$6a,$ab,$ff,$75,$55 .byte $6a,$a7,$60,$a0,$00,$aa,$55,$55,$a5,$95,$55,$55,$60,$ab,$d5,$aa .byte $57,$55,$aa,$aa,$56,$95,$00,$00,$00,$aa,$a9,$55,$56,$90,$5a,$95 .byte $7a,$aa,$aa,$aa,$aa,$d5,$6a,$aa,$aa,$aa,$9a,$a5,$6a,$00,$0a,$a6 .byte $a5,$56,$a5,$a9,$55,$56,$af,$d5,$aa,$b5,$6a,$80,$2a,$95,$5a,$a6 .byte $a5,$56,$a5,$aa,$aa,$aa,$a5,$aa,$5a,$aa,$aa,$55,$56,$80,$30,$eb .byte $00,$44,$10,$40,$04,$04,$04,$44,$10,$44,$04,$54,$88,$20,$80,$08 .byte $08,$08,$88,$20,$88,$08,$a8,$a8,$88,$80,$88,$80,$88,$88,$20,$88 .byte $80,$88,$a8,$80,$a0,$08,$20,$88,$20,$a8,$88,$20,$80,$88,$44,$04 .byte $5a,$96,$a5,$a9,$aa,$aa,$aa,$6a,$a0,$a0,$a0,$60,$50,$90,$a0,$a0 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$00,$aa,$a5,$57,$aa,$aa,$aa,$aa,$77 .byte $5d,$aa,$d5,$aa,$aa,$da,$aa,$aa,$aa,$00,$00,$aa,$aa,$95,$6a,$a9 .byte $55,$77,$6a,$a5,$57,$03,$d0,$96,$aa,$aa,$aa,$55,$50,$aa,$aa,$5a .byte $aa,$00,$02,$aa,$77,$aa,$56,$90,$f5,$da,$95,$56,$95,$5f,$3f,$5a .byte $ab,$75,$d5,$aa,$a0,$aa,$aa,$aa,$fe,$aa,$80,$00,$00,$05,$6a,$aa .byte $50,$7f,$fe,$a5,$5a,$5f,$fd,$aa,$d5,$6a,$aa,$97,$5d,$55,$aa,$aa .byte $00,$00,$00,$a9,$50,$5d,$77,$a5,$5f,$fd,$d0,$6a,$ab,$ff,$57,$55 .byte $aa,$95,$60,$a0,$00,$aa,$55,$55,$a5,$95,$55,$55,$60,$ab,$55,$a9 .byte $d5,$55,$aa,$aa,$56,$90,$00,$00,$00,$aa,$a9,$55,$55,$90,$5a,$95 .byte $5a,$aa,$aa,$aa,$ab,$d5,$6a,$aa,$a6,$aa,$9a,$95,$6a,$00,$0a,$a6 .byte $a5,$5e,$a5,$a9,$55,$56,$ad,$d6,$aa,$55,$6a,$80,$2a,$95,$5a,$a6 .byte $a5,$56,$a5,$aa,$95,$aa,$a5,$a9,$56,$aa,$aa,$55,$56,$80,$a2,$14 .byte $00,$44,$10,$54,$14,$54,$54,$54,$10,$54,$54,$54,$88,$20,$a8,$28 .byte $a8,$a8,$a8,$20,$a8,$a8,$a8,$88,$a0,$80,$88,$a0,$88,$a8,$20,$08 .byte $80,$88,$a8,$a8,$a8,$20,$20,$88,$88,$88,$20,$20,$20,$a0,$44,$04 .byte $96,$a5,$a9,$aa,$aa,$aa,$6a,$5a,$a0,$a0,$60,$50,$90,$a0,$a0,$a0 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$02,$aa,$a5,$76,$aa,$aa,$aa,$aa,$75 .byte $7d,$aa,$d5,$6a,$aa,$da,$aa,$aa,$aa,$00,$00,$0a,$aa,$a5,$6a,$a9 .byte $55,$9f,$6a,$a5,$57,$03,$d0,$95,$aa,$aa,$aa,$03,$50,$55,$55,$56 .byte $aa,$00,$02,$aa,$9e,$aa,$56,$90,$5f,$5a,$55,$56,$95,$5f,$0f,$5a .byte $ab,$dd,$d6,$aa,$a0,$aa,$aa,$aa,$aa,$aa,$00,$00,$00,$57,$6a,$aa .byte $70,$77,$5e,$a5,$5a,$5c,$fd,$aa,$d5,$6a,$aa,$75,$55,$55,$6a,$aa .byte $40,$00,$00,$a9,$50,$d5,$f7,$a5,$5f,$cd,$50,$6a,$ab,$ff,$f5,$56 .byte $aa,$9d,$60,$a0,$00,$2a,$55,$55,$a5,$55,$55,$d5,$50,$ab,$55,$a9 .byte $75,$55,$aa,$a9,$56,$80,$00,$00,$00,$2a,$a5,$55,$55,$50,$56,$95 .byte $5a,$aa,$aa,$aa,$ab,$55,$6a,$aa,$55,$aa,$9a,$95,$5a,$00,$0a,$a6 .byte $a5,$7e,$a5,$a9,$55,$56,$ad,$5a,$aa,$75,$5a,$80,$0a,$95,$5a,$a6 .byte $a5,$56,$a5,$aa,$55,$6a,$a5,$a9,$d6,$aa,$aa,$55,$56,$a8,$04,$06 .byte $00,$44,$50,$04,$04,$44,$40,$40,$04,$44,$44,$f4,$88,$a0,$08,$08 .byte $88,$80,$80,$08,$88,$88,$f8,$88,$88,$80,$88,$80,$80,$88,$20,$08 .byte $80,$a8,$a8,$88,$88,$80,$20,$88,$88,$88,$88,$88,$08,$a0,$44,$04 .byte $a5,$a9,$aa,$aa,$aa,$6a,$5a,$96,$a0,$60,$50,$90,$a0,$a0,$a0,$a0 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$0a,$aa,$a9,$56,$aa,$aa,$aa,$aa,$55 .byte $de,$aa,$d5,$6a,$aa,$da,$aa,$95,$5a,$00,$00,$00,$aa,$a5,$4a,$a9 .byte $56,$9f,$7a,$a5,$57,$00,$d0,$95,$aa,$aa,$aa,$00,$10,$55,$55,$55 .byte $aa,$80,$02,$aa,$aa,$aa,$56,$a0,$77,$6a,$55,$56,$95,$5f,$0f,$fa .byte $ab,$77,$5a,$aa,$a0,$aa,$aa,$aa,$aa,$a0,$00,$00,$05,$7f,$6a,$aa .byte $70,$75,$de,$a5,$5a,$5f,$fd,$aa,$d5,$aa,$a9,$f7,$75,$55,$6a,$aa .byte $94,$00,$00,$a9,$50,$5d,$77,$a5,$5f,$fd,$50,$6a,$ab,$f7,$55,$5a .byte $aa,$95,$50,$a0,$00,$2a,$55,$55,$a5,$55,$55,$55,$50,$ab,$d5,$a7 .byte $55,$56,$aa,$a9,$55,$80,$00,$00,$00,$2a,$a5,$55,$55,$50,$56,$a5 .byte $5a,$aa,$96,$aa,$ab,$55,$6a,$a9,$d5,$6a,$9a,$95,$5a,$00,$0a,$a6 .byte $a5,$7e,$a5,$a9,$55,$56,$ad,$6a,$ab,$55,$5a,$a0,$0a,$55,$5a,$a6 .byte $a5,$56,$a5,$aa,$55,$5a,$ad,$a5,$5a,$a9,$aa,$55,$00,$80,$f9,$5f .byte $00,$54,$10,$54,$54,$44,$54,$54,$54,$54,$54,$54,$a8,$20,$a8,$a8 .byte $88,$a8,$a8,$a8,$a8,$a8,$a8,$20,$a0,$28,$a0,$a8,$a8,$88,$a8,$08 .byte $80,$88,$88,$a8,$a8,$a8,$a8,$88,$88,$88,$88,$88,$a8,$88,$41,$04 .byte $a9,$aa,$aa,$aa,$6a,$5a,$96,$a5,$60,$50,$90,$a0,$a0,$a0,$a0,$a0 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$0a,$aa,$a9,$56,$aa,$95,$aa,$aa,$5d .byte $de,$aa,$d5,$6a,$aa,$9a,$aa,$55,$56,$00,$00,$00,$0a,$a9,$0a,$a5 .byte $56,$af,$7a,$a5,$57,$00,$d0,$a5,$6a,$aa,$a8,$00,$00,$55,$55,$55 .byte $6a,$a0,$02,$aa,$aa,$aa,$56,$a0,$77,$6a,$55,$55,$95,$57,$0f,$5a .byte $ab,$5f,$5a,$aa,$a0,$aa,$aa,$aa,$aa,$80,$00,$00,$55,$5f,$5a,$aa .byte $70,$5f,$fe,$a5,$5a,$5f,$cd,$aa,$55,$aa,$a9,$f7,$d6,$55,$5a,$aa .byte $b5,$00,$00,$a9,$70,$55,$ff,$a5,$7c,$ff,$50,$5a,$ab,$f5,$d5,$6a .byte $aa,$75,$50,$ab,$00,$09,$55,$57,$a5,$55,$57,$55,$50,$ab,$55,$ad .byte $55,$56,$aa,$a9,$55,$80,$00,$00,$00,$0a,$95,$55,$55,$50,$56,$a5 .byte $6a,$a9,$55,$5a,$ab,$55,$aa,$a5,$55,$6a,$9a,$95,$5a,$00,$5a,$a6 .byte $a5,$fe,$a5,$a9,$55,$56,$ad,$6a,$a5,$55,$5a,$a0,$02,$55,$5a,$a6 .byte $a5,$56,$a5,$a9,$55,$5a,$a5,$a5,$5a,$a5,$aa,$50,$00,$a8,$10,$90 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$10 .byte $aa,$aa,$aa,$6a,$5a,$96,$a5,$a9,$50,$90,$a0,$a0,$a0,$a0,$a0,$60 .byte $aa,$a0,$a9,$5a,$55,$6a,$50,$2a,$aa,$a9,$76,$aa,$55,$6a,$aa,$95 .byte $7e,$aa,$d5,$6a,$aa,$9a,$a9,$55,$55,$00,$00,$00,$00,$a8,$02,$a5 .byte $56,$af,$7a,$a5,$57,$00,$d0,$a5,$6a,$aa,$a8,$00,$00,$05,$55,$55 .byte $5a,$a8,$00,$2a,$aa,$aa,$55,$a0,$9d,$aa,$55,$55,$95,$57,$0f,$9a .byte $aa,$77,$6a,$aa,$a0,$aa,$aa,$aa,$aa,$00,$00,$02,$55,$df,$5a,$aa .byte $50,$f7,$7e,$95,$5a,$5f,$3f,$aa,$56,$aa,$ad,$dd,$da,$59,$56,$aa .byte $ad,$50,$00,$a9,$50,$75,$df,$a5,$5f,$fd,$50,$5a,$ab,$fd,$55,$aa .byte $aa,$55,$50,$a8,$00,$00,$00,$77,$a5,$55,$75,$75,$50,$ab,$d5,$95 .byte $d5,$5a,$aa,$a9,$55,$80,$00,$00,$00,$0a,$95,$55,$55,$50,$56,$a5 .byte $6a,$a5,$55,$55,$ab,$55,$aa,$9d,$55,$6a,$96,$95,$56,$05,$7a,$a6 .byte $a5,$fe,$a5,$a9,$57,$d6,$a5,$aa,$ad,$d5,$56,$ad,$02,$55,$5a,$a6 .byte $a5,$56,$a5,$a9,$55,$5a,$a5,$b5,$5a,$a5,$aa,$00,$00,$00,$d0,$28 .byte $a5,$79,$c9,$35,$d0,$02,$e6,$7a,$4c,$3d,$d0,$a9,$01,$85,$4a,$d0 .byte $0d,$a9,$00,$85,$4a,$a5,$7a,$d0,$05,$e6,$79,$4c,$3d,$d0,$a9,$00 .byte $85,$79,$85,$7a,$f0,$17,$ad,$82,$02,$29,$02,$f0,$06,$a9,$00,$85 .byte $55,$10,$10,$c6,$55,$10,$0c,$20,$5a,$d0,$20,$65,$d0,$20,$5f,$d0 .byte $20,$7a,$d0,$a5,$4d,$c5,$56,$d0,$03,$4c,$a0,$b0,$a5,$4e,$c5,$4e .byte $f0,$fc,$4c,$a3,$9f,$a9,$20,$85,$54,$60,$a9,$20,$85,$55,$60,$a6 .byte $4d,$ca,$86,$56,$60,$e6,$4c,$a5,$4c,$c9,$04,$30,$0a,$a9,$00,$85 .byte $4c,$a5,$4a,$49,$01,$85,$4a,$4c,$e9,$b4,$a6,$4a,$bd,$aa,$d2,$8d .byte $a5,$1e,$bd,$ab,$d2,$8d,$59,$1f,$a5,$4c,$aa,$0a,$0a,$0a,$0a,$18 .byte $69,$b1,$85,$5e,$a9,$00,$69,$d2,$85,$5f,$a0,$0f,$b1,$5e,$99,$ad .byte $26,$88,$10,$f8,$bd,$ad,$d2,$8d,$ff,$1e,$a5,$7a,$c9,$29,$d0,$16 .byte $a5,$4e,$29,$03,$c9,$03,$d0,$0e,$ce,$96,$1d,$ce,$f0,$1d,$ce,$4b .byte $1e,$a9,$01,$8d,$ce,$27,$60,$a5,$52,$10,$0e,$a5,$58,$d0,$0d,$ad .byte $82,$02,$4a,$b0,$f1,$a9,$01,$85,$58,$4c,$94,$b0,$4c,$98,$d2,$a5 .byte $52,$10,$f6,$ad,$80,$02,$c9,$f0,$b0,$21,$4c,$9a,$b0,$a5,$4b,$d0 .byte $ee,$a5,$57,$d0,$0d,$ad,$82,$02,$29,$08,$d0,$0f,$a9,$01,$85,$57 .byte $d0,$38,$ad,$82,$02,$29,$08,$49,$08,$85,$57,$a5,$58,$d0,$0c,$ad .byte $82,$02,$4a,$b0,$09,$a9,$01,$85,$58,$d0,$be,$20,$98,$d2,$a5,$59 .byte $d0,$0e,$ad,$82,$02,$29,$02,$d0,$10,$a9,$01,$85,$59,$4c,$9a,$b0 .byte $ad,$82,$02,$29,$02,$49,$02,$85,$59,$60,$a5,$4d,$48,$a5,$4e,$48 .byte $8a,$48,$a2,$01,$86,$4b,$ca,$86,$19,$86,$1a,$a6,$4d,$ca,$20,$0b .byte $d1,$e4,$4d,$d0,$04,$a9,$60,$85,$3c,$ad,$80,$02,$c9,$f0,$b0,$03 .byte $20,$a2,$d2,$a5,$52,$30,$03,$20,$a2,$d2,$a5,$57,$f0,$0b,$ad,$82 .byte $02,$29,$08,$49,$08,$85,$57,$10,$d5,$ad,$82,$02,$29,$08,$d0,$ce .byte $68,$aa,$68,$85,$4e,$68,$85,$4d,$a9,$01,$85,$57,$4a,$85,$4b,$a9 .byte $40,$85,$3c,$60,$a9,$30,$8d,$00,$22,$a9,$38,$8d,$01,$22,$a9,$36 .byte $8d,$02,$22,$a9,$3e,$8d,$03,$22,$a2,$1e,$a9,$30,$9d,$04,$22,$a9 .byte $34,$9d,$05,$22,$ca,$ca,$10,$f2,$a2,$1c,$86,$70,$bd,$12,$d4,$8d .byte $91,$01,$bd,$f5,$d3,$85,$71,$a2,$1c,$bd,$c5,$98,$9d,$44,$22,$ca .byte $10,$f7,$a2,$e7,$bd,$0d,$d3,$9d,$60,$22,$ca,$d0,$f7,$a2,$0b,$86 .byte $72,$bd,$2f,$d4,$8d,$a5,$01,$85,$3d,$bd,$3b,$d4,$8d,$a6,$01,$85 .byte $3e,$bd,$47,$d4,$8d,$a7,$01,$85,$3f,$bd,$53,$d4,$85,$73,$60,$c6 .byte $71,$10,$15,$c6,$70,$10,$04,$a9,$1c,$85,$70,$a6,$70,$bd,$12,$d4 .byte $8d,$91,$01,$bd,$f5,$d3,$85,$71,$ee,$00,$22,$ad,$00,$22,$c9,$38 .byte $90,$05,$a9,$30,$8d,$00,$22,$ee,$02,$22,$ad,$02,$22,$c9,$38,$90 .byte $05,$a9,$30,$8d,$02,$22,$ee,$01,$22,$ad,$01,$22,$c9,$40,$90,$05 .byte $a9,$38,$8d,$01,$22,$ee,$03,$22,$ad,$03,$22,$c9,$40,$90,$05,$a9 .byte $38,$8d,$03,$22,$a2,$1f,$fe,$04,$22,$bd,$04,$22,$c9,$38,$90,$05 .byte $a9,$30,$9d,$04,$22,$ca,$10,$ee,$a5,$73,$30,$2b,$c6,$73,$10,$27 .byte $c6,$72,$10,$04,$a9,$0b,$85,$72,$a6,$72,$bd,$2f,$d4,$8d,$a5,$01 .byte $85,$3d,$bd,$3b,$d4,$8d,$a6,$01,$85,$3e,$bd,$47,$d4,$8d,$a7,$01 .byte $85,$3f,$bd,$53,$d4,$85,$73,$60,$ad,$82,$02,$29,$01,$49,$01,$85 .byte $58,$60,$a9,$40,$85,$3c,$a6,$4d,$ca,$60,$a0,$30,$a0,$00,$20,$45 .byte $62,$00,$00,$00,$00,$18,$1b,$1c,$1e,$22,$22,$1b,$24,$00,$00,$00 .byte $00,$00,$00,$1e,$22,$26,$1b,$24,$21,$1b,$1a,$1e,$17,$26,$1b,$00 .byte $00,$00,$00,$00,$00,$17,$0c,$28,$17,$22,$19,$1b,$1a,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$1b,$2a,$23,$1b,$24,$26,$00,$00,$00,$00 .byte $00,$0c,$22,$1b,$00,$23,$20,$17,$2b,$1b,$24,$00,$00,$00,$00,$00 .byte $00,$26,$29,$0c,$00,$23,$20,$17,$2b,$1b,$24,$00,$00,$00,$59,$5a .byte $5b,$5c,$5d,$5e,$41,$40,$40,$5f,$60,$61,$62,$63,$64,$65,$66,$43 .byte $40,$67,$68,$40,$69,$40,$6a,$6b,$6c,$6d,$6e,$6f,$70,$71,$72,$73 .byte $74,$40,$75,$76,$40,$77,$78,$79,$40,$7a,$7b,$40,$7c,$7d,$7e,$46 .byte $43,$40,$7f,$40,$80,$81,$82,$83,$43,$84,$85,$86,$87,$88,$89,$8a .byte $8b,$8c,$8d,$40,$42,$8e,$8f,$90,$91,$92,$40,$93,$43,$40,$44,$95 .byte $96,$46,$43,$97,$98,$99,$40,$9a,$9b,$9c,$9d,$46,$9e,$9f,$a0,$a1 .byte $a2,$40,$42,$45,$a3,$a4,$a5,$a6,$40,$a7,$45,$40,$44,$a8,$a9,$aa .byte $ab,$ac,$ad,$ae,$af,$b0,$40,$b1,$44,$b2,$40,$b3,$b4,$b5,$b6,$44 .byte $44,$40,$42,$45,$42,$46,$44,$b7,$40,$b8,$45,$40,$b9,$ba,$bb,$bc .byte $40,$bd,$be,$bf,$c0,$c1,$c2,$c3,$c4,$41,$40,$c5,$c6,$c7,$c8,$c9 .byte $40,$ca,$cb,$cc,$40,$42,$43,$40,$cd,$44,$ce,$40,$cf,$d0,$40,$d1 .byte $d2,$d3,$41,$40,$d4,$d5,$d6,$d7,$d8,$d9,$40,$da,$41,$40,$db,$44 .byte $44,$dc,$47,$48,$40,$40,$40,$40,$49,$4a,$4b,$41,$4c,$4d,$4e,$4f .byte $50,$51,$40,$40,$40,$41,$40,$40,$52,$53,$40,$40,$40,$54,$55,$41 .byte $40,$56,$57,$58,$40,$3c,$03,$03,$3c,$03,$03,$03,$03,$03,$3c,$03 .byte $03,$03,$03,$03,$03,$3c,$03,$03,$03,$3c,$03,$03,$03,$03,$03,$03 .byte $03,$03,$24,$15,$06,$f7,$d6,$c5,$b5,$a5,$95,$85,$76,$67,$58,$49 .byte $3a,$2b,$1d,$1c,$1b,$0c,$0d,$0c,$0b,$1a,$19,$28,$27,$26,$25,$33 .byte $33,$33,$33,$33,$33,$33,$32,$22,$11,$10,$00,$1f,$1e,$1d,$1c,$1b .byte $1a,$18,$16,$22,$11,$10,$00,$10,$10,$10,$10,$10,$10,$10,$10,$10 .byte $10,$10,$00,$ff,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$a9 .byte $ff,$85,$6b,$85,$6c,$a9,$00,$85,$19,$85,$1a,$60,$c5,$6b,$d0,$09 .byte $a9,$00,$85,$19,$a9,$ff,$85,$6b,$60,$38,$e5,$6c,$d0,$06,$85,$1a .byte $a9,$ff,$85,$6c,$60,$85,$6a,$a5,$95,$d0,$f9,$a5,$4b,$d0,$f5,$98 .byte $48,$8a,$48,$a0,$01,$a6,$6a,$b9,$6b,$00,$c9,$ff,$f0,$21,$88,$10 .byte $f6,$a5,$6c,$29,$7f,$a8,$bd,$30,$d6,$d9,$30,$d6,$a0,$01,$b0,$0f .byte $a5,$6b,$29,$7f,$a8,$bd,$30,$d6,$d9,$30,$d6,$90,$08,$a0,$00,$8a .byte $09,$80,$99,$6b,$00,$68,$aa,$68,$a8,$60,$a5,$4b,$d0,$fb,$a2,$01 .byte $b4,$6b,$c8,$d0,$03,$4c,$a4,$d5,$88,$10,$16,$98,$29,$7f,$95,$6b .byte $a8,$a9,$01,$9d,$00,$21,$a9,$ff,$9d,$02,$21,$9d,$04,$21,$9d,$06 .byte $21,$b9,$ab,$d5,$85,$5c,$b9,$0a,$d6,$85,$5d,$de,$00,$21,$d0,$d5 .byte $b9,$1d,$d6,$9d,$00,$21,$bc,$02,$21,$fe,$04,$21,$fe,$06,$21,$c8 .byte $b1,$5c,$c9,$ff,$d0,$08,$95,$6b,$a9,$00,$95,$19,$f0,$b7,$c9,$fe .byte $f0,$14,$c9,$fd,$d0,$1b,$c8,$b1,$5c,$95,$6b,$a8,$b9,$ab,$d5,$85 .byte $5c,$b9,$0a,$d6,$85,$5d,$a0,$00,$98,$9d,$04,$21,$9d,$06,$21,$b1 .byte $5c,$10,$0d,$c8,$b1,$5c,$9d,$00,$21,$88,$b1,$5c,$c8,$4c,$6a,$d5 .byte $0a,$10,$16,$4a,$29,$bf,$9d,$00,$21,$98,$9d,$02,$21,$de,$06,$21 .byte $de,$04,$21,$a9,$00,$95,$19,$f0,$3b,$4a,$95,$17,$98,$9d,$02,$21 .byte $b4,$6b,$b9,$be,$d5,$85,$5c,$b9,$f7,$d5,$85,$5d,$bc,$06,$21,$b1 .byte $5c,$10,$01,$88,$95,$19,$98,$9d,$06,$21,$b4,$6b,$b9,$d1,$d5,$85 .byte $5c,$b9,$e4,$d5,$85,$5d,$bc,$04,$21,$b1,$5c,$10,$01,$88,$95,$15 .byte $98,$9d,$04,$21,$ca,$30,$03,$4c,$d0,$d4,$60,$43,$8d,$be,$cd,$76 .byte $7c,$9d,$9f,$b5,$d8,$e9,$1a,$31,$47,$50,$65,$86,$9b,$b6,$5e,$a6 .byte $c6,$22,$d2,$8d,$d1,$d3,$c7,$e1,$02,$26,$42,$4c,$5b,$d1,$91,$d4 .byte $c1,$78,$cc,$ce,$cc,$cc,$cc,$cf,$cb,$cd,$ce,$cd,$cb,$d0,$cb,$cb .byte $cc,$cb,$cc,$cb,$d6,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8 .byte $d8,$d8,$d8,$d8,$d8,$d8,$d8,$d6,$d6,$d6,$d7,$d8,$d7,$d8,$d8,$d7 .byte $d7,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d6,$d6,$d6,$d6,$d7,$d7 .byte $d7,$d7,$d7,$d7,$d7,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$d8,$02,$01,$02 .byte $01,$01,$01,$01,$04,$02,$04,$07,$02,$04,$02,$0e,$01,$02,$01,$01 .byte $00,$09,$05,$09,$02,$04,$02,$08,$04,$05,$05,$00,$03,$04,$06,$03 .byte $07,$00,$02,$0b,$0b,$11,$11,$0f,$0f,$17,$17,$00,$00,$00,$00,$0b .byte $0b,$11,$11,$0b,$0b,$11,$11,$0f,$0f,$17,$17,$00,$00,$ff,$04,$00 .byte $03,$00,$02,$00,$01,$00,$00,$00,$00,$00,$04,$00,$03,$00,$04,$00 .byte $03,$00,$02,$00,$01,$00,$00,$00,$04,$04,$04,$04,$0d,$0d,$0d,$0d .byte $0d,$0d,$0d,$0d,$04,$04,$04,$04,$04,$04,$04,$04,$8d,$0c,$0e,$11 .byte $16,$0c,$0e,$11,$16,$0c,$0e,$11,$16,$0c,$0e,$11,$16,$0c,$0e,$11 .byte $16,$0c,$0e,$11,$16,$ff,$0b,$0b,$0b,$0b,$09,$09,$09,$09,$07,$07 .byte $07,$07,$06,$06,$06,$06,$04,$04,$04,$04,$02,$02,$02,$02,$18,$16 .byte $14,$11,$0f,$0d,$0b,$ff,$0b,$0a,$09,$09,$07,$06,$05,$0d,$0c,$0b .byte $0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09 .byte $08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07 .byte $0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c .byte $0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a .byte $09,$08,$07,$0d,$0c,$0b,$0a,$09,$08,$07,$0d,$0c,$0b,$0a,$09,$08 .byte $07,$ff,$0f,$0f,$0a,$09,$07,$06,$05,$0e,$0e,$0a,$09,$07,$06,$05 .byte $0c,$0c,$09,$08,$07,$06,$05,$0b,$0b,$09,$08,$07,$06,$05,$0a,$0a .byte $08,$07,$06,$05,$04,$09,$08,$07,$06,$05,$04,$03,$08,$06,$05,$04 .byte $03,$02,$02,$07,$06,$05,$04,$03,$02,$02,$06,$05,$04,$03,$03,$02 .byte $02,$05,$05,$04,$04,$03,$02,$02,$04,$04,$03,$03,$02,$02,$01,$03 .byte $03,$03,$02,$02,$02,$02,$0f,$10,$11,$12,$1f,$ff,$0f,$10,$11,$12 .byte $0f,$10,$11,$12,$0f,$10,$11,$12,$0f,$10,$11,$12,$ff,$08,$08,$08 .byte $08,$06,$06,$06,$06,$04,$04,$04,$04,$02,$02,$02,$02,$04,$ff,$0f .byte $14,$18,$1f,$0f,$14,$18,$1f,$0f,$14,$18,$1f,$0f,$14,$18,$1f,$18 .byte $1a,$1c,$1e,$1f,$ff,$08,$08,$08,$08,$08,$08,$08,$08,$07,$08,$09 .byte $0a,$0b,$0c,$0d,$0e,$0f,$ff,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$09 .byte $09,$09,$09,$08,$07,$06,$05,$04,$1f,$12,$00,$1e,$11,$00,$1d,$10 .byte $ff,$08,$08,$00,$08,$08,$00,$08,$08,$1f,$1f,$1e,$1e,$1d,$1c,$1b .byte $1a,$19,$18,$17,$16,$15,$14,$13,$12,$11,$10,$0f,$0e,$0d,$0c,$0b .byte $0a,$ff,$0a,$0a,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08 .byte $08,$08,$08,$08,$07,$06,$05,$04,$03,$02,$0d,$0b,$09,$00,$0d,$0b .byte $09,$00,$0d,$0b,$09,$ff,$06,$07,$08,$00,$06,$06,$06,$00,$04,$04 .byte $04,$1f,$1f,$1e,$1d,$1c,$1b,$1a,$19,$18,$17,$16,$15,$14,$13,$12 .byte $11,$ff,$0a,$0a,$07,$07,$88,$03,$03,$03,$03,$ff,$08,$07,$06,$05 .byte $04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$ff,$04,$05,$06,$07,$07 .byte $07,$05,$04,$03,$01,$14,$14,$14,$14,$16,$14,$17,$15,$16,$14,$17 .byte $15,$17,$14,$15,$14,$14,$16,$14,$15,$17,$14,$17,$15,$16,$14,$17 .byte $15,$17,$14,$15,$14,$fe,$0f,$11,$13,$15,$17,$19,$1b,$1d,$1e,$1f .byte $ff,$09,$09,$08,$07,$06,$05,$04,$03,$02,$01,$0f,$0e,$0d,$0c,$0b .byte $0a,$09,$08,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0e,$0d,$0c,$0b .byte $0a,$09,$08,$00,$00,$ff,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18 .byte $ff,$03,$03,$03,$06,$06,$06,$05,$05,$05,$02,$88,$84,$87,$8d,$86 .byte $83,$88,$84,$8a,$82,$20,$09,$d9,$a9,$00,$8d,$0e,$25,$20,$f7,$3f .byte $60,$20,$09,$d9,$20,$fa,$3f,$a9,$c8,$85,$34,$a9,$00,$85,$fd,$60 .byte $a5,$4c,$85,$62,$20,$09,$d9,$a5,$4a,$f0,$08,$ad,$ae,$27,$d0,$03 .byte $8d,$0e,$25,$20,$fd,$3f,$4c,$e7,$d8,$ad,$00,$39,$c9,$c6,$d0,$61 .byte $ad,$04,$39,$c9,$fe,$d0,$5a,$a2,$0f,$bd,$73,$d9,$9d,$ff,$24,$ca .byte $d0,$f7,$a2,$28,$bd,$97,$d9,$9d,$b3,$18,$ca,$d0,$f7,$a9,$01,$85 .byte $fd,$20,$dd,$d1,$a5,$62,$aa,$0a,$0a,$0d,$ae,$27,$8d,$02,$25,$bd .byte $11,$da,$8d,$06,$25,$bd,$15,$da,$8d,$07,$25,$ad,$ae,$27,$f0,$12 .byte $a9,$00,$8d,$af,$27,$a2,$03,$b5,$44,$9d,$af,$27,$ca,$d0,$f8,$4c .byte $6c,$d9,$a2,$03,$b5,$3f,$9d,$af,$27,$ca,$d0,$f8,$a2,$00,$a0,$25 .byte $60,$68,$68,$60,$8b,$23,$00,$00,$00,$00,$c0,$d9,$af,$27,$83,$d9 .byte $70,$d9,$04,$8f,$27,$cb,$08,$27,$cb,$07,$18,$b4,$07,$18,$bb,$07 .byte $18,$c2,$07,$18,$c9,$07,$18,$d0,$cd,$40,$c0,$f2,$3c,$00,$00,$db .byte $40,$c0,$ef,$30,$00,$00,$dd,$40,$c8,$f1,$30,$00,$00,$ec,$40,$c8 .byte $ef,$2c,$00,$00,$ec,$40,$c0,$ef,$2c,$ec,$80,$c0,$ff,$a0,$00,$00 .byte $1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$01,$04,$06,$08,$0d,$0d,$04 .byte $11,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$08,$0d,$13,$04,$11,$0c .byte $04,$03,$08,$00,$13,$04,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$00 .byte $03,$15,$00,$0d,$02,$04,$03,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d .byte $1d,$04,$17,$0f,$04,$11,$13,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1d .byte $1d,$c0,$d4,$e6,$f7,$d9,$d9,$d9,$d9,$00,$00,$00,$fa,$ff,$cf,$0d .byte $0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$00,$00 .byte $00,$1a,$10,$14,$00,$29,$32,$46,$09,$84,$1e,$bc,$00,$39,$0d,$33 .byte $15,$a9,$85,$0d,$1c,$44,$16,$e3,$e8,$fe,$58,$2a,$fa,$54,$50,$4c .byte $26,$22,$1e,$93,$ed,$48,$18,$19,$1c,$18,$19,$19,$19,$1c,$1c,$1c .byte $1d,$1d,$1e,$5e,$67,$82,$64,$68,$72,$7c,$8b,$95,$9f,$a5,$b2,$bf .byte $c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$c0,$a1,$55,$fb .byte $c1,$c6,$4e,$53,$d7,$dc,$ad,$a8,$07,$02,$61,$5c,$bb,$b6,$16,$11 .byte $70,$6b,$ca,$c5,$25,$20,$7f,$7a,$d9,$d4,$33,$2e,$8d,$88,$e7,$e2 .byte $42,$3d,$9c,$97,$f6,$f1,$51,$4c,$ab,$a6,$05,$00,$5f,$5a,$ba,$b5 .byte $cb,$d0,$b1,$ac,$a7,$a2,$0c,$07,$02,$fd,$66,$61,$5c,$57,$c0,$bb .byte $b6,$b1,$1b,$16,$11,$0c,$75,$70,$6b,$66,$cf,$ca,$c5,$c0,$1e,$1f .byte $1e,$1f,$1f,$18,$18,$1f,$1f,$18,$18,$19,$19,$19,$19,$19,$19,$1a .byte $1a,$1a,$1a,$1a,$1a,$1b,$1b,$1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c,$1c .byte $1c,$1d,$1d,$1d,$1d,$1d,$1d,$1e,$1e,$1e,$1e,$1f,$1f,$1f,$1f,$1f .byte $1f,$1f,$1f,$19,$19,$19,$19,$1a,$1a,$1a,$19,$1a,$1a,$1a,$1a,$1a .byte $1a,$1a,$1a,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$1b,$85 .byte $99,$ad,$44,$51,$04,$04,$04,$04,$00,$02,$00,$02,$00,$02,$00,$02 .byte $00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02 .byte $00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02 .byte $00,$02,$00,$02,$61,$68,$72,$7c,$81,$89,$93,$9d,$a3,$ab,$b5,$bf .byte $c3,$c9,$d3,$dd,$df,$e9,$f3,$fd,$02,$0c,$16,$20,$25,$2f,$39,$43 .byte $26,$26,$26,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22 .byte $22,$22,$22,$22,$22,$22,$22,$22,$22,$23,$23,$23,$23,$23,$23,$23 .byte $23,$90,$90,$90,$93,$90,$00,$08,$00,$08,$1e,$1e,$1e,$1e,$1e,$1e .byte $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e .byte $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e .byte $1e,$1e,$1e,$1e,$1e,$1e,$f9,$f6,$f6,$fb,$f8,$f6,$f6,$fa,$f8,$f6 .byte $f6,$fc,$fa,$f6,$f6,$fe,$f6,$f6,$f6,$fb,$f6,$f6,$f6,$fb,$f6,$f6 .byte $f6,$fb,$a0,$a0,$a0,$10,$50,$00,$80,$00,$80,$00,$9a,$00,$9a,$00 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00,$9a,$00 .byte $9a,$00,$9a,$00,$9a,$00,$9a,$17,$31,$57,$7d,$13,$31,$57,$7d,$13 .byte $31,$57,$7d,$1b,$31,$57,$7d,$0b,$31,$57,$7d,$0b,$31,$57,$7d,$0b .byte $31,$57,$7d,$0f,$27,$cb,$08,$27,$cb,$47,$18,$4e,$47,$18,$a8,$47 .byte $18,$a8,$47,$18,$a8,$47,$18,$fa,$47,$19,$4c,$47,$19,$a2,$47,$19 .byte $fd,$47,$1a,$57,$47,$1a,$b1,$47,$1b,$0c,$47,$1b,$66,$47,$1b,$c0 .byte $47,$1c,$1e,$47,$1d,$3d,$47,$1d,$93,$47,$1d,$ed,$47,$1e,$48,$47 .byte $1e,$a1,$47,$1e,$fb,$47,$1f,$55,$47,$1f,$b5,$47,$1f,$c1,$47,$1f .byte $d7,$0f,$27,$cb,$06,$27,$cb,$8f,$27,$cb,$17,$13,$6d,$71,$30,$34 .byte $8e,$82,$86,$8a,$43,$58,$54,$5c,$60,$50,$4c,$ae,$aa,$b6,$b2,$a6 .byte $a2,$c1,$c5,$d1,$c9,$cd,$d7,$db,$e7,$df,$e3,$1a,$1a,$1a,$1a,$1c .byte $1c,$1c,$1c,$1c,$1c,$1d,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f .byte $1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$a4,$fb,$aa,$ba .byte $97,$ba,$a0,$08,$11,$ba,$17,$00,$00,$8e,$ba,$20,$20,$8e,$8e,$a9 .byte $be,$3c,$3c,$8e,$8e,$c4,$c0,$c2,$8e,$8e,$de,$c0,$c2,$a8,$a0,$a8 .byte $a8,$a8,$a8,$a8,$c0,$c0,$a8,$c0,$c0,$c0,$a0,$a8,$c0,$c0,$af,$af .byte $a0,$a8,$c0,$c0,$af,$af,$a0,$a8,$a8,$af,$af,$a0,$a8,$a8,$1a,$1b .byte $14,$5c,$17,$5c,$1c,$17,$1a,$5c,$17,$18,$18,$05,$5c,$3e,$3e,$37 .byte $37,$05,$3f,$3e,$3e,$37,$37,$06,$3f,$3f,$37,$37,$03,$3f,$3f,$88 .byte $00,$2e,$38,$6d,$7a,$7c,$00,$8b,$05,$37,$fd,$82,$19,$3b,$f7,$a2 .byte $a0,$a0,$1b,$b0,$f7,$a2,$a0,$a0,$1b,$b0,$b0,$f9,$84,$15,$b0,$b0 .byte $bb,$ca,$7f,$f6,$ba,$eb,$19,$1a,$1b,$1d,$1f,$1f,$71,$85,$99,$ad .byte $59,$00,$26,$26,$26,$26,$26,$22,$90,$90,$90,$90,$68,$92,$2e,$2e .byte $2e,$2e,$20,$a8,$58,$b2,$0c,$66,$bb,$13,$6d,$ca,$2a,$7f,$de,$30 .byte $82,$ec,$43,$a1,$f6,$56,$b0,$0a,$4c,$a2,$c1,$d7,$18,$18,$19,$19 .byte $19,$1a,$1a,$1a,$1b,$1b,$1b,$1c,$1c,$1c,$1d,$1d,$1d,$1e,$1e,$1f .byte $1f,$1f,$1f,$1f,$b2,$c9,$cd,$df,$e3,$1f,$1f,$1f,$1f,$1f,$60,$8a .byte $34,$71,$1f,$1c,$1c,$1a,$b6,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba .byte $7c,$7c,$9c,$9c,$9c,$9c,$9c,$9c,$9c,$9c,$be,$de,$9e,$9e,$9e,$9e .byte $9e,$9e,$9e,$9e,$02,$03,$01,$02,$ff,$03,$03,$02,$03,$ff,$04,$04 .byte $04,$05,$ff,$05,$06,$06,$07,$00,$08,$08,$09,$0a,$01,$0a,$0b,$0c .byte $0b,$01,$0c,$0c,$0f,$0e,$01,$0c,$14,$1e,$26,$00,$80,$00,$5a,$dc .byte $00,$00,$01,$01,$01,$01,$04,$04,$04,$04,$02,$fc,$fc,$fc,$fc,$fd .byte $00,$00,$00,$00,$c0,$a0,$80,$40,$10,$04,$02,$01,$00,$00,$00,$00 .byte $7f,$05,$04,$03,$7f,$04,$03,$02,$7f,$03,$02,$01,$00,$00,$00,$40 .byte $00,$e0,$c0,$a0,$80,$00,$80,$40,$10,$03,$02,$01,$01,$00,$00,$00 .byte $02,$02,$01,$01,$20,$d0,$60,$e0,$80,$00,$80,$20,$a0,$30,$e0,$fd .byte $fd,$fe,$fe,$ff,$00,$00,$01,$01,$02,$02,$03,$04,$04,$ff,$02,$00 .byte $03,$ff,$01,$01,$02,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b3,$b5 .byte $b5,$b5,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$ba,$01,$ff .byte $01,$ff,$01,$ff,$01,$ff,$01,$ff,$01,$a7,$67,$5f,$37,$5e,$29,$9d .byte $5b,$be,$be,$be,$be,$be,$be,$be,$be,$be,$be,$c2,$c2,$c2,$bb,$bb .byte $bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$bb,$1a,$1a,$1a,$1a,$1a,$1a .byte $1a,$1a,$1a,$1a,$16,$16,$16,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f .byte $1f,$1f,$1f,$01,$02,$02,$9c,$9c,$9c,$1c,$1c,$1c,$71,$85,$99,$ad .byte $26,$26,$26,$26,$03,$08,$0c,$10,$3f,$0f,$0f,$03,$03,$00,$00,$00 .byte $00,$00,$00,$54,$54,$55,$55,$55,$55,$55,$55,$55,$95,$95,$95,$a5 .byte $a9,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$ff,$ff,$ff,$ff .byte $ff,$ff,$ff,$3f,$3f,$0f,$0f,$0f,$0f,$0f,$5f,$5f,$03,$43,$57,$55 .byte $5f,$5f,$5f,$5f,$5f,$5f,$5f,$5f,$95,$95,$5f,$95,$55,$a5,$5f,$a5 .byte $a5,$aa,$af,$aa,$aa,$aa,$af,$aa,$aa,$aa,$af,$aa,$aa,$aa,$af,$aa .byte $47,$43,$43,$28,$43,$29,$31,$39,$38,$34 ORG $FF7A START JMP GameColdInit .byte $3F .byte $39 .byte $34 CART_SIGNATURE: ; FF80-FFF7 .byte $04,$C4,$76,$30,$6A,$8C,$8A,$3A,$CA,$F5,$BC,$71,$CA,$76,$08,$AB .byte $75,$58,$CD,$19,$2A,$29,$2E,$F0,$DB,$7B,$84,$98,$A4,$0E,$0A,$7C .byte $3F,$D8,$93,$8D,$59,$98,$FA,$77,$03,$FF,$E9,$9B,$70,$A8,$B3,$A5 .byte $AA,$E7,$7F,$82,$CF,$DD,$5F,$F4,$54,$79,$BA,$D7,$6D,$73,$26,$CE .byte $B3,$06,$39,$94,$BA,$74,$A1,$E7,$8F,$AF,$6C,$B2,$E2,$74,$70,$0B .byte $2E,$68,$F2,$4F,$27,$E2,$AA,$4D,$F7,$B0,$CD,$C6,$9D,$B1,$42,$59 .byte $CE,$0D,$59,$14,$13,$8E,$71,$5C,$A0,$09,$4E,$00,$85,$99,$E7,$CA .byte $E4,$A5,$D9,$A1,$2B,$47,$A4,$CE .byte $FF ; region verification. $FF=all regions .byte $E7 ; encryption check starts at $E000 .word NMI_ROUTINE .word START .word IRQ_ROUTINE