1562 Commits

Author SHA1 Message Date
scawful
7453dbdfdd add minecart track starting positions and update ranch girl sprite inclusion 2025-12-09 08:02:38 -05:00
scawful
57012b2656 Ice block push direction validation and documentation
Add side validation to prevent players from manipulating the ice block
by changing direction while in contact. Uses Sprite_DirectionToFacePlayer
to verify Link's position matches his facing direction before allowing push.

Key changes:
- IceBlock_ValidatePushSide: Anti-cheat that validates Link is on the
  correct side of the block for his facing direction
- Direction locking: Push direction locked in SprMiscA until block stops
- Comprehensive documentation of mechanics and sprite RAM usage
- Section headers for code organization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 08:00:33 -05:00
scawful
f508f9a19d menu scroll fixes 2025-12-08 22:31:08 -05:00
scawful
740571ca7f upgrade submenus with hints, indicators, journal with X and rings with Y in menu 2025-12-08 22:12:05 -05:00
scawful
9b4ee7a9a1 add journal flags to deku scrub, mask salesman, ranch girl 2025-12-08 22:08:18 -05:00
scawful
2d62553065 add docs for asm style guide and oracle system architecture 2025-12-08 22:07:30 -05:00
scawful
6c6e6a0bc6 Add menu journal with main quest and side quest hints and progression tracking 2025-12-08 21:46:33 -05:00
scawful
851da89644 Fix: Zora Sanctuary Waterfall trigger and Lost Woods transition logic 2025-12-08 16:42:19 -05:00
scawful
9a8c6d919a Fix lost woods for ZSCustomOverworld v3 2025-12-08 14:32:20 -05:00
scawful
1aa5878ab1 Fix: Resolve BG color brightness regression, persist Time System tint, and refactor Minecart data 2025-12-08 14:04:12 -05:00
scawful
1c19788ba9 Fix HUD artifact: Revert FloorIndicator overflow from Song of Storms commit
The changes in commit 841ef2d added ~15 bytes to FloorIndicator, exceeding
its 156-byte size limit ($0AFD0C-$0AFDA7) and causing ROM corruption that
manifested as a brown/black tile artifact below the HUD item box.

Reverted changes:
- BNE+JMP pattern back to BEQ (saves 3 bytes)
- Removed Song of Storms rain check from FloorIndicator (saves 12 bytes)

Song of Storms functionality in ZSCustomOverworld.asm remains intact.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 13:53:15 -05:00
scawful
d01a4b83a0 Fix ActivateSubScreen: prevent .turnOn from falling through to clear
The .turnOn path was setting $1D=1 then falling through to .normal
which cleared $1D - immediately undoing the overlay enable.

Fix: Add BRA .exit after setting $1D in .turnOn path.
Also remove the unnecessary module $0E check - the real bug was
the fall-through, not menu state interference.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:48:19 -05:00
scawful
791ebaf552 Fix menu navigation: restore original up/down behavior
- Keep loop counters in FindNextItem/FindPrevItem (prevents infinite recursion)
- Restore FindNextDownItem/FindNextUpItem to original logic:
  - Move ONE row, then delegate to FindNextItem if slot empty
- Fix boundary check in FindNextUpItem: use BEQ/BPL for signed comparison
  (CMP #$01 : BCS was wrong - unsigned comparison treats $FE as 254 >= 1)

The original design: Up/Down navigate rows, delegate to horizontal scan
if target slot is empty. The loop counters in horizontal navigation
prevent infinite loops when all items are empty.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:39:21 -05:00
scawful
841ef2d017 Fix Song of Storms: Rain persists across transitions, dismissal works from any area
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:07:32 -05:00
scawful
d41dcdadb9 Fix ZSOW vs Day/Night Sprites: Use Oracle_CheckIfNight and move ZSOW include to end 2025-11-22 19:39:18 -05:00
scawful
a8ff3ef0f9 Update tracker: Mark Time System refactor DONE and ZSOW bug ACTIVE 2025-11-22 19:25:37 -05:00
scawful
ad2c00c359 Fix regression in ColorSubEffect: Use 16-bit immediate loading for color constants 2025-11-22 19:22:59 -05:00
scawful
93bd42be8b Refactor Time System: Introduce TimeState struct and modularize RunClock 2025-11-22 19:10:15 -05:00
scawful
52a5ed4b02 Refactor menu system: Add constants and deduplicate input logic 2025-11-22 19:03:56 -05:00
scawful
3ceab24c7c Fix Menu System issues: Journal tilemap, Ocarina selector, and input regression
- Fixed: Journal tilemap not updating by ensuring 5 (Palette/Refresh) flag is set in Menu_Journal and other submenus.
- Fixed: Ocarina menu not clearing main menu selector by realigning Menu_ItemCursorPositions to match Menu_AddressIndex, resolving a data mismatch.
- Fixed: Input entirely breaking in the menu (regression from previous commit) by reverting bash116 update flag from 3 back to 2, which seems to prevent VBlank timing issues.
- Updated Docs/GEMINI.md with recent debugging insights covering processor status mismatch, input polling, VRAM update flags, data table mismatches, and custom NMI handlers.
2025-11-22 17:50:29 -05:00
scawful
2b504d987f Fix Time System BG color tinting and overlay clearing bugs
- Fixed: BG color resetting to untinted value on screen transitions (InitColorLoad2).
- Fixed: Addressing mode error in ColorSubEffect causing incorrect tinting.
- Fixed: Active overlays being cleared when hour advances due to static table lookup and incomplete logic in Overworld_LoadBGColorAndSubscreenOverlay.
- Updated handoff documentation with resolution details.
2025-11-22 16:41:58 -05:00
scawful
8b23049e28 Fix menu system crashes and stability issues
- Fix IrisSpotlight crash ($00F361): Removed errant $0116/$17 writes
  from menu_select_item.asm that corrupted VRAM upload index
- Fix journal stack corruption: Added missing PHB in Journal_CountUnlocked
- Fix P register mismatches: Added SEP #$30 to Menu_RefreshQuestScreen,
  Menu_ScrollFrom, Menu_DrawRingPrompt
- Fix MagicBag crashes: Fixed data bank corruption in error path,
  fixed uninitialized Y register in cursor movement
- Relocate StoryState from volatile $7C to SRAM $7EF39E
- Add bounds checking to HouseTag_Main jump table
- Use long addressing (.l) for SRAM access in custom_tag.asm

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 03:20:35 -05:00
scawful
e485439628 Overhaul menu: Add RHS selector, expand journal, document states 2025-11-21 19:02:36 -05:00
scawful
5cd1248c30 feat: Implement consumable item effects (Pineapple, Honeycomb) and consumption logic with error handling 2025-11-21 17:49:28 -05:00
scawful
117dd70d2c Add implementation plan for Castle Ambush & Guard Capture System, including probe detection and capture mechanics 2025-10-03 16:49:36 -04:00
scawful
5aba4e7311 Update GEMINI.md to enhance documentation structure and clarity, adding comprehensive references for core systems, development guidelines, and sprite documentation. 2025-10-03 16:15:57 -04:00
scawful
ff54149660 Update SpriteCreationGuide 2025-10-03 16:07:58 -04:00
scawful
84fa424871 Refactor Overlords documentation for improved clarity and formatting
- Updated the table formatting for better readability in the Overlords.md file.
- Ensured consistent alignment of columns in the jump table and WRAM description sections.
- Enhanced descriptions for clarity regarding overlord types and their respective data storage.
2025-10-03 16:07:42 -04:00
scawful
26d35364af Add advanced technical documentation for ZScream custom overworld
- Introduced comprehensive documentation covering internal hook architecture, memory management, graphics loading pipeline, sprite loading system, cross-namespace integration, performance considerations, and debugging strategies.
- Detailed sections on adding custom features and modifying existing behaviors, including examples and code snippets.
- Included a complete hook list and memory map quick reference for developers.
2025-10-03 15:50:34 -04:00
scawful
4289e134aa Refactor logging statements to use %log_end macro for consistency across item and menu scripts 2025-10-03 14:36:19 -04:00
scawful
f2b92e816b Refactor sprite logging macros and enhance debug output for better traceability 2025-10-03 13:49:45 -04:00
scawful
07e5717ea2 Enhance sprite creation guide with multi-layered drawing techniques and quest integration details 2025-10-03 01:52:57 -04:00
scawful
aede7551a3 Add new sprite documentation for Minecart, Pedestal, Portal, and Switch Track
- Created detailed documentation for the Minecart sprite, outlining its properties, constants, collision setup, main logic, and design patterns.
- Added documentation for the Pedestal sprite, including its vanilla overrides, custom logic for item interaction, and event triggering based on area context.
- Introduced documentation for the Portal sprite, detailing its two-way warping system, initialization, main logic, and helper routines for seamless transitions.
- Documented the Switch Track sprite, explaining its interactive behavior, state-based animation, and integration with external switches for dynamic track manipulation.
2025-10-03 01:52:48 -04:00
scawful
8c3bf9d95b Add documentation for custom enemy sprites: Eon Scrub, Keese, Leever, and Octorok
- Created detailed markdown files for Eon Scrub, Keese, Leever, and Octorok sprites.
- Included sprite properties, main logic, drawing routines, and design patterns for each sprite.
- Highlighted unique behaviors, state machines, and interactions with the player for each enemy type.
- Ensured clarity in the implementation details and provided assembly code snippets for reference.
2025-10-03 00:31:19 -04:00
scawful
1cc7d84782 Add detailed sprite analysis for Puffstool, Sea Urchin, Thunder Ghost and more
- Introduced comprehensive documentation for the Puffstool sprite, covering properties, core routines, and key behaviors.
- Added analysis for the Sea Urchin sprite, detailing its initialization, state management, and drawing routines.
- Included a thorough examination of the Thunder Ghost sprite, highlighting its dynamic health, lightning attack mechanics, and movement patterns.
2025-10-02 23:55:31 -04:00
scawful
6780dd0d45 Add sprite analysis documentation for various bosses and mini-bosses
- Created detailed documentation for the Kydrog Boss sprite, outlining its phases, behaviors, and mechanics.
- Added analysis for the Manhandla sprite, including its transformation into Big Chuchu and phase management.
- Documented the Octoboss sprite, highlighting its unique mechanics and interactions with a "brother" Octoboss.
- Provided an overview of the Twinrova boss sprite, detailing its transformation and phase-based attacks.
- Included analysis for the Vampire Bat mini-boss, emphasizing its enhanced behavior compared to standard Keese.
- Documented the Wolfos mini-boss, focusing on its integration into a mask quest and unique pacification mechanics.
2025-10-02 21:24:44 -04:00
scawful
0f1e0a8c75 Document unresolved conflicts in sprite loading integration and outline future work for dynamic sprite sets in ZSCustomOverworld. 2025-10-02 14:24:43 -04:00
scawful
55ab99d6f9 Simplify GEMINI search heuristics 2025-10-02 13:16:21 -04:00
scawful
6ba634caa4 Add comprehensive documentation for sprites and systems
- Introduced detailed analysis for the Minecart system, highlighting its state machine, track system, and areas for improvement.
- Created an NPCs analysis document, summarizing various NPC sprites and their functionalities.
- Added an Objects analysis document, covering interactive elements like collectibles, ice blocks, and minecarts.
- Documented the Overlord sprite system, detailing its role in spawning other sprites and managing events.
- Compiled a Dungeons & Indoor Areas document, outlining custom room tags, enhanced mechanics, and advanced collision systems.
- Developed an Overworld Systems Analysis, focusing on the ZSCustomOverworld architecture and its core features.
- Added a Time System document, explaining the in-game clock and day/night cycle management.
- Documented the ZScream Custom Overworld, detailing its data-driven approach and key features.
2025-10-02 12:44:30 -04:00
scawful
27ffaf16d8 Refactor project structure and enhance documentation for "Oracle of Secrets" development. Introduced new epics for core infrastructure, system integration, dungeon polish, quest implementation, and boss enhancements. Improved technical debt tracking with actionable tasks, including restructuring code for better maintainability and readability. Updated known bugs and conflicts, and outlined new features and content for dungeons and quests. Enhanced overall organization and clarity of project documentation. 2025-10-02 12:20:15 -04:00
scawful
90a4a44e72 Add documentation on bosses, npcs, objects, overlords, and the overworld 2025-10-01 23:42:09 -04:00
scawful
15784d397e Update documentation: restructure and expand guides for Dungeons, Items, Masks, Menu, and Music systems 2025-10-01 23:21:57 -04:00
scawful
eeeb9ffeb4 Add detailed documentation for memory mapping, quest flow, and sprite creation
- Created MemoryMap.md to outline WRAM and SRAM structures, including key variables and custom regions.
- Added QuestFlow.md to document main quest progression and major side-quests, detailing triggers, events, rewards, and flags.
- Introduced SpriteCreationGuide.md to provide a comprehensive guide for creating custom sprites, including file setup, properties, main structure, initialization, logic, and drawing routines.
- Updated oracle.org to include new documentation links and improve project organization with infrastructure suggestions.
2025-10-01 22:40:58 -04:00
scawful
8d4d2b8f41 Temporarily comment out sections for porting to ZSOWv3 in ocarina.asm, ZSCustomOverworld.asm, and time_system.asm 2025-10-01 13:29:54 -04:00
scawful
ed1a30adce Add SNES hardware registers and patches documentation 2025-10-01 12:41:57 -04:00
scawful
3066aae151 Add debug printing macros and replace print statements with %print_debug in multiple files 2025-10-01 12:39:51 -04:00
scawful
4137d5bf7c Remove CameraCache definition from overlays.asm 2025-09-20 17:29:49 -04:00
scawful
3c36567947 Fix LostWoods hook bug, inject into ZSCustomOverworld 2025-09-14 13:45:04 -04:00
scawful
c5474fae5d Fix special area time based custom bg color by removing unnecessary buffer operations 2025-09-14 13:43:49 -04:00
scawful
0a68bb4f3d Fix RomToPaletteBuffer in Day/Night system for ZSCustomOverworld 2025-09-14 12:26:16 -04:00
scawful
6f6e17df85 Add lost woods hook to ZSCustomOverworld 2025-09-14 12:23:46 -04:00
scawful
c177991040 Remove manual overrides to special overworld area and spawn points 2025-09-14 12:21:30 -04:00
scawful
6f088cb976 Add SetImpervious macro and update symbols for camera cache and sprite properties 2025-09-14 12:13:27 -04:00
scawful
3834e4df0f Upgrade to ZSOverworld ASM ver3
- Adds tall and wide areas
- Adds support for special overworld maps
2025-09-14 11:00:37 -04:00
scawful
3492713a68 Wolfos: refactor animation handling and streamline movement logic 2025-08-03 17:57:38 -04:00
scawful
22a847bae9 Wolfos: add macros, refactor movement 2025-07-22 08:58:34 -04:00
scawful
2c682aec88 SwitchTrack: Remove call to main during prep 2025-06-24 18:17:42 -04:00
scawful
cbe2f2b8c9 update comments 2025-06-24 18:15:40 -04:00
scawful
8e619ee5e6 Add Menu_Journal to Menu module 2025-06-24 18:15:05 -04:00
scawful
e00ff48be3 Add menu journal code skeleton and tilemaps 2025-06-24 18:14:52 -04:00
scawful
b286103f75 Add Menu_CheckForSpecialMenus fn for Menu_ItemScreen 2025-06-24 18:14:11 -04:00
scawful
c25f4027eb Remove outdated Guia del Probador Beta documentation file 2025-04-12 12:57:48 -04:00
scawful
905ee8582c Refactor Overworld ASM files: replace ZSCustomOverworld_Latest with ZSCustomOverworld, delete obsolete ZCustomOverworld and ZCustomOverworld2 files. 2025-04-12 12:57:21 -04:00
scawful
2892b9c5f0 Move morningstar gfx bin 2025-03-25 20:29:19 -04:00
scawful
e28cdd0f04 Complete Minecart mechanics implementation; mark all tasks as done 2025-03-24 21:03:33 -04:00
scawful
9eace5a53a Remove commented-out code in book_of_secrets and portal_rod for cleaner readability 2025-03-24 21:02:45 -04:00
scawful
62b4ad4e99 Update minecart and pedestal sprite positions; clean up switch track code 2025-03-24 21:02:28 -04:00
scawful
706dcc0710 Refactor Lanmola sprite functions for improved readability and maintainability 2025-03-20 18:41:48 -04:00
scawful
56c098a884 Cleanup switch track 2025-02-16 10:53:07 -05:00
scawful
ee09b6dacc Add comment for checking MinecartTrack positions with breakpoint 2025-02-16 10:41:21 -05:00
scawful
8e6d63c6f8 Remove unused CheckForTrackTiles and update comments in minecart 2025-02-13 09:30:43 -05:00
scawful
5a192edf13 Move UpdateCachedCoords, RoundCoords to sprite_functions 2025-02-13 09:18:40 -05:00
Justin Scofield
875a9b5e89 Merge pull request #105 from scawful/NewMinecart
Add updated minecart collision, switch track, multi cart, T junction tracks
2025-02-12 18:18:24 -05:00
Jared_Brian_
dcc7e6fe08 Merge branch 'master' into NewMinecart 2025-02-11 18:37:42 -07:00
Jared_Brian_
3b12b9f596 added collision legend 2025-02-08 12:08:15 -07:00
Jared_Brian_
7f3fbad7ae Changed the switch tracks to allow for more than just one switch 2025-02-08 11:55:46 -07:00
Jared_Brian_
717d9fb108 Fixed the switch track logic 2025-02-03 23:14:46 -07:00
Jared_Brian_
e112bed264 Made it so the minecart sprite to follower to sprite hand off is much smoother by telling the old sprite cart not to draw after the follower spawns, adjusting the positioning of the follower draw itself, and also made it so it won't always be vertical
Fixed the bug that made it so the minecart would auto grab you sometimes after getting off
and then there was another bug that had accidently been introduced that made carts on track 00 not work
2025-02-01 19:08:57 -07:00
Jared_Brian_
ed439e28ed Added the default directions for junction interaction.
Made the corner change direction animation more snappy.
Made the initial animation frame for vertical carts actually be vertical.
2025-01-27 21:47:19 -07:00
scawful
a1c9c8c8d5 generic housekeeping shit 2025-01-26 22:14:19 -05:00
scawful
490ecef311 Sprite functions housekeeping 2025-01-26 22:13:05 -05:00
scawful
d60b3683a0 Fix dialogue pointer bug 2025-01-26 21:14:59 -05:00
scawful
5851f3c9c5 disable offscreen deactivation code for poltergeist 2025-01-25 11:35:06 -05:00
scawful
154b6bc9be Fix bug with poltergeist axe, fork, knife not being deflectable 2025-01-25 11:34:52 -05:00
scawful
a780f67d90 fix usage of GetDistance8bit in various sprites 2025-01-25 11:26:44 -05:00
scawful
af0d0e5b5e Adjust sensitivity of ice block push 2025-01-25 11:23:56 -05:00
Jared_Brian_
e203e57183 Added the T junction logic 2025-01-22 23:32:23 -07:00
Jared_Brian_
46e557e82e Added the multi cart per room setup 2025-01-21 22:44:26 -07:00
scawful
2303a450dc update time system defines 2025-01-19 22:13:13 -05:00
scawful
7adb541a6a move link ram and fns to link.asm 2025-01-19 17:42:30 -05:00
scawful
316d5f302b add ForcePrizeDrop_long symbol 2025-01-19 15:02:45 -05:00
scawful
b3a71f740f PolsVoice force prize drop when any song is played 2025-01-19 15:02:31 -05:00
scawful
739c2f994e force prize drop for puffstool spores 2025-01-19 15:00:57 -05:00
scawful
8587046d82 sea urchin force prize drop 2025-01-19 15:00:05 -05:00
scawful
5ddb771382 force prize drop from keese 2025-01-19 14:58:53 -05:00
scawful
d8954a0f26 make twinrova ice attack less frequent 2025-01-19 14:58:44 -05:00
scawful
c484f982ef Update piratian aggro behavior, show message on contact 2025-01-19 14:43:05 -05:00
scawful
a025d63441 add friendly piratian hint dialogue 2025-01-19 14:33:27 -05:00
scawful
85cdc25f4f housekeeping 2025-01-19 14:29:47 -05:00
scawful
3f436cca7f Update Song of Storms functionality and implement Magic Pedestal sprite 2025-01-19 14:29:25 -05:00
scawful
c8d17dd941 Refactor color handling in menu and update palette definitions 2025-01-19 14:11:04 -05:00
scawful
63b90e7fc3 indent messages data 2025-01-19 14:05:38 -05:00
scawful
ec2fca99ab Add LinkItem_BookOfSecrets, cleanup overlays code 2025-01-19 14:02:17 -05:00
scawful
8bd186356a Refactor SongFlag handling to use byte operations 2025-01-19 14:01:25 -05:00
scawful
a7b3278927 Add ApplyGraphicsSheet(sheet,dest) macro 2025-01-19 13:51:12 -05:00
scawful
6aaafb87ce Add ProbCheck2 macro 2025-01-19 13:49:52 -05:00
scawful
4ae52f3584 update twinrova keese probability, kill offspring when dead 2025-01-19 13:46:46 -05:00
scawful
cca13cba32 Add fire and ice attack to keese on timer 2025-01-19 13:46:25 -05:00
scawful
a0f1ae77a5 object housekeeping 2025-01-19 13:39:15 -05:00
scawful
236e888bdb npc housekeeping 2025-01-19 13:30:19 -05:00
scawful
a9d42e398f boss housekeeping 2025-01-19 13:27:38 -05:00
scawful
f8a264d1df Add Sprite_CountActiveById, limit keese in twinrova fight 2025-01-19 13:16:52 -05:00
scawful
c7db1c1776 wolfos immune to arrows, fix song flag check 2025-01-19 13:09:37 -05:00
scawful
a00c78d9f0 Add SongFlag symbol 2025-01-19 13:04:50 -05:00
scawful
07317bf238 darknut chases link when attacked 2025-01-19 12:59:14 -05:00
scawful
d95162d8ef lower helmet chuchu health, housekeeping 2025-01-19 12:59:02 -05:00
scawful
206993e3d5 Add Piratian friendly and aggro behavior 2025-01-19 12:34:53 -05:00
scawful
aef81e8032 Add keese to twinrova gfx, spawn ice/fire keese randomly 2025-01-19 12:20:58 -05:00
scawful
f37e570e77 add Twinrova_RestoreFloorTile for removing ice tiles 2025-01-19 12:20:31 -05:00
scawful
36bf7e83a8 Update SRAM item names 2025-01-19 12:17:56 -05:00
scawful
deae33c596 agregue messages_es.org para la traducción al español 2025-01-19 12:02:32 -05:00
scawful
3a4126d487 Add prize pack rarities and item drop bounce properties 2025-01-19 12:00:23 -05:00
scawful
738c949f54 update custom keese draw for twinrova room 2025-01-19 11:55:17 -05:00
scawful
dceb823ee4 add probability check macro 2025-01-19 11:54:52 -05:00
scawful
5302b03d31 Add sram.asm, separate from symbols.asm 2025-01-19 11:54:38 -05:00
scawful
93a0c7fd8e Add Sprite_SpawnIceKeese 2025-01-19 11:35:04 -05:00
scawful
202b042b6b Add PlayerTransform, CheckNewRButtonPress fns 2025-01-19 11:33:56 -05:00
scawful
c8f6d0e989 Add all_music.asm, cleanup Oracle_main.asm 2025-01-18 12:47:52 -05:00
scawful
e98b0a02ad Add Link_ConsumeMagicBagItem, implement Link_Banana 2025-01-18 11:00:51 -05:00
scawful
64adca2012 Cleanup portal rod code 2025-01-18 11:00:34 -05:00
scawful
90225c3b4a Sprite housekeeping 2025-01-18 10:59:45 -05:00
scawful
a6eac7dc4f Fix sword barrier sprite prep 2025-01-18 10:59:08 -05:00
scawful
b8fa53ec92 Refactor time system to use named variables for hours and minutes; add night check functions and update palette handling 2025-01-17 23:19:28 -05:00
scawful
913f9ea3d0 add sfx.asm 2025-01-17 22:42:29 -05:00
Jared_Brian_
002b8b7f33 woopse 2025-01-16 22:10:30 -07:00
Jared_Brian_
492d65c135 added my testing stuff to git ignore and initial upload 2025-01-16 22:10:19 -07:00
scawful
252293cc73 Add distance check to kaepora gaebora sprite 2025-01-13 08:56:53 -05:00
scawful
09a7271ace Fix bug with magic bean quest when leaving map and returning 2025-01-13 08:49:13 -05:00
scawful
d73e49c9bc Fix mask salesman song of healing dialogue ID 2025-01-12 19:04:01 -05:00
scawful
ac855f7eeb Change HeadPos macros into functions 2025-01-12 15:25:20 -05:00
scawful
2f3faba1a6 Fix KaeporaGaebora sprite interaction 2025-01-12 15:25:02 -05:00
scawful
f9f4436df2 Housekeeping 2025-01-11 21:10:30 -05:00
scawful
dea2ff1561 Maple grants portal rod when speaking beta 2025-01-11 21:09:56 -05:00
scawful
01289b10e9 NPC cleanup, add deku scrub dialogue ID and map marker 2025-01-11 21:09:43 -05:00
scawful
03478c4f04 Add deku butler and deku princess peacetime dialogue 2025-01-11 21:09:10 -05:00
scawful
ee18cda610 Fix bug with eon abyss link sprite palette 2025-01-11 09:40:59 -05:00
scawful
b09aebc5de update crystals and gamestate symbols 2025-01-11 08:56:56 -05:00
scawful
e9ff95faf3 Update bean vendor prep so village elder loads indoors 2025-01-10 21:19:54 -05:00
scawful
80fd69d8bb Enemy housekeeping 2025-01-10 20:42:42 -05:00
scawful
59a063e5f4 Update world map conditions 2025-01-10 20:42:25 -05:00
scawful
de478a5e71 Store palette color before applying daynight pal in ZSCustomOverworld 2025-01-10 19:41:21 -05:00
scawful
1fa904a109 Change ZSCustomOverworld default overlay to rain for song of storms 2025-01-10 19:40:46 -05:00
scawful
cd961b6953 Update progress flags and world map icon conditions 2025-01-10 19:40:17 -05:00
scawful
9060ecd855 Fix sprite macro 2025-01-10 19:39:35 -05:00
scawful
740a94d3bc Update boss sprites and macros 2025-01-09 02:46:06 -05:00
scawful
87685843e7 Add deku mask spoiler to guide 2025-01-09 02:45:41 -05:00
scawful
b90f7ffcea Menu cleanup 2025-01-09 02:36:31 -05:00
scawful
21514f841e Overworld cleanup 2025-01-09 02:36:14 -05:00
scawful
bc591c4e7a Item and mask cleanup 2025-01-09 02:35:38 -05:00
scawful
006690858c Update spoiler tag on spanish beta tester guide 2025-01-09 02:35:04 -05:00
scawful
c661665d90 Add spanish beta tester guide 2025-01-09 02:32:22 -05:00
scawful
8eff895633 Portal Sprite cleanup 2025-01-06 17:54:23 -05:00
scawful
02df9c4856 Boss housekeeping 2025-01-06 17:52:35 -05:00
scawful
5177cdfd63 Update sprite functions, remove Sprite_BounceOffWall 2025-01-06 17:51:54 -05:00
scawful
1b9ce3e0fb Add todo notes for Shrine of Wisdom and Glacia Estate 2025-01-06 17:50:17 -05:00
scawful
de033261ec Add goldstar sram check to L/R button switch 2024-12-24 18:02:38 -06:00
scawful
3711641e5d Add structs.asm with Sprite struct 2024-12-22 20:43:30 -05:00
scawful
1406cca079 Add macros for status flag and indexed STA 2024-12-22 20:43:03 -05:00
scawful
449dbd149e Add HyruleDream sprites as subtype for 0x76 Farore 2024-12-22 20:41:40 -05:00
scawful
57648349fa Add overlord.asm with experimental castle soldier spawn path fn 2024-12-22 17:23:17 -05:00
scawful
d816858c8e Update Maple dream logic 2024-12-22 17:22:59 -05:00
scawful
ff391f4913 Update SRAM for Dreams, add brackets to separate sections 2024-12-22 17:22:39 -05:00
scawful
ec13abe166 Update Maple dialogue 2024-12-22 17:22:08 -05:00
scawful
89f8ee4ea8 Remove Maku Tree dream logic, add Maple dream hut logic 2024-12-22 12:28:22 -05:00
scawful
b2ffbc0b9c Remove all_dreams.asm and Events directory 2024-12-22 12:27:54 -05:00
scawful
9267ea459c Add Maple Dream Hut dialogue 2024-12-22 11:35:06 -05:00
scawful
ae22150baf Fix vampire bat miniboss draw code 2024-12-22 10:49:38 -05:00
scawful
221e3db4f4 Fix bug with magic bean quest bee check 2024-12-22 10:36:56 -05:00
scawful
3fa0b9346e Fix magic bean quest time elapsed for real this time 2024-12-22 10:27:00 -05:00
scawful
1dbaf028ca Add maple.asm 2024-12-21 16:54:37 -05:00
scawful
a0d465b05e Add milestone jingle to song of storms in magic bean quest 2024-12-21 16:46:29 -05:00
scawful
5c9a19c78e Add milestone jingle to magic bean quest 2024-12-21 16:45:57 -05:00
scawful
f0920bb35a Fix bug with magic bean prog time check 2024-12-21 16:45:04 -05:00
scawful
b9fc66d047 Add portal rod get to maple beta 2024-12-21 11:56:41 -05:00
scawful
57c4ea2142 Add goron mines puzzle ideas 2024-12-21 11:56:22 -05:00
scawful
16ee2ad31b Fix magic bean collision detection bug 2024-12-21 11:56:06 -05:00
scawful
495ac1e886 Lower VampireBat health for mushroom grotto 2024-12-20 18:29:49 -05:00
scawful
376c7ad1f7 Lower song of healing volume 2024-12-20 18:29:32 -05:00
scawful
f034a5c108 Restore Minecart sprite behavior 2024-12-20 17:22:37 -05:00
scawful
583d7416c5 Disable unused experimental minecart room tag 2024-12-20 17:21:33 -05:00
scawful
ac34c96f4f Reduce PolsVoice OAM allocation 2024-12-20 17:21:17 -05:00
scawful
eb9c64ff7e Add custom fire/ice keese and vampire bat mini boss sprite 2024-12-20 17:20:58 -05:00
scawful
e15c97bc3c Move Sprite_Twinrova FireAttack and IceAttack to common functions 2024-12-20 17:20:21 -05:00
scawful
2a5447db1e Add new Maple intro dialogue 2024-12-20 15:52:43 -05:00
scawful
525ff47aff Update Maple intro dialogue ID 2024-12-20 15:52:30 -05:00
scawful
826ee6bea6 Minish Link doesnt affect cracked floors 2024-12-20 15:52:14 -05:00
scawful
0b6de8edc4 Cleanup dungeon code 2024-12-20 11:01:11 -05:00
scawful
a304b96bc0 Add BottleVendor sells milk, remove behavior from Maple witch 2024-12-20 11:00:31 -05:00
scawful
704dd78901 Fix dungeon tingle maps save ram check 2024-12-19 13:54:47 -05:00
scawful
a901945316 cleanup 2024-12-19 13:53:59 -05:00
scawful
4927fa284b Add PolsVoice_CheckForFluteSong 2024-12-19 10:42:36 -05:00
scawful
d0ac8d75e2 cleanup sprite functions 2024-12-19 09:45:27 -05:00
scawful
2a996a69e5 Update sprite macros for draw code, add new macros 2024-12-19 09:44:08 -05:00
scawful
548379f95a Cleanup floor tag puzzles 2024-12-19 09:43:13 -05:00
scawful
4f42ab2b40 Fix bug where running out of arrows granted you the silvers 2024-12-19 09:42:52 -05:00
scawful
3221dc694e Add SprCustom RAM 2024-12-17 08:42:47 -05:00
scawful
72e5427173 Add kydreeok boss notes 2024-12-17 08:41:35 -05:00
scawful
91048dd066 Add minecart mechanic notes 2024-12-17 08:41:23 -05:00
scawful
9138995669 Mark magic bean quest done 2024-12-17 08:41:02 -05:00
scawful
a9fadbef75 Add macros for flags, status registers, and jump tables 2024-12-16 22:38:32 -05:00
scawful
87a69d44ac Add MagicBean_DragPlayer and MagicBean_Finished 2024-12-16 22:37:26 -05:00
scawful
bf5bba7022 Update BeanVendor_Prep 2024-12-16 22:37:02 -05:00
scawful
5713b2357d Add grass animation frames to magic bean 2024-12-16 22:36:40 -05:00
scawful
b53d236641 Add shadow to bean vendor/magic bean 2024-12-16 21:51:29 -05:00
scawful
a5d3698d5c Update symbols.asm 2024-12-15 17:57:38 -05:00
scawful
39dbe806a8 Add Sprite_CheckCollisionWithSprite 2024-12-15 17:57:04 -05:00
scawful
3b9352620e Update MagicBean song of storms logic 2024-12-15 17:56:35 -05:00
scawful
a428d736f5 Add CheckForDailyQuests for magic bean day cycles 2024-12-15 17:56:11 -05:00
scawful
febb2adef8 Dismiss magic bean item sprite when planted 2024-12-15 17:23:21 -05:00
scawful
e0166057c7 Cleanup Ocarina song notes and comments 2024-12-15 16:29:58 -05:00
scawful
c430f9c4a9 Add MagicBean event to OcarinaEffect_SummonStorms 2024-12-15 16:16:28 -05:00
scawful
be4a5d9b8c Fix Sprite_CheckForPresence and Sprite_SetupHitBox 2024-12-15 16:15:24 -05:00
scawful
3c1a8d7298 Add MagicBean_FertileSoil and setup sprite detection 2024-12-15 16:14:22 -05:00
scawful
2459ea0e98 Add MagicBean_BottleLogic fn 2024-12-15 16:13:57 -05:00
scawful
1e7bf4d727 Update MagicBean to check for GoodBee hitbox overlap 2024-12-13 10:16:39 -05:00
scawful
71f0471014 Add SetFrame and SpriteJumpTable macros 2024-12-13 10:16:04 -05:00
scawful
82193a9003 Update Sprite_SetupHitBox labels, add alt entry for pos1 args 2024-12-13 10:14:45 -05:00
scawful
f9060d7c15 Add MagicBeanProg SRAM for flower quest progress 2024-12-13 10:13:42 -05:00
scawful
f0fb30bc7b Add Sprite_CheckForPresence, takes $00 as SprID 2024-12-13 09:50:48 -05:00
scawful
ba3657505a Cleanup great sea music 2024-12-11 09:11:05 -05:00
scawful
08b9669452 Lower frozen hyrule volume 2024-12-11 09:10:44 -05:00
scawful
41e3fd67ed Cleanup impa npc asm 2024-12-11 09:08:05 -05:00
scawful
6389b7084b Fix bug with GameOver_FadeAndRevive in Eon Abyss 2024-12-10 21:16:53 -05:00
scawful
aad56348d3 Dismiss deku NPCs in the caves if tail palace cleared 2024-12-10 20:40:31 -05:00
scawful
cbfe459820 Move Minecart Track tile type behavior to followers.asm 2024-12-10 20:15:27 -05:00
scawful
c5c8edb8dc Add LinkState_Minecart replacing LinkState_UsingBombos 0x09 2024-12-10 20:13:28 -05:00
scawful
20afe1811b Add Minecart_AnimDirection table 2024-12-10 20:13:10 -05:00
scawful
a4a5738626 Update directional mosaic table in ZSCustomOverworld 2024-12-10 19:18:53 -05:00
scawful
5b1e4bc783 Disable EnableBeginningRain in ZSCustomOverworld 2024-12-10 19:18:23 -05:00
scawful
50f18743d1 Add MinecartFollower_TransitionToSprite for DrawMinecartFollwer 2024-12-10 19:17:05 -05:00
scawful
5368f498ea Add Crumble Floor Room Tag, include in dungeons.asm 2024-12-10 19:03:43 -05:00
scawful
69554a4c9b sprite cleanup 2024-12-10 19:01:58 -05:00
scawful
56439fd7ab cleanup gbc_form.asm 2024-12-10 17:56:03 -05:00
scawful
759cadc30d Move sprite includes from ZSpriteLib to Core 2024-12-10 17:55:50 -05:00
scawful
e5a220e84c cleanup followers.asm 2024-12-10 17:55:25 -05:00
scawful
aa50be2e15 Move ZSpriteLib files to Core 2024-12-10 17:55:10 -05:00
scawful
21bd65b5eb Update Minecart WaitVert and WaitHoriz, add LinkSomaria symbol 2024-12-09 19:21:10 -05:00
scawful
e794152520 Add TingleId SRAM, various housekeeping 2024-12-09 19:12:45 -05:00
scawful
aa220eb9c4 Replace Minecart macros with fns, add Minecart_SetDirectionX fns 2024-12-09 19:11:51 -05:00
scawful
e4f000b891 Add note about MinecartDirection prep conflict 2024-12-09 19:10:41 -05:00
scawful
f779a90864 sprite housekeeping 2024-12-08 20:13:11 -05:00
scawful
87784b7693 minecart subtype bug fix 2024-12-08 20:12:56 -05:00
scawful
26f8d7a862 time system housekeeping 2024-12-08 20:12:32 -05:00
scawful
efcd0f0ac3 menu housekeeping 2024-12-08 20:12:12 -05:00
scawful
70f13ff1c0 mask housekeeping 2024-12-08 20:11:58 -05:00
scawful
d9bd2ad4aa cleanup all_sprites.asm 2024-12-04 18:18:09 -05:00
scawful
335cd261e0 Add damage flash to eon leever 2024-12-04 18:17:51 -05:00
scawful
411002164d Add Fortress_SFX fn for overlay anim 2024-12-04 18:17:38 -05:00
scawful
36a78555fd Cleanup todos and add comments to overworld entrances and overlays 2024-12-02 19:57:41 -05:00
scawful
db4e6185d6 Add Fortress of Secrets entrance overlay 2024-12-02 19:50:53 -05:00
scawful
2bcf274f0f Kydreeok final boss death bug fix 2024-12-02 18:42:53 -05:00
scawful
bbe79f23e3 Kirby consume player attack improvement 2024-12-02 13:03:43 -05:00
scawful
5a5dc38712 Enemy collision improvements 2024-12-02 13:01:05 -05:00
scawful
0c97c2f475 housekeeping 2024-12-02 11:48:55 -05:00
scawful
0a8e86b501 Minecart refactoring, break up collision handling into multiple fns 2024-12-02 11:48:02 -05:00
scawful
4145ea8e4b Update Zora handler 2024-12-02 11:47:38 -05:00
scawful
01e530e5fa Update Eon Abyss Village Dog 2024-12-02 11:47:19 -05:00
scawful
39854cabf8 Update Goron sprite interaction logic 2024-12-02 11:46:59 -05:00
scawful
4e448d5ab3 Add EonZora idle walk and interaction logic 2024-12-02 11:46:15 -05:00
scawful
bd0af82aba Add Eon Abyss Sea Zora and Goron dialogue 2024-12-02 11:45:11 -05:00
scawful
c13c37d5b7 Restore custom entrance code 2024-12-02 07:13:35 -05:00
scawful
60bcb90636 Cleanup Oracle_main 2024-12-02 05:21:24 -05:00
scawful
74cdaa0f59 Update darknut draw 2024-12-01 15:30:35 -05:00
scawful
fa60680b80 Update leever draw and add tile collision 2024-12-01 15:30:12 -05:00
scawful
f761a34f7a despawn intro owl after getting sword 2024-12-01 15:29:51 -05:00
scawful
f9683a2280 Cleanup Leever 2024-12-01 10:14:40 -05:00
scawful
f0aa7f19ab Random chance of hearts from bush instead of guards 2024-12-01 10:14:23 -05:00
scawful
32903cd34e Add custom collision ZS source 2024-11-29 18:20:54 -05:00
scawful
5172a85897 Overworld cleanup 2024-11-29 18:20:38 -05:00
scawful
c94733b37e Dungeon cleanup and zora follower collision 2024-11-29 18:20:15 -05:00
scawful
530d8eca9e add hardware.asm for zs custom ow 2024-11-29 16:28:38 -05:00
scawful
acdc46e5f3 Update XLR item cheat to max items again 2024-11-29 16:07:25 -05:00
scawful
ac8c689d9c Add ZSCustomOverworld_Latest, speed up transitions and fix exit bug 2024-11-29 16:05:14 -05:00
scawful
4b7515651a ThunderGhost fix lightning attack draw 2024-11-29 16:04:51 -05:00
scawful
ab6c1cfdf7 Add recoiling to Helmet Chuchu 2024-11-29 16:04:33 -05:00
scawful
2e3f06d6d8 Update mask form palette upload to use time of day 2024-11-29 16:03:49 -05:00
scawful
860e616c17 Fix Bean Vendor bug 2024-11-29 15:15:47 -05:00
scawful
0fa952c9b0 Fix Tingle map sales logic 2024-11-28 19:59:51 -05:00
scawful
b7e4cd9183 Update util XLR item cheat 2024-11-28 19:50:12 -05:00
scawful
d819b1d26d Add recoiling behavior to a variety of custom sprites 2024-11-28 19:49:10 -05:00
scawful
e9e8944f96 Disable Moosh form indoors 2024-11-28 19:33:47 -05:00
scawful
81084c0aba Fix DekuLink hover cancelled by pit slip bug 2024-11-28 19:26:50 -05:00
scawful
31da8257fe Sprite housekeeping 2024-11-28 17:54:36 -05:00
scawful
b7c73ebf23 Fix bug with Sprite_CheckIfRecoiling 2024-11-28 17:52:48 -05:00
scawful
defda4e20f Add Eon Leever sprite 2024-11-28 17:52:34 -05:00
scawful
58b66bc157 Add PlayAnimBackwards macro 2024-11-28 17:52:02 -05:00
scawful
425ec1d1e1 Day Night system mosaic transition bg color fix 2024-11-28 15:38:57 -05:00
scawful
8a76b19e07 Portal Rod Portal Sprite cleanup 2024-11-28 14:54:56 -05:00
scawful
97e7b7cc78 Deku leaf only sparkle if deku form 2024-11-28 14:54:41 -05:00
scawful
5115fccdcf Add sparkle to deku leaf when standing on 2024-11-28 14:53:26 -05:00
scawful
3d4af7b68b Update ResetToLinkGraphics as fn with dw logic 2024-11-28 14:33:43 -05:00
scawful
73d100d5df Fix bug with using masks in dark world dungeons 2024-11-28 14:33:15 -05:00
scawful
130df6b653 Minecart and follower stuff 2024-11-28 11:29:00 -05:00
scawful
07451bc0ca boss housekeeping 2024-11-28 11:28:24 -05:00
scawful
a0a31549e8 npc housekeeping 2024-11-28 11:27:34 -05:00
scawful
d54d3147e7 Lower booki and anti-kirby health 2024-11-28 01:03:58 -05:00
scawful
adbac4cadb Add village_elder.asm and update map icon marker set 2024-11-28 00:55:23 -05:00
scawful
fc80fda459 NPC Housekeeping 2024-11-28 00:55:03 -05:00
scawful
033d2e76f0 Update VillageDog and EonDog lifting logic 2024-11-28 00:54:06 -05:00
scawful
194695abf8 Disallow Minish form during intro 2024-11-27 19:24:13 -05:00
scawful
0fb961e146 Cleanup symbols, rearrange elements 2024-11-27 17:12:04 -05:00
scawful
1c2686c4a7 Items housekeeping 2024-11-27 17:09:48 -05:00
scawful
c11e112a40 Fix bug with Sprite_SelectNewDirection data bank long jump 2024-11-27 13:41:02 -05:00
scawful
834da79237 Fix Ocarina fallthrough to song of time bug 2024-11-27 10:55:02 -05:00
scawful
8c8611465f Enemy housekeeping 2024-11-27 10:54:47 -05:00
scawful
2d0942a1d9 Update Darknut enemy sprite probing behavior 2024-11-27 10:54:02 -05:00
scawful
b3be08ebcc NPC housekeeping 2024-11-26 10:05:10 -05:00
scawful
173f5816c5 Boss housekeeping 2024-11-26 10:04:20 -05:00
scawful
37b1444e06 Fix Ocarina song to wrong song bug 2024-11-26 10:03:46 -05:00
scawful
dfa80dc4a4 Fix Anti-Kirby priority draw, cleanup and optimize code 2024-11-21 21:46:54 -05:00
scawful
05ef14311a Fix Octorok priority gfx bug 2024-11-21 21:35:05 -05:00
scawful
daf8d4c39d Sprite housekeeping 2024-11-21 21:29:50 -05:00
scawful
d4843293f2 Reduce HelmetChuchu health 2024-11-21 21:29:04 -05:00
scawful
454f84382e Add ThunderGhost attack act as barrier, inflict recoil 2024-11-21 21:28:12 -05:00
scawful
6def732e80 Improve Goriya collision and movement AI 2024-11-21 21:27:56 -05:00
scawful
78cf800378 Sprites housekeeping 2024-11-21 21:02:28 -05:00
scawful
f25ae499d7 Make BusinessScrub enemy sprite persist off screen 2024-11-21 20:59:16 -05:00
scawful
b630bf90d9 Cleanup IceBlock sprite, add TODO plan for improving collision 2024-11-21 20:51:31 -05:00
scawful
ec785dafb6 Clear new inputs and add timer check to new R button press 2024-11-21 15:09:56 -05:00
scawful
48b7228ff2 Lower puffstool enemy health 2024-11-21 14:51:14 -05:00
scawful
db8e9dc774 Lower color dungeon theme volume 2024-11-21 14:25:08 -05:00
scawful
271f6b0480 Update tasks status, move dream sequences to side quests 2024-11-19 21:45:12 -05:00
scawful
3f06909deb Cleanup overworld, merge special area code and remove maku_tree.asm 2024-11-19 21:44:45 -05:00
scawful
4b4256133b Adjust world map icons/ram, show level 1 icon alone, 2-7 grouped 2024-11-19 20:47:49 -05:00
scawful
ce5d9f7620 Housekeeping 2024-11-19 20:38:49 -05:00
scawful
a1bbeabcee oracle.org sprites section, add timeline, update tasks 2024-11-19 20:37:39 -05:00
scawful
9aa9d39c78 Replace more common sprite ram with symbols 2024-11-19 16:25:24 -05:00
scawful
b17b2125be Refactor Kydrog boss, condense macros into functions 2024-11-19 16:11:46 -05:00
scawful
a4ec5b9f7a Replace common sprite ram with their symbols 2024-11-19 16:11:23 -05:00
scawful
2b90a21925 Add save ram value timeline to oracle.org 2024-11-19 14:58:53 -05:00
scawful
3f27c9ab48 Cleanup some NPCs 2024-11-19 14:58:32 -05:00
scawful
d88410e9c2 Cleanup Pols Voice 2024-11-19 14:57:39 -05:00
scawful
1abe75ddb1 Add maku tree map indicator during intro
Move map icon and dungeon id documentation to symbols.asm
2024-11-19 14:56:38 -05:00
scawful
caab7bf1e0 Cleanup jump feather and sword collect asm 2024-11-19 13:50:12 -05:00
scawful
1cf4935dcf Adjust darknut health values 2024-11-19 13:49:46 -05:00
scawful
5aa9e97375 Add comments and cleanup Minecart, Mineswitch, switch_track 2024-11-17 13:48:51 -05:00
scawful
a2af6a176a Housekeeping 2024-11-16 12:32:55 -05:00
scawful
c5374768c4 Make Twinrova hitbox more consistent 2024-11-16 12:31:36 -05:00
scawful
a75b775cc6 Change Overlord_KalyxoCastleGuards to 0x04 2024-11-16 12:31:12 -05:00
scawful
7e2d44dedf Cleanup followers.asm 2024-11-16 12:30:19 -05:00
scawful
75238da73d Misc housekeeping 2024-11-10 18:49:20 -05:00
scawful
6044a92a3a Disable experiment overworld entrance, area, cleanup lost woods cam 2024-11-10 18:48:28 -05:00
scawful
526ed5b20a Update sprite list in oracle.org 2024-11-10 18:47:38 -05:00
scawful
e3056ca827 Housekeeping, whitespace cleanup 2024-11-09 21:26:39 -05:00
scawful
6b3118b14b Fix Tingle not enough rupees dialogue 2024-10-27 16:58:59 -04:00
scawful
8b3456301f add Overlord X, Y, and Timers to symbols.asm 2024-10-26 18:45:15 -04:00
scawful
d718a1de43 add Overlord_SpawnSoldierPath 2024-10-26 18:44:59 -04:00
scawful
7cdd24a7fc add Overlord_KalyxoCastleGuards 2024-10-26 18:44:50 -04:00
scawful
e227700343 update Link_FallIntoDungeon IDs 2024-10-26 18:44:17 -04:00
scawful
6517b6ee18 Update labels for all messages 2024-10-26 13:34:07 -04:00
scawful
47073551d6 Remove player.asm, merge into tables.asm 2024-10-26 13:32:09 -04:00
scawful
bef7fefc19 Turn messages.txt into messages.org 2024-10-26 11:19:04 -04:00
scawful
66dc6cbab6 Move credits to oracle.org, remove credits.txt 2024-10-26 11:16:25 -04:00
scawful
d5572a80ab Move ROM map info to oracle.org, delete rom_map.txt 2024-10-26 11:15:26 -04:00
scawful
9f9c38c694 Update oracle.org todo 2024-10-25 22:43:34 -04:00
scawful
cc4850dc8b Fix collectible item count draw in magic bag menu 2024-10-25 18:05:54 -04:00
scawful
cd15cf21c7 Update dungeon map gfx 2024-10-25 18:05:44 -04:00
scawful
1f1a8f18ef Add GoronMines EntranceAnimation to overlays 2024-10-25 17:49:44 -04:00
scawful
b1512b6012 Add KalyxoGoron expanded dialogue options 2024-10-25 17:49:22 -04:00
scawful
df77882206 Add KalyxoGoron mines opening dialogue and logic 2024-10-25 17:49:03 -04:00
scawful
d35abce142 Add Zora_HandleDialogue 2024-10-25 16:56:18 -04:00
scawful
324532f614 Add Sea Zora NPC hint and peacetime dialogue 2024-10-25 16:56:02 -04:00
scawful
bd6c1de020 Add PrevScroll SRAM 2024-10-25 16:35:18 -04:00
scawful
96a537f6cd Update Librarian previous translation logic 2024-10-25 16:35:02 -04:00
scawful
07e1fd5bd6 Cleanup ZCustomOverworld 2024-10-25 16:31:33 -04:00
scawful
1defb93144 Housekeeping 2024-10-25 16:30:41 -04:00
scawful
b22d1376f2 Add CheckForTingleMaps, disable map if not purchased 2024-10-25 16:29:49 -04:00
scawful
f800c1bd36 Update Rock Sirloin pickup logic 2024-10-25 10:49:35 -04:00
scawful
b1801640eb Move Music section in Oracle_main 2024-10-25 10:49:21 -04:00
scawful
d3cb9509ef Move LW and DW world map to Bank 40, 41 2024-10-25 10:48:45 -04:00
scawful
deaac178d1 Cleanup sprites 2024-10-25 10:48:25 -04:00
scawful
efe5e8a0d8 Fix collectible item count draw 2024-10-25 10:47:27 -04:00
scawful
f0a89bc7f0 Add Zora_TrackHeadToPlayer for Sea Zora NPC 2024-10-23 14:25:29 -04:00
scawful
ec58ffeeb1 Update Magic Bean flower sprite 2024-10-23 14:18:15 -04:00
scawful
84178d350e Fix Ocarina song menu select logic 2024-10-23 13:43:46 -04:00
scawful
ede8c0cdb0 Fix Ocarina song access logic 2024-10-23 13:33:23 -04:00
scawful
6564efdf3a Update Magic Bag cursor positions and draw names+count 2024-10-23 12:51:00 -04:00
scawful
7ff486b05e Add Menu_CollectibleNames and DrawCollectibleNamesAndCount 2024-10-23 12:50:37 -04:00
scawful
dcad260cfc Prevent grappling onto objects with Goldstar 2024-10-22 10:55:21 -04:00
scawful
6f3a21bcac Update oracle org file, mark some todos and rearrange tasks 2024-10-21 19:46:34 -04:00
scawful
6fefe009db update zora NPC logic 2024-10-19 19:45:04 -04:00
scawful
1337a104d9 add Sea Zora NPC dialogue 2024-10-19 19:26:40 -04:00
scawful
49c4869f3a update Librarian Kalyxo Castle translation 2024-10-19 19:16:53 -04:00
scawful
dfea61e1bc update librarian logic 2024-10-19 19:14:39 -04:00
scawful
9d894a16cf add Scrolls symbol 2024-10-19 19:10:09 -04:00
scawful
f0563c0d8d add Librarian_ScrollQuestComplete 2024-10-19 19:09:42 -04:00
scawful
b6b7b08421 add Librarian_CheckResponse 2024-10-19 19:09:33 -04:00
scawful
9d55a4facb add Librarian_CheckForNoMaps 2024-10-19 19:09:19 -04:00
scawful
ea3a2fbd40 add more librarian translation dialogue 2024-10-19 19:08:52 -04:00
scawful
499d4dca77 Update Librarian translation logic 2024-10-19 18:17:15 -04:00
scawful
b7ceb1d9b4 Add Librarian translation dialogue 2024-10-19 18:16:53 -04:00
scawful
213e3ea4d7 Add secret scroll dialogue for all Kalyxo dungeons 2024-10-19 15:22:31 -04:00
scawful
63020eb37d Update Tingle tail palace dialogue 2024-10-19 14:42:51 -04:00
scawful
cd488e3777 Update TingleMaps ram when buying a map 2024-10-19 14:26:05 -04:00
scawful
427f9b0f6c Update Tingle NPC logic 2024-10-19 14:13:21 -04:00
scawful
1210c96d50 Update Tingle intro message, add player said no response 2024-10-19 14:13:07 -04:00
scawful
e9ebd1a94c Update symbols.asm, add TingleMaps SRAM 2024-10-13 18:15:05 -04:00
scawful
c107609f35 Add Tingle_MapPrompt and Tingle_MapSales using new dialogue 2024-10-13 18:14:36 -04:00
scawful
8e5058f628 Add tingle message binary to message.asm 2024-10-13 18:14:06 -04:00
scawful
ce6c46c21e Add Tingle dialog to messages.txt 2024-10-13 18:13:38 -04:00
scawful
b0be277aeb Time system and custom gfx cleanup 2024-10-12 13:30:18 -04:00
scawful
f32d85ebc5 Allow exit item menu by selecting with A 2024-10-12 13:29:46 -04:00
scawful
635109da00 Update tables.asm reference 2024-10-12 11:58:53 -04:00
scawful
2eb83a6476 Allow the player to lift business scrubs when approaching behind 2024-10-12 10:44:56 -04:00
scawful
3e6cf6ad85 Make Owl sprite impervious to projectiles 2024-10-12 10:44:35 -04:00
scawful
8acffea515 Add MosaicFix for ZCustomOverworld day/night bg on mosaic trans 2024-10-12 10:44:00 -04:00
scawful
d2d8c01926 Merge Zora subtypes into parent sprite, setup Zora_Handler 2024-10-11 00:01:17 -04:00
scawful
b8d931333a Add dialogue and adjust tingle hitbox 2024-10-11 00:00:35 -04:00
scawful
251fb9bb50 Add tingle head tracking logic 2024-10-10 21:18:54 -04:00
scawful
fef595ef2e Fix bug with BusinessScrub pea shot 2024-10-08 21:13:02 -04:00
scawful
119fdfccea Add Sea Zora NPC handler for Zora Princess, Eon Zora, Eon Zora Elder 2024-10-08 20:49:23 -04:00
scawful
13b6a8997c Enable LoadPeacetimeSprites, add Zora Sanctuary map peacetime 2024-10-08 20:47:56 -04:00
scawful
88c76f7aa5 Add Eon Abyss Sea Zora and Sea Zora Elder draw routines 2024-10-08 20:17:11 -04:00
scawful
b31cb0c507 Housekeeping NPCs, Octorok, TransferDungeonMapGfx 2024-10-08 20:11:40 -04:00
scawful
3918eeac17 Add Tingle sprite, move Zora princess to bank 2C 2024-10-08 20:10:50 -04:00
scawful
b740a4fba9 Merge EonScrub into BusinessScrub sprite ID 2024-10-08 15:59:36 -04:00
scawful
46e4bc4dc0 Add TransferDungeonMapGfx and dungeon_maps.bin 2024-10-07 19:47:44 -04:00
scawful
f82c016d48 [Custom Music] Add Makefile for extracting vanilla songs to bin 2024-10-07 14:51:01 -04:00
scawful
f3060e3c9a [CustomTag] Cleanup CrumbleFloorTag 2024-10-07 14:49:28 -04:00
scawful
0099a81adc [Day/Night] Cleanup DrawClockToHud, CheckForSongOfTime 2024-10-07 14:48:54 -04:00
scawful
b19f2e2de1 [ZSCustomOW+Day/Night] Fix bug with CustomBGColor in overlay areas 2024-10-07 14:48:13 -04:00
scawful
3ff70cc4c3 Rename house_tag.asm to custom_tag.asm, move MinishTag 2024-10-07 09:08:51 -04:00
scawful
0e697a87f8 Move functions to symbols.asm, remove Util.functions.asm 2024-10-06 23:41:48 -04:00
scawful
8060b82251 Cleanup Kydreeok and Kydreeok Head 2024-10-06 23:38:43 -04:00
scawful
80828790c9 Cleanup KydrogBoss 2024-10-06 23:38:22 -04:00
scawful
c73c496579 Cleanup Kydrog NPC 2024-10-06 23:38:14 -04:00
scawful
346dc84f31 Align custom RAM skip commands 2024-10-06 21:34:34 -04:00
scawful
a54417ce15 Rename Func02B3A1 to HandleSubscreenBgColorPyramidWarp 2024-10-06 21:33:15 -04:00
scawful
9f93d49718 Housekeeping 2024-10-06 18:41:52 -04:00
scawful
d3baacab34 Move custom RAM to symbols.asm 2024-10-06 18:41:15 -04:00
scawful
dfa41dfa5c Cleanup Minecart 2024-10-06 15:35:12 -04:00
scawful
ee20f2143b Update WaterOctorok action logic 2024-10-06 15:34:39 -04:00
scawful
c37860bd83 Cleanup HelmetChuchu sprite 2024-10-06 12:51:10 -04:00
scawful
93553232ce Cleanup overworld overlays jump table organization 2024-10-06 12:33:34 -04:00
scawful
7749e86421 Rename DekuScrubBro to BusinessScrub in business_scrub.asm 2024-10-06 12:33:08 -04:00
scawful
6dc1c15c21 Add WaterOctorok hiding and shooting behavior 2024-10-06 12:32:41 -04:00
scawful
690a9e4003 Add SetupDistanceFromSprite macro 2024-10-06 09:40:40 -04:00
scawful
1e27733a3b Add WaterOctorok subtype, draw water ripple 2024-10-06 09:32:26 -04:00
scawful
79e71b0a93 Housekeeping 2024-10-06 08:22:39 -04:00
scawful
7638a7f7ec Eon Sea Urchin impervious to sword, better prize pack 2024-10-06 08:22:03 -04:00
scawful
46c7397223 Setup KaeporaGaebora subtype sprite 2024-10-06 08:11:59 -04:00
scawful
98e8fdbc43 Merge KaeporaGaebora into EonOwl sprite instead of BeanVendor 2024-10-06 07:53:44 -04:00
scawful
1d0f140ced Sprite housekeeping 2024-10-04 09:12:17 -04:00
scawful
e22303cb74 Reduce Puffstool enemy health 2024-10-04 09:11:59 -04:00
scawful
25cf8bf7e3 Cleanup Maku Tree 2024-10-04 09:11:43 -04:00
scawful
c271be37f7 Cleanup Piration 2024-10-04 09:11:23 -04:00
scawful
b8b3e15ff3 Housekeeping 2024-10-04 00:09:23 -04:00
scawful
f1f759cbec Cleanup world_map.asm 2024-10-04 00:08:51 -04:00
scawful
15df798812 Add Moosh documentation and cleanup mask_routines 2024-10-04 00:08:19 -04:00
scawful
15ea5fbfe6 Cleanup business_scrub.asm 2024-10-04 00:06:54 -04:00
scawful
adaf5cb5be Update VillageElder world map value 2024-10-04 00:06:27 -04:00
scawful
cb2deb9240 Add EonScrub_Defeated action 2024-10-04 00:06:02 -04:00
scawful
93454f14c5 Update Skeleton Guard dialogue 2024-10-03 19:37:13 -04:00
scawful
6b6ca20e51 Add list of NPCs to org file 2024-10-03 19:23:54 -04:00
scawful
e608e6fe5a Cleanup deku_scrub.asm 2024-10-03 19:23:33 -04:00
scawful
98f58d8b0e Cleanup korok.asm 2024-10-03 19:23:15 -04:00
scawful
79b9f76ab0 Cleanup ranch_girl.asm 2024-10-03 19:23:01 -04:00
scawful
9872d9d0ba Cleanup bug_net_kid.asm 2024-10-03 19:22:47 -04:00
scawful
6fd5e047df Cleanup menu_draw and menu_text components 2024-10-03 19:07:07 -04:00
scawful
5170c4908f Cleanup Wolfos sprite, adjust movement speeds 2024-10-03 19:06:45 -04:00
scawful
8b69e44e42 Rename Dreams directory to Events 2024-10-02 18:21:16 -04:00
scawful
63b8a6faf6 Cleanup menu components 2024-10-02 18:11:59 -04:00
scawful
305e093def Implement Armor Ring in Sprite_AttemptDamageToLinkPlusRecoil 2024-10-01 18:27:46 -04:00
scawful
ed0a8203f8 Cleanup dungeon tags, prepare for CustomTag system 2024-10-01 18:17:16 -04:00
scawful
d28a6f38af Rename HouseTag to CustomTag, move fixed color fade-in effect 2024-10-01 17:50:19 -04:00
scawful
3c33b015c4 Cleanup goldstar.asm 2024-10-01 17:36:55 -04:00
scawful
1c677e0470 Cleanup portal_rod.asm 2024-10-01 17:36:28 -04:00
scawful
1c5dadd4f8 Remove unused SRAM modifier and uncle code 2024-10-01 17:36:05 -04:00
scawful
6881fde0e0 Cleanup ocarina.asm 2024-10-01 00:53:37 -04:00
scawful
a8d10d583a Cleanup ice_rod.asm 2024-10-01 00:53:06 -04:00
scawful
b5ac9a2b52 Add CurrentSong label to Oracle_main.asm 2024-09-30 08:12:17 -04:00
scawful
e8fa9be019 Add menu input for seashells, honeycombs, deku sticks 2024-09-30 08:11:44 -04:00
scawful
42eff19cf1 Update Oracle main banks and header comment 2024-09-29 22:11:51 -04:00
scawful
42ce2c4ee2 Cleanup Asar warnings with deprecated #$ format in tables 2024-09-29 22:01:34 -04:00
scawful
76d08711f0 Cleanup time_system.asm 2024-09-29 21:16:25 -04:00
scawful
1b013499f6 Cleanup world_map.asm 2024-09-29 21:16:11 -04:00
scawful
863b3eaf5d Whitespace housekeeping 2024-09-29 18:10:13 -04:00
scawful
87634efca0 Add MagicRing_CheckForPower during Sprite_ApplyCalculatedDamage 2024-09-29 17:27:00 -04:00
scawful
d0fe5ad320 Move custom_gfx.asm to overworld expanded space 2024-09-29 16:59:22 -04:00
scawful
b28e967a18 Adjust Eon Owl flight path and timer 2024-09-29 11:42:03 -04:00
scawful
a115632478 Add todo for water octorok, golden fish, ice wolfos magic bean, deku stick, honeycomb 2024-09-26 16:51:56 -04:00
scawful
68f9d051cd Whitespace cleanup stuff 2024-09-26 16:51:40 -04:00
scawful
d17c4ad316 Add custom bosses and enemies to Oracle org file 2024-09-25 12:45:38 -04:00
scawful
aed6a84bad Update bank used for expanded music 2024-09-24 08:10:26 -04:00
scawful
07b98bc6c1 Add Zora river conflict ideas, rearrange org file 2024-09-22 20:18:42 -04:00
scawful
f3aa6f900c housekeeping messages, overlays, mermaid 2024-09-22 20:08:17 -04:00
scawful
10466047c8 Refactor time_system.asm 2024-09-22 20:04:24 -04:00
scawful
95ae6131a9 Add Goron Mines and Garo ideas to org file 2024-09-22 20:02:37 -04:00
scawful
874c4af85c Cleanup Mermaid subsprites jump table 2024-09-22 16:27:48 -04:00
scawful
ee9b89129c Fix bug with Maple sprite prep 2024-09-22 11:59:51 -04:00
scawful
87aeeadaca Housekeeping 2024-09-22 11:51:18 -04:00
scawful
e4d7a4d73b Fix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicatorFix bug with world map icon hall of secrets indicator 2024-09-22 11:50:45 -04:00
scawful
0bf892e1b4 Module15_0C - Prevent game from setting $7EF3C7 to 06 2024-09-22 11:40:46 -04:00
scawful
c5c7261ff4 Add X icon during Eon Abyss intro to warp 2024-09-22 11:26:57 -04:00
scawful
befe26ae1b Abstract Hall of Secrets and Pyramid Icon in World Map 2024-09-22 11:11:49 -04:00
scawful
75cb1e3c23 Cleanup Time System code 2024-09-22 10:52:38 -04:00
scawful
378c05fc20 Cleanup ThunderGhost sprite 2024-09-22 10:51:48 -04:00
scawful
cfd3c899da Update Sea Urchin prize drop 2024-09-22 10:51:30 -04:00
scawful
7ee71def8f Cleanup Ocarina item code 2024-09-21 14:36:08 -04:00
scawful
353cacde63 Adjust AntiKirby damage based on player sword level 2024-09-21 14:35:23 -04:00
scawful
d3dab072fb Add no sword fist damage and bottle damage 2024-09-19 01:45:28 -04:00
scawful
b981bb14bf Update the oracle.org tracking with librarian todo 2024-09-18 23:41:07 -04:00
scawful
3e73c7ab1a whitespace cleanup 2024-09-18 23:38:18 -04:00
scawful
aa9a75077b Update Mermaid/Maple/Librarian action logic structure 2024-09-18 23:37:34 -04:00
scawful
96aa5f916e Update Song of Time notes in ocarina.asm 2024-09-18 22:37:27 -04:00
scawful
3321528296 Update dungeon items in levels list 2024-09-18 22:36:25 -04:00
scawful
3b0bdd9f4a cleanup whitespace in symbols.asm 2024-09-18 22:31:12 -04:00
scawful
2b452cc04c add more explicit length suffices 2024-09-18 18:43:47 -04:00
scawful
25085330d1 add explicit length suffices 2024-09-18 18:32:10 -04:00
scawful
7489e90092 replace = operator with == 2024-09-18 18:22:05 -04:00
scawful
db9f28bf2a replace warnpc with assert pc <= 2024-09-18 18:21:55 -04:00
scawful
5c98331ddf update task tracking and add urls to docs and discord 2024-09-15 20:35:29 -04:00
scawful
f8a3b130d7 whitespace cleanup 2024-09-15 20:35:15 -04:00
scawful
d72ca53d4d add oracle.org for project progress tracking 2024-09-06 19:49:04 -04:00
scawful
5d65fbc4f6 add peacetime deku scrub npcs 2024-09-04 06:52:09 -04:00
scawful
dcc5907e48 add LoadPeacetimeSprites, use part0 after events for new spriteset 2024-09-04 06:52:01 -04:00
scawful
841be325d5 cleanup whitespace 2024-09-04 06:48:28 -04:00
scawful
7f473eb1c6 add intro music to house tag 2024-08-31 16:26:05 -04:00
scawful
cd883f7c78 add eon abyss village dog draw 2024-08-31 16:25:44 -04:00
scawful
94cdb40437 store rock meat in SRAM when picked up 2024-08-31 16:25:30 -04:00
scawful
42747d9647 add dream cutscene subtype to business scrub 2024-08-31 16:25:14 -04:00
scawful
1f1ef631c4 update ww ganondorf theme 2024-08-31 15:28:50 -04:00
scawful
f87c26b30d update deku theme 2024-08-31 15:26:37 -04:00
scawful
e153440f3a fix sword shield sprite palette 2024-08-31 15:25:11 -04:00
scawful
7ceff90d62 rock sirloin can only be lifted with glove 2024-08-30 19:29:31 -04:00
scawful
a4fda335d6 add RockSirloin sprite state 2024-08-30 19:24:15 -04:00
scawful
c99582aa15 add RockSirloin draw for Lupo Mountain 2024-08-30 19:22:36 -04:00
scawful
794e96917c add vasu ring shop sign dialogue 2024-08-30 18:52:53 -04:00
scawful
a8c4bf9b2c update eon goron draw 2024-08-30 18:36:05 -04:00
scawful
50aa2d5219 add dialogue for small sword and shield 2024-08-30 18:28:50 -04:00
scawful
3a84630d41 update goron sprite, include in game 2024-08-29 21:46:41 -04:00
scawful
052036b0f4 reorder object_handler, label heavy pot routines 2024-08-29 21:39:51 -04:00
scawful
a719498033 replace stone tower temple with deku theme 2024-08-29 20:24:22 -04:00
scawful
377741c667 refactor octoboss 2024-08-29 20:23:58 -04:00
scawful
57d431e3b7 refactor object_handler 2024-08-29 20:23:41 -04:00
scawful
536671d5f4 goron sprite template with kalyxo and eon draw data 2024-08-29 20:23:31 -04:00
scawful
3b304524ab add more labels to ZCustomOverworld2 2024-08-27 18:41:57 -04:00
scawful
fe93bf3238 remove unnecessary todo 2024-08-27 18:41:43 -04:00
scawful
b0b825cce9 fix save and quit bg color bug 2024-08-27 18:41:37 -04:00
scawful
ed9d5dd48b fix song of time activation bug 2024-08-26 08:00:20 -04:00
scawful
acd2befbc1 check for dungeon map interface in InitTilesets, fix bug 2024-08-25 15:24:16 -04:00
scawful
1632dc595f add kiki hop and walk data todo 2024-08-24 19:11:29 -04:00
scawful
4cd398b967 add octoboss sprite hook 2024-08-24 19:10:52 -04:00
scawful
b7109d5420 kiki only runs away if health is very low 2024-08-24 11:14:46 -04:00
scawful
e27896f554 remove bad pushpc 2024-08-24 09:37:54 -04:00
scawful
16f5dc7014 feat: Update master sword behavior and dialogue
- Make the pedestal sword the lv4 sword
- Change the dialogue for the sword pull
2024-08-22 22:05:35 -04:00
scawful
e75101a68c set collectibles to sprite id 0x52 2024-08-22 18:22:34 -04:00
scawful
7b24d677f8 merge whirlpool with deku leaf sprite slot 2024-08-22 18:21:08 -04:00
scawful
2572d56520 dialogue updates 2024-08-22 17:24:45 -04:00
scawful
21f4c127c4 add more dialogue 2024-08-22 13:19:25 -04:00
scawful
8f5e0e4365 add more non-vanilla dialogue from the game for feedback 2024-08-22 11:28:59 -04:00
scawful
a291c6acae dialogue updates 2024-08-22 11:06:28 -04:00
scawful
38c0aeec42 maku tree housekeeping 2024-08-21 19:33:55 -04:00
scawful
4143b82247 add important dialogue messages for reference and feedback 2024-08-21 19:33:07 -04:00
scawful
dc29bf0e9d add new dungeon dream entrance ID 2024-08-18 22:31:53 -04:00
scawful
486c9b6766 add maku tree dream sequence dialogue 2024-08-18 22:31:30 -04:00
scawful
6aaf28872d clear custom gfx flag for korok cove 2024-08-18 21:52:55 -04:00
scawful
07851b97ec add movement to koroks, update draw data 2024-08-18 21:52:42 -04:00
scawful
2c38035279 fix korok gfx initialization 2024-08-18 21:52:28 -04:00
scawful
a90e73f06c fix octorok shooting direction, random 4way shot logic 2024-08-18 20:16:55 -04:00
scawful
ae8bd1ae64 fix octorok draw priority 2024-08-18 20:05:43 -04:00
scawful
1fcb453776 experimental special ow camera values 2024-08-18 19:56:01 -04:00
scawful
62d83abf05 set expanded special ow as small map size 070A, 070E 2024-08-18 19:55:48 -04:00
scawful
0db8c201a8 add LoadSpecialOverworld
Interrupts the vanilla LoadSpecialOverworld function after LoadOverworldFromUnderworld is called. Adds additional data to the table for more special areas.
2024-08-18 17:59:21 -04:00
scawful
d45a877738 add special area return trigger for OW 91 2024-08-18 17:51:46 -04:00
scawful
78162e3768 add new special overworld trigger for minish houses 2024-08-18 17:51:26 -04:00
scawful
e01a21e29e update tables for reference 2024-08-18 17:50:50 -04:00
scawful
b74dfc0233 update link state to falling in Link_FallIntoDungeon 2024-08-18 17:50:43 -04:00
scawful
1f38fb5fc0 add blanket and fade to black to MakuTree_HandleDreams 2024-08-18 17:48:47 -04:00
scawful
8a43a0d570 fix eon owl sprite prep 2024-08-18 16:38:05 -04:00
scawful
0173742a00 fix LoadTransAuxGFX dungeon bug, add labels to ZS OW V2 2024-08-18 15:35:39 -04:00
scawful
a4ddf1eb22 restore song of storms for ZSCustomOverworldV2 2024-08-17 18:53:47 -04:00
scawful
c33cdc87ca fix maku tree hitbox on subsequent visits 2024-08-17 18:36:37 -04:00
scawful
3d1ea38096 diagnose and add todo for lost woods scroll bug 2024-08-17 18:32:41 -04:00
scawful
e289b2246e fix maple bottle rejection dialogue 2024-08-17 18:19:55 -04:00
scawful
4935eb301d fix business scrub clearing liftable sprite bug 2024-08-17 18:04:43 -04:00
scawful
8b6785c7cc add Castle_RestoreCamera for bridge cutscene 2024-08-17 17:58:28 -04:00
scawful
bda31162ea lower DW raven damage 2024-08-17 17:34:25 -04:00
scawful
e0b258f8b9 time system housekeeping 2024-08-17 17:26:01 -04:00
scawful
25e9d307e8 reorganize Oracle_main.asm 2024-08-17 17:25:03 -04:00
scawful
b16b192cd3 SetBGColorMainBuffer hook for ZS OW v2, comments 2024-08-17 17:12:56 -04:00
scawful
84c3a4230d fix reference to BackgroundFix in ReplaceBGColor using Oracle namespace 2024-08-17 17:11:24 -04:00
scawful
fe379a6067 add palette buffer and cgram labels to time system 2024-08-17 15:37:39 -04:00
scawful
1d4583b85d add temp fix for expanded messages 2024-08-17 14:49:17 -04:00
scawful
46d5864e50 set freespace address of day/night fix in ZS OW v2 2024-08-17 12:24:48 -04:00
scawful
7868ad654b remove hardcoded 0E freespace from time system 2024-08-17 12:24:32 -04:00
scawful
f35a850f98 add ram_map.txt to core 2024-08-16 13:53:15 -04:00
scawful
ed8cf3f205 todos for rain overlay song of storms 2024-08-16 13:53:02 -04:00
scawful
3270294fc2 wrap old bg color mosaic fix in conditional 2024-08-16 13:51:41 -04:00
scawful
713c5ddcdc Add day/night background color fix to ZS OW v2 ReplaceBGColor 2024-08-16 11:29:14 -04:00
scawful
ece1dfa7d7 Refactor day/night system to support ZS_CUSTOM_OW_V2 flag 2024-08-16 11:28:41 -04:00
scawful
94a134246e add ZS_CUSTOM_OW_V2 conditions to day night system 2024-08-16 10:49:11 -04:00
scawful
a67a59874e add ZS_CUSTOM_OW_V2 flag and conditional 2024-08-16 10:46:49 -04:00
scawful
682fd5a991 add ZCustomOverworld2 with debug sections removed 2024-08-16 10:33:52 -04:00
scawful
772698ef04 despawn eon owl from forest of dreams outside of intro 2024-08-14 10:04:12 -04:00
scawful
b80893b03a maku tree run dialog when link nearby for intro 2024-08-10 16:50:36 -04:00
scawful
0a53f01b32 remove test maku tree handle dreams entry point 2024-08-10 16:49:07 -04:00
scawful
d1948541c4 add timer and adjust eon owl flying speed 2024-08-10 14:12:15 -04:00
scawful
b206f12c50 update oam alloc and subtype for collectible sword 2024-08-10 14:06:12 -04:00
scawful
f0f27a0a1e fix maple shopkeeping bug 2024-08-10 13:59:17 -04:00
scawful
e90f0d8340 add SwordShield collectible to map 0x58 2024-08-10 13:58:36 -04:00
scawful
33bc0d855c add Sprite_SwordShield_Draw 2024-08-10 13:58:23 -04:00
scawful
c12898c9e0 remove sword shield from farore sequence 2024-08-10 13:58:02 -04:00
scawful
a5c31ad55c fix deku scrub npc mask barrier softlock 2024-08-10 13:45:16 -04:00
scawful
090911e635 add Lv1_Sword to collectible sprite 2024-08-10 13:28:17 -04:00
scawful
e8ca936cda add pineapple to collectible sprite 2024-08-10 13:27:34 -04:00
scawful
074453c39e add eon owl dialogue 2024-08-10 13:26:38 -04:00
scawful
eab1f82875 update piratian movement 2024-07-28 16:55:41 -04:00
scawful
1c229e346c add sram for all collectibles 2024-07-28 16:55:14 -04:00
scawful
6a84b1349c add Collectible sprite for pineapple and others 2024-07-28 16:55:02 -04:00
scawful
e27f24f1cd add pea shot to EonScrub 2024-07-28 16:12:44 -04:00
scawful
25da6a8a66 add seashell, honeycomb, deku stick to magic bag 2024-07-28 16:12:18 -04:00
scawful
4f353eac07 update eon scrub and eon owl oam alloc 2024-07-27 17:44:03 -04:00
scawful
29063638ef include new octorok and piratian 2024-07-27 17:43:34 -04:00
scawful
e2fa989cdf add Sprite_Piratian_Move, override SnapDragon 2024-07-27 17:43:19 -04:00
scawful
91d6de7733 DEATHS_MAXED = $7EF405 2024-07-27 17:22:42 -04:00
scawful
81edb5792a AncillaAdd_Blanket, SpriteSFX_QueueSFX2WithPan 2024-07-27 17:22:20 -04:00
scawful
a443be7951 add EonOwl ID, update AI 2024-07-27 17:21:45 -04:00
scawful
791c358997 reduce puffstool spore attack grav and x speed 2024-07-27 17:19:27 -04:00
scawful
e7115dbae8 add PeaShot for EonScrub using BusinessScrub SpawnPeaShot 2024-07-27 17:18:33 -04:00
scawful
67e6c4818b update EonScrub ID 2024-07-27 17:18:11 -04:00
scawful
9c1a3186fc add EonScrub logic based on BusinessScrub AI 2024-07-27 16:51:35 -04:00
scawful
827033c31c octorok damage flash and gfx based on direction 2024-07-27 16:51:24 -04:00
scawful
872d3237ee update Sprite_CheckIfRecoiling 2024-07-27 16:50:19 -04:00
scawful
b7674a4c95 make Octorock_ShootEmUp use rand for 4way or single 2024-07-27 15:56:32 -04:00
scawful
fe334be8b5 add shadow to new octorok 2024-07-27 15:56:01 -04:00
scawful
245bc80c9d add Sprite_CheckIfRecoiling to sprite_functions 2024-07-27 15:41:03 -04:00
scawful
9ff8118e5f add Sprite_Octorok_Move based on vanilla logic 2024-07-27 15:40:32 -04:00
scawful
580ca66b78 add Octorok_SpawnRock 2024-07-27 14:58:34 -04:00
scawful
b243803fa8 add Octorok_ShootEmUp, single and 4-way 2024-07-27 14:58:04 -04:00
scawful
32bc3342a5 add piratian draw and template 2024-07-27 14:51:53 -04:00
scawful
305fb04841 rename deku_scrub_enemy to business_scrub 2024-07-27 13:41:43 -04:00
scawful
f95a4b0064 remove last frame of new octorok, stone is a separate sprite 2024-07-27 13:41:05 -04:00
scawful
37efbca816 add eon scrub draw and template 2024-07-27 13:12:19 -04:00
scawful
10f448fa55 add new octorok draw and template 2024-07-27 13:08:43 -04:00
scawful
d326cdbf46 run the puff cloud anim in Puffstool_Spores 2024-07-26 19:47:18 -04:00
scawful
43dcc6157f add toon style puff cloud to puffstool 2024-07-26 19:46:46 -04:00
scawful
5d0e073303 remove old puffstool spore draw 2024-07-26 19:46:30 -04:00
scawful
aa3a85e17e add eon owl sprite template with draw 2024-07-26 19:41:26 -04:00
scawful
7c6fafbdd0 add Link_FallIntoDungeon, takes X to index entrance IDs 2024-07-18 21:41:26 -04:00
scawful
7a98fd1394 update current dream values 2024-07-18 21:33:42 -04:00
scawful
5df32f8968 add long entry point for Link_EnterDream 2024-07-18 21:32:26 -04:00
scawful
b196e4963c set the current dream and jump to Link_EnterDream 2024-07-18 21:24:45 -04:00
scawful
6ad725cbc4 include all_dreams in Oracle_main 2024-07-18 21:20:03 -04:00
scawful
cc202bbb3e add Link_EnterDream in Dreams/all_dreams.asm 2024-07-18 21:11:45 -04:00
scawful
8dc34ac433 add MakuTree_HandleDreams 2024-07-18 21:06:51 -04:00
scawful
841a321364 add CurrentDream free ram 2024-07-18 21:06:21 -04:00
scawful
8a6a453c5c add DREAMS sram 2024-07-18 20:57:25 -04:00
scawful
7b85c0caec Update Catfish Item Get to Bottle 2024-07-16 20:45:14 -04:00
scawful
9d2ffe9e00 misc label housekeeping 2024-07-16 20:23:18 -04:00
scawful
9100b4f845 prevent lift while bunny form 2024-07-16 20:22:38 -04:00
scawful
a4cf2c69bf fix follower disappearing outside bug 2024-07-11 12:54:34 -04:00
scawful
9f426e6f64 remove zora baby follower outdoors 2024-07-10 23:28:56 -04:00
scawful
520045faff allow moosh to fly over minish tiles 2024-07-10 23:18:47 -04:00
scawful
09f4023eae Put LinkState_Bunny HandleAPress in minish_form.asm 2024-07-10 23:18:29 -04:00
scawful
0de6896874 add RingSlotsNum and todo for upgrades 2024-07-10 22:42:43 -04:00
scawful
29040afae5 add new ring found text 2024-07-10 22:42:27 -04:00
scawful
a61d8ce228 housekeeping ring menu 2024-07-10 22:23:34 -04:00
scawful
928a340f67 add RingMenu_StoreRingToSlotStack 2024-07-10 22:21:23 -04:00
scawful
1e203c2cd0 add support for ring slot 2 and 3 2024-07-10 22:09:16 -04:00
scawful
6c287598b9 add ring slot check for effects 2024-07-10 22:07:23 -04:00
scawful
c554991500 update current ring selection logic and draw 2024-07-10 22:03:04 -04:00
scawful
5030d5aec6 update magic ring menu draw 2024-07-10 20:07:29 -04:00
scawful
f60cff4c7b update vasu ring appraisal 2024-07-10 18:50:29 -04:00
scawful
5f21a23205 update ring box menu draw 2024-07-10 18:50:23 -04:00
scawful
3778c6b0bc ZoraBaby adjust body animations in sprite 2024-07-10 11:47:12 -04:00
scawful
b1743d5eb5 add Follower_WatchLink 2024-07-10 11:46:38 -04:00
scawful
f783375003 add NewWaterOverlayData 2024-07-10 08:18:15 -04:00
scawful
0dc71ecaa8 add ZoraBaby_CheckForWaterSwitchSprite 2024-07-09 23:17:12 -04:00
scawful
a74f23fb44 add ZoraBaby_PullSwitch 2024-07-09 22:44:02 -04:00
scawful
13756f7908 label holes tag routines by num 2024-07-09 21:54:36 -04:00
scawful
900eb1b783 cleanup zora baby jump table 2024-07-09 21:54:18 -04:00
scawful
97ed0e0412 cleanup follower labels 2024-07-09 21:54:10 -04:00
scawful
20c35b8bb3 add ZoraBaby_CheckForWaterGateSwitch 2024-07-09 21:33:47 -04:00
scawful
89de0d14b2 zora mask dont resurface on switch 2024-07-09 20:01:37 -04:00
scawful
aae64e8298 update zora temple water collision 2024-07-09 19:36:19 -04:00
scawful
95959f8692 cleanup follower code 2024-07-09 18:06:37 -04:00
scawful
e419c779e1 override locksmith for zora baby sprite 2024-07-09 17:57:58 -04:00
scawful
c16e138572 add aliases for various common symbols 2024-07-09 17:19:48 -04:00
scawful
0d9a8eb5dd upload zora baby follower gfx in prep 2024-07-09 17:14:27 -04:00
scawful
1b6ccdd108 update zora baby idle draw 2024-07-09 17:14:18 -04:00
scawful
29de97c3e2 update vasu ring appraisal logic 2024-07-09 16:30:54 -04:00
scawful
346249e670 cleanup follower code 2024-07-09 15:50:33 -04:00
scawful
8ebe8c5ca9 Add ZoraBaby_RevertToSprite 2024-07-09 15:49:39 -04:00
scawful
cf3146ecf8 cleanup twinrova 2024-07-09 14:16:23 -04:00
scawful
f6e37f45e8 Make Zora follower blue palette 2024-07-09 14:14:02 -04:00
scawful
64e039a505 make zora follower sway like a girl 2024-07-09 14:13:53 -04:00
scawful
92009c9c3a move MinecartFollower to followers.asm bank 2C 2024-07-09 13:50:01 -04:00
scawful
5c3e66bc7d bank organization n cleanup 2024-07-09 13:49:28 -04:00
scawful
0a5f006031 Add Sprite ID labels for all custom sprites 2024-07-09 11:53:44 -04:00
scawful
5dece0f764 remove mothula 2024-07-09 11:28:35 -04:00
scawful
9a151517a6 reorganize all_sprites 2024-07-09 11:16:07 -04:00
scawful
981e0d3200 change running man body draw palette 2024-07-09 10:52:28 -04:00
scawful
e04b9994ec add DekuLink_CancelBeforeTransition 2024-07-09 10:36:33 -04:00
scawful
dc571cd7f1 add vasu appraisal dialogue branch 2024-07-08 22:42:32 -04:00
scawful
7b10c7fd29 dismiss cape flag when switching items 2024-07-08 22:14:47 -04:00
scawful
7bb24227d0 dismiss moosh when playing song again 2024-07-08 22:05:06 -04:00
scawful
c2d6b9ce06 update moosh fly movement anim 2024-07-08 22:02:26 -04:00
scawful
b937582c87 I am Error dialogue 2024-07-08 21:02:08 -04:00
scawful
a106bf8fe5 dont reset moosh from menu 2024-07-08 20:58:36 -04:00
scawful
fcf843b626 add Moosh form to Eon Abyss Song of Soaring 2024-07-08 20:27:28 -04:00
scawful
b48324805b remove RingBox and SongMenu DeleteCursor 2024-07-08 16:55:26 -04:00
scawful
f1ca9136dc add Menu_DeleteCursor_AltEntry 2024-07-08 16:55:10 -04:00
scawful
ed31090b04 add Vasu_AppraiseRing 2024-07-08 16:50:51 -04:00
scawful
ab4f265596 add FOUNDRINGS sram for vasu appraisal 2024-07-08 16:50:41 -04:00
scawful
aa9a62721c add ring names and descriptions 2024-07-08 16:44:27 -04:00
scawful
b99473c10c add Menu_DrawRingsInBox 2024-07-08 16:44:13 -04:00
scawful
678ca692f7 add RingMenu and RingBox tilemap 2024-07-08 16:43:40 -04:00
scawful
bb3f94c28a Move CheckBottle to Menu_Exit 2024-07-08 16:43:05 -04:00
scawful
df291e9305 replace CheckBottle with RingMenu 2024-07-08 16:42:47 -04:00
scawful
870ffc99a3 update vasu dialogue interaction tree 2024-07-08 12:17:22 -04:00
scawful
15efddf019 add MsgChoice to symbols 2024-07-08 11:18:50 -04:00
scawful
9cb6d4494e add 3 choice dialogue to vasu 2024-07-08 11:18:39 -04:00
scawful
4406c3cbc2 move magic rings sram to magic_rings.asm 2024-07-08 10:52:08 -04:00
scawful
8aaaaf9436 reorganize dungeon banks 2024-07-08 10:51:49 -04:00
scawful
5c0c1cd1be add sfx to floor puzzles 2024-07-08 10:50:09 -04:00
scawful
176a54abda add vasu/error sprite 2024-07-08 00:39:56 -04:00
scawful
25f97748d5 add heart ring, slowly regenerate health 2024-07-07 23:12:01 -04:00
scawful
4b20ac9642 add blast ring, uses bombos damage class 2024-07-07 22:19:27 -04:00
scawful
66289c79b1 add light ring, sword beam at -2 hearts 2024-07-07 22:13:16 -04:00
scawful
aa50f568b0 add steadfast ring, reduces knockback when equipped 2024-07-07 22:05:45 -04:00
scawful
f6de58ac44 update magic ring bitwise sram 2024-07-07 22:05:33 -04:00
scawful
dd69c80fb9 fix helmet chuchu and manhandla damage flash 2024-07-07 21:33:58 -04:00
scawful
33d22587d6 fix kaepora gaebora song check 2024-07-07 19:29:37 -04:00
scawful
20c726c6ad only draw shadow for deku scrub projectile 2024-07-07 19:22:10 -04:00
scawful
f6eb25a7ed disallow input while deku spin before hover 2024-07-07 19:15:42 -04:00
scawful
91f6a178b5 update deku bubble sfx 2024-07-07 19:06:58 -04:00
scawful
fa75373c3b fix deku mask poof/bubble crash 2024-07-07 19:02:21 -04:00
scawful
5dfbd97a24 add custom magic bubble gfx 2024-07-07 17:49:52 -04:00
scawful
9a348dd3cd clear inputs after using deku bubble 2024-07-07 17:39:27 -04:00
scawful
0c53d55739 update deku bubble sfx 2024-07-07 17:34:23 -04:00
scawful
aabcc9d653 fix bug with magic bubble ancillae slot alloc 2024-07-07 17:28:10 -04:00
scawful
2347cf8ef8 prevent dashing as deku link 2024-07-07 17:27:50 -04:00
scawful
4edfb72ed4 update deku link magic ability cost 2024-07-07 16:44:21 -04:00
scawful
03ada1312d update magic bubble damage class 2024-07-07 16:42:53 -04:00
scawful
11edd98334 restrict deku abilities to only when mask is equipped 2024-07-07 16:12:24 -04:00
scawful
bb70b5beba add ancilla functions and ram to symbols 2024-07-07 16:03:57 -04:00
scawful
d0f347e3a5 set deku hover flag when player is standing on flower 2024-07-07 16:03:43 -04:00
scawful
e44b0c5fe4 cleanup magic bubble code 2024-07-07 16:03:28 -04:00
scawful
894580538a add DekuLink_ShootBubbleOrStartHover 2024-07-07 16:03:08 -04:00
scawful
312d479950 add MagicBubbleSwapDynamicGfx 2024-07-07 12:47:41 -04:00
scawful
720bcbec9b replace unused ancilla 0E with MagicBubble 2024-07-07 12:47:22 -04:00
scawful
089b487141 add Ancilla_MagicBubbleShot 2024-07-07 12:47:05 -04:00
scawful
86fc3e967a add Ancilla_BoundsCheck 2024-07-07 12:46:33 -04:00
scawful
455c2679f2 add Ancilla move routines 2024-07-07 12:46:19 -04:00
scawful
51dffdb5c6 add Ancilla_SetupBasicHitBox 2024-07-07 12:46:06 -04:00
scawful
91d79ccda2 add Ancilla_CheckBasicSpriteCollision 2024-07-07 12:45:54 -04:00
scawful
85156e07d3 add Ancilla_SFX routines 2024-07-07 12:45:27 -04:00
scawful
e6356dfe45 Hide sword while deku hover 2024-07-07 11:15:09 -04:00
scawful
8c1ff13681 replace sprite labels, more cleanup 2024-07-07 11:11:10 -04:00
scawful
1f2bb46559 cleanup sprite functions and macros 2024-07-07 11:00:28 -04:00
scawful
9e739c8891 fix librarian translation check 2024-07-07 10:37:04 -04:00
scawful
00c59f9234 remove duplicate sprite apply speed function 2024-07-07 10:32:19 -04:00
scawful
0979c4eb81 update all sprites to use SprFlash instead of SprMiscA 2024-07-07 10:20:15 -04:00
scawful
15031bb6ec move Sprite_DamageFlash, replace SprMiscA with SprFlash 2024-07-07 10:19:54 -04:00
scawful
dba7609be2 rename SprPriority to SprFlash based on zel_ram.lst documentation 2024-07-07 10:19:29 -04:00
scawful
6755d482a6 rename sprites.asm to symbols.asm 2024-07-07 00:27:45 -04:00
scawful
c8fe30c8dd remove some print statements 2024-07-07 00:23:12 -04:00
scawful
18ec996f33 cleanup labels, move sprites.asm to main 2024-07-07 00:18:10 -04:00
scawful
f78b4a1d87 scale darknut health with sword 2024-07-07 00:05:16 -04:00
scawful
626633d770 add Ancilla routine labels 2024-07-06 23:34:04 -04:00
scawful
14db4cbd67 add Sprite_Decelerate_X, Sprite_Decelerate_Y 2024-07-06 23:28:25 -04:00
scawful
3d3539f9af add Guard and Prober functions, TrackBodyToHead 2024-07-06 23:26:37 -04:00
scawful
19f13ae7c6 add Sprite_SpawnProbeAlways 2024-07-06 23:19:25 -04:00
scawful
37b8df9b70 update darknut hitboxes for parrying 2024-07-06 20:54:44 -04:00
scawful
967afa2179 update darknut draw 2024-07-06 20:51:38 -04:00
scawful
935346fb13 cleanup deku mask, remove unused code 2024-07-06 19:47:35 -04:00
scawful
f0f89a1fb7 fix deku mask hover speed and control 2024-07-06 18:49:33 -04:00
scawful
28b736b963 move LinkState table 2024-07-06 17:10:21 -04:00
scawful
16d3e80219 move LinkCarryOrToss 2024-07-06 17:08:44 -04:00
scawful
ecd75a49bf cleanup sprite ram 2024-07-06 17:08:28 -04:00
scawful
9045abf919 cleanup link ram 2024-07-06 17:07:31 -04:00
scawful
bb79af6c9f update long function references 2024-07-06 16:34:02 -04:00
scawful
81ae7453e3 fix goldstar open menu bug after dragging 2024-07-06 16:33:33 -04:00
scawful
a9603984e2 update references to new labels 2024-07-06 15:58:19 -04:00
scawful
2823bd9967 add AncillaAdd long routines 2024-07-06 15:53:51 -04:00
scawful
e14096cc78 add Snitch_SpawnGuard, Sprite_KillFriends 2024-07-06 15:53:35 -04:00
scawful
0d71ba3f56 add bank07 long function labels 2024-07-06 15:34:09 -04:00
scawful
2bdf5db12e add ancilla labels and move ancilla table 2024-07-06 15:08:49 -04:00
scawful
730900f6a6 add link ram labels and functions 2024-07-06 15:08:20 -04:00
scawful
29fd3623be add controller ram labels 2024-07-06 15:08:09 -04:00
scawful
bddc3af2a6 add misc ram labels 2024-07-06 15:07:59 -04:00
scawful
8d06c6d19b cleanup sprite labels 2024-07-06 15:06:38 -04:00
scawful
5bea1cc446 cleanup fishing rod, update labels 2024-07-06 13:02:14 -04:00
scawful
49a08548a8 remove running boy check from fishing rod bobber 2024-07-06 11:49:00 -04:00
scawful
1fd01ffc67 change fishing rod bobber to sprite 2D 2024-07-06 11:47:42 -04:00
scawful
d2e5d63926 update goriya draw 2024-07-06 11:20:07 -04:00
scawful
8c94a3afc0 update eon abyss map menu names 2024-07-06 10:40:07 -04:00
scawful
250bf5bc13 finish interior dungeon names in menu 2024-07-06 10:30:58 -04:00
scawful
b4517e7a1b add Meadow_main for Meadow of Shadows v2 using Oracle engine 2024-07-05 23:19:01 -04:00
scawful
d330407409 make librarian persist when changing rooms in library 2024-07-05 23:18:35 -04:00
scawful
b4d6b0f11c add Librarian_OfferTranslation 2024-07-05 23:12:00 -04:00
scawful
f5d986cad5 add Librarian_CheckForAllMaps 2024-07-05 23:11:41 -04:00
scawful
662757185f make deku scrub nut deal damage 2024-07-05 23:00:50 -04:00
scawful
026ca4f576 add dialogue to librarian 2024-07-05 22:54:44 -04:00
scawful
d37a46af86 add shadow to mermaid/maple/librarian 2024-07-05 22:44:39 -04:00
scawful
9774feb399 add librarian subsprite to mermaid/maple 2024-07-05 22:42:49 -04:00
scawful
62b0702b01 fix kaepora gaebora spawn condition bug 2024-07-05 22:35:48 -04:00
scawful
cfeebb772a fix zora link falling animation 2024-07-05 21:51:42 -04:00
scawful
7de26a47f2 force bunny link to fall into pits 2024-07-05 21:51:18 -04:00
scawful
33c6655471 add ZoraMask.fall_into_pit 2024-07-05 21:40:12 -04:00
scawful
90b5b6f292 maple sells milk bottles for 30 rupees 2024-07-05 18:24:47 -04:00
scawful
9e5f42a1a4 update old man dialogue camera trigger 2024-07-05 18:03:48 -04:00
scawful
bff7950c38 cleanup follower code, add table with IDs 2024-07-05 17:44:38 -04:00
scawful
d3db872a5b update old man mountain quest dialogue triggers 2024-07-05 17:38:07 -04:00
scawful
4d18be2777 cleanup maku tree 2024-07-05 17:26:31 -04:00
scawful
a1bd408711 update magic bean dynamic gfx, remove banana as it replaces the apple sprite 2024-07-05 17:26:18 -04:00
scawful
1d7c560b85 add milk bottle item, heals 5 hearts 2024-07-05 17:19:09 -04:00
scawful
7905bae709 label prog flags, magic rings, custom rods save ram 2024-07-05 16:57:52 -04:00
scawful
af227905cb update magic bag offsets and cursor 2024-07-05 16:54:28 -04:00
scawful
e3ae050a4c add greyed out rings to quest menu 2024-07-05 16:48:10 -04:00
scawful
902ffd4f49 update hall of secrets spawn gfx set 2024-07-05 16:43:25 -04:00
scawful
d85b3a20b0 update zora event validation 2024-07-05 16:43:10 -04:00
scawful
45d24bd4a5 add Menu_DrawMagicRings to quest menu 2024-07-05 16:40:28 -04:00
scawful
87e7789dfb update credits 2024-07-05 16:35:06 -04:00
scawful
23a1ea9de1 song menu logic fix 2024-07-05 16:34:06 -04:00
scawful
da4b529f9a restrict song menu based on ocarina save ram 2024-07-05 16:31:02 -04:00
scawful
54bc1ef0a4 move color song note icons to song menu 2024-07-05 16:03:23 -04:00
scawful
56f51239aa hookshot to remove chuchu mask/helmet 2024-07-05 15:04:23 -04:00
scawful
a7366a070a fix lv3 and lv4 sword icons in menu 2024-07-05 14:07:20 -04:00
scawful
dbb6aae9e9 add gold ocarina to hud 2024-07-05 14:07:12 -04:00
scawful
5feb121ab9 add song of time to L/R ocarina switch 2024-07-05 13:58:57 -04:00
scawful
ea1c5c3645 add SpawnPointData, update old man cave 2024-07-05 13:27:29 -04:00
scawful
3aad81da23 set indoors and dark world during old man quest spawn 2024-07-05 13:08:22 -04:00
scawful
ce93cea94b save and continue picks up in dungeon 2024-07-05 13:02:50 -04:00
scawful
26be968026 fix thunder ghost health bug 2024-07-05 12:29:06 -04:00
scawful
34cfa8d870 song of time speeds up clock until day/night 2024-07-05 12:28:35 -04:00
scawful
2402f9cff5 add TimeSpeed ram for controlling day/night 2024-07-05 12:15:57 -04:00
scawful
c4f4e8f9af add spacewiki, evolvingfetus, darklink45 to credits 2024-07-05 11:57:16 -04:00
scawful
962ea7b1dd reuse InvertSpeed_XY for FloatAwayFromPlayer 2024-07-05 11:56:57 -04:00
scawful
fa134b1935 add rock meat gfx to magic bag 2024-07-05 11:56:06 -04:00
scawful
5ea2540965 add gold ocarina icon 2024-07-05 11:55:47 -04:00
scawful
6b52af9004 update inanimate sprites priority draw 2024-07-04 23:37:08 -04:00
scawful
b1ac55cfa2 fix wolfos priority, optimize size 2024-07-04 23:35:07 -04:00
scawful
c023112009 fix village dog priority draw 2024-07-04 23:34:05 -04:00
scawful
0dd74034e0 fix anti kirby priority draw 2024-07-04 23:33:04 -04:00
scawful
edef644ac6 fix sea urchin priority, move to bank 30 2024-07-04 23:32:33 -04:00
scawful
fbd7b4b2c6 add oam buffer info for reference 2024-07-04 23:29:35 -04:00
scawful
45c5389b4d update booki floating movement, chase, hide 2024-07-04 23:27:47 -04:00
scawful
d053b4954d update Sprite_FloatTowardPlayer 2024-07-04 23:27:35 -04:00
scawful
fab2c27356 fix deku scrub enemy priority draw 2024-07-04 23:11:29 -04:00
scawful
589434d87e fix thunder ghost priority draw 2024-07-04 23:10:42 -04:00
scawful
4e7dd28b30 fix puffstool priority draw 2024-07-04 23:09:58 -04:00
scawful
b148529286 fix goriya and boomerang priority draw 2024-07-04 23:09:29 -04:00
scawful
22486ba1ac fix booki priority draw, adjust health by sword 2024-07-04 23:07:44 -04:00
scawful
54c2406d7b adjust thunder ghost health based on sword 2024-07-04 23:06:47 -04:00
scawful
0894f0ec5b fix helmet chuchu priority draw 2024-07-04 23:05:43 -04:00
scawful
d31fbf4010 adjust helmet chuchu health based on sword lvl 2024-07-04 22:53:58 -04:00
scawful
fa07feb5dd add red chuchu without helmet 2024-07-04 22:53:46 -04:00
scawful
88e324d020 replace agah charge sfx with song of time 2024-07-04 20:49:00 -04:00
scawful
725e09858a lower antikirby health 2024-07-04 20:28:51 -04:00
scawful
c61478340d add num of bananas save ram, check for limit in shop 2024-07-04 20:28:42 -04:00
scawful
8440c02952 update shop banana draw 2024-07-04 20:24:41 -04:00
scawful
f5c249a151 add dialogue to korok, make liftable 2024-07-04 16:38:38 -04:00
scawful
d5697d0691 update thunder ghost lightning hitbox 2024-07-04 16:27:15 -04:00
scawful
df5ee69a25 update wolfos sprite 2024-07-04 16:26:06 -04:00
scawful
51f211a61d add puffstool sport attack, adjust health based on sword 2024-07-04 16:21:06 -04:00
scawful
e2efec345d add damage flash to goriya 2024-07-04 16:06:56 -04:00
scawful
b1eb48e14b cleanup sprites lib 2024-07-04 16:04:18 -04:00
scawful
b385e10837 add damage flash to booki 2024-07-04 16:04:07 -04:00
scawful
e71d2900db add damage flash to thunder ghost 2024-07-04 16:03:17 -04:00
scawful
3f9fad8c7f cleanup minecart and switch track 2024-07-04 15:42:12 -04:00
scawful
9f0f17ebf3 fix minecart transition direction logic 2024-07-04 15:41:58 -04:00
scawful
5956800a07 update mineswitch hitbox 2024-07-04 15:06:19 -04:00
scawful
60420d885f update minecart corner tile move timing 2024-07-04 14:39:49 -04:00
scawful
5bf4d5ea7b fix TileBehavior_Pit label addr 2024-07-04 14:39:33 -04:00
scawful
0fa69b9196 update zora princess collision 2024-07-04 14:07:26 -04:00
scawful
978774330d add CheckForFollowerIntraroomTransition to minecart 2024-07-04 13:50:05 -04:00
scawful
2f74fda0cb add pit horiz and vert to minecart 2024-07-04 13:45:33 -04:00
scawful
f993f48376 minecart check for input from pit collision track tile type 2024-07-04 13:43:41 -04:00
scawful
e139f2a8d5 add minecart tracks with pit behavior 2024-07-04 13:43:13 -04:00
scawful
fa7d25663d cleanup portal sprite 2024-07-04 12:10:05 -04:00
scawful
3642c9bc03 add HelmetChuchu_SpawnHookshotDrag 2024-07-04 00:41:47 -04:00
scawful
a7fb4e2e66 add Sprite_CheckForHookshot 2024-07-04 00:38:00 -04:00
scawful
e6ba0d17d3 add puffstool spore subtype 2024-07-04 00:31:22 -04:00
scawful
ad7991570e add Puffstool_SpawnSpores based on octo baby 2024-07-04 00:31:11 -04:00
scawful
9d012e60a0 add collision to maku tree dialog hitbox 2024-07-04 00:11:45 -04:00
scawful
52de697dee reduce octoballoon babies spawned by half 2024-07-03 23:59:04 -04:00
scawful
c4d83c0c89 remove banana bean swap dynamic for now 2024-07-03 23:45:20 -04:00
scawful
9dac3164e3 move world map code to bank 34 for expanded draw 2024-07-03 23:41:36 -04:00
scawful
b429020383 document dungeon ids and vanilla counterparts for reference 2024-07-03 23:41:16 -04:00
scawful
77bc687bb8 update hall of secrets world map icon progression 2024-07-03 23:39:37 -04:00
scawful
0e45cf05fa add fortress and final boss icon to world map 2024-07-03 23:32:13 -04:00
scawful
4fa7f6a2af update master sword map icon 2024-07-03 23:30:30 -04:00
scawful
99275be6a2 add pendant draw to world map 2024-07-03 22:25:19 -04:00
scawful
4f86de444c map icons pendants, master sword, fortress, final boss 2024-07-03 21:58:32 -04:00
scawful
0373c93f5b clear links sweat anim in menu (important for some reason?) 2024-07-03 21:46:00 -04:00
scawful
07ca56cf48 menu clear itemstep, useY1 and useY2 for all items 2024-07-03 21:44:39 -04:00
scawful
5d0bad1071 set $0304 to prevent item + 1 anim exploits 2024-07-03 21:41:27 -04:00
scawful
8ad4835697 fix kalyxo map dungeon markers 2024-07-03 20:35:38 -04:00
scawful
19ac208ecc add eon abyss map progression checks 2024-07-03 20:25:24 -04:00
scawful
0d3124981d add fortress of secrets and master sword prog bits 2024-07-03 20:21:17 -04:00
scawful
a0e2f28b6c rename m maku tree to i intro over 2024-07-03 20:19:49 -04:00
scawful
62373ca600 add pendant quest bit to oosprog 2024-07-03 20:17:57 -04:00
scawful
0ba6edca5d move progression ram to Oracle_main 2024-07-03 20:09:11 -04:00
scawful
e2bf33b2c9 fix crystal/pendant spawn bug 2024-07-03 19:44:44 -04:00
scawful
5721f7542e disable mire rain event in ZCustomOverworld 2024-07-03 00:16:41 -04:00
scawful
edb2f50502 disable beginning rain in ZCustomOverworld 2024-07-03 00:14:49 -04:00
scawful
3b0511e78a update ApplyKorokSpriteSheets 2024-07-03 00:13:50 -04:00
scawful
e5bc8fab7e update spawn point labels 2024-07-03 00:13:28 -04:00
scawful
9b4112e626 move koroks to sprite bank 30 2024-07-03 00:13:13 -04:00
scawful
c300657eea setup korok subsprites makar, hollo, rown 2024-07-03 00:08:51 -04:00
scawful
c0107e2d2f Kid at ranch checks for flute 2024-07-02 23:18:14 -04:00
scawful
0829f52c50 update village elder dialogue 2024-07-02 23:16:17 -04:00
scawful
a93b31679e increase cost of stone mask to 850 rupees 2024-07-02 22:51:45 -04:00
scawful
6b75a5c282 add error beep for unimplemented song of time 2024-07-02 22:39:05 -04:00
scawful
36a88e6a89 change wolfos message id, update health 2024-07-02 22:38:01 -04:00
scawful
f1ca71867a increase deku scrub attack timer, fix prizes 2024-07-02 22:04:42 -04:00
scawful
d9ca14fb41 add shadow to deku scrub enemy 2024-07-02 22:04:03 -04:00
scawful
b7d1b531e1 make deku scrub enemy harmless, pea shot harmful 2024-07-02 19:16:47 -04:00
scawful
3919a0dc7b cleanup new sprite table 2024-07-01 23:14:54 -04:00
scawful
55c23e6844 rename sprite_hooks to sprites 2024-07-01 23:09:28 -04:00
scawful
922ef81a60 add song names to song menu 2024-07-01 09:58:55 -04:00
scawful
d2edbc3346 add song menu cursor 2024-07-01 09:47:53 -04:00
scawful
556b5521f6 transfer song menu gfx and delete cursor before switching 2024-07-01 09:47:47 -04:00
scawful
91e36eea6b update song menu tilemap 2024-07-01 09:47:27 -04:00
scawful
f1ebae06b2 increase big chuchu speed 2024-06-30 21:43:39 -04:00
scawful
fc1136a6bc lower darknut and thunder ghost health 2024-06-30 21:26:27 -04:00
scawful
f0aec7b206 add todo for impa prep code 2024-06-30 21:11:52 -04:00
scawful
ccb411ed7c update mushroom and tail palace hints 2024-06-30 21:00:04 -04:00
scawful
326b84ba3f update fortune teller maku tree flag 2024-06-30 20:56:58 -04:00
scawful
587820f77d add Submenu_Return 2024-06-30 20:49:36 -04:00
scawful
4779c38ed9 add Menu_DrawCursor 2024-06-30 20:47:26 -04:00
scawful
e5941069c0 add cursor to magic bag 2024-06-30 20:43:17 -04:00
scawful
f91ad5e924 adjust magic bag draw positions 2024-06-30 20:43:07 -04:00
scawful
be3d664245 remove byrna text 2024-06-30 20:42:55 -04:00
scawful
d97526e525 Close the magic bag if the player presses start 2024-06-30 20:06:00 -04:00
scawful
8e8ba00497 optimize minecart draw 2024-06-30 19:45:05 -04:00
scawful
a20379c1d8 add Menu_SongMenu 2024-06-30 19:44:51 -04:00
scawful
2ba2de411c add Menu_MagicBag 2024-06-30 19:44:03 -04:00
scawful
ab4d099de4 add print pc to end of ocarina freespace 2024-06-30 17:40:28 -04:00
scawful
ba307c5c32 Add BananaBeanSwapDynamicGfx 2024-06-30 17:40:17 -04:00
scawful
789a949dde update banana bean gfx 2024-06-30 17:39:07 -04:00
scawful
41fb48221f add banana bean dynamic gfx bin 2024-06-30 17:25:20 -04:00
scawful
60e0341b1c cleanup menu anim dismiss 2024-06-30 16:49:11 -04:00
scawful
87b988acfd fix quest icons tilemap 2024-06-30 16:49:01 -04:00
scawful
8cca038c6e add ring gfx to hud 2024-06-30 16:45:09 -04:00
scawful
b348935e98 label banana gfx for hud 2024-06-30 15:55:09 -04:00
scawful
9790a47a51 add ShopItem_Banana 2024-06-30 15:54:03 -04:00
scawful
9603fbfe2f remove manhandla gfx transfer from manhandla sprite action 0 2024-06-30 14:17:19 -04:00
scawful
53c8886ad8 transfer manhandla gfx during room scroll 2024-06-30 14:17:03 -04:00
scawful
e9f9f04655 cleanup twinrova, optimize action size 2024-06-30 14:16:11 -04:00
scawful
79b73163d4 allow wolfos to be normal enemy in dungeons 2024-06-30 14:07:37 -04:00
scawful
61dffd7017 bulk replace SprX/SprY labels to all sprites, .w qualifiers on STAs 2024-06-30 12:34:42 -04:00
scawful
7c4e1841ec lower helmet chuchu health 2024-06-30 11:36:37 -04:00
scawful
cd4db3fee9 prevent lifting while minish 2024-06-30 11:21:44 -04:00
scawful
8a4d974bc6 prevent maku tree from giving you heart container again 2024-06-30 11:13:38 -04:00
scawful
4454892a43 lower puffstool health (again) 2024-06-30 00:48:11 -04:00
scawful
30629d12ba remove SprState reset from MoveBody 2024-06-29 21:30:02 -04:00
scawful
49f6f69aca Skip end cutscene until it's ready 2024-06-29 18:08:54 -04:00
scawful
3b561b1d33 add palette flashing to underwater areas 2024-06-29 18:08:26 -04:00
scawful
6f3218345c include expanded dialogue code 2024-06-29 17:58:29 -04:00
scawful
389b962407 remove test dialogue code, print end of expanded dialogue 2024-06-29 17:58:18 -04:00
scawful
6dc728ffbc maku tree sets lower bits of OOSPROG 2024-06-29 17:55:09 -04:00
scawful
0b98549388 swap maku tree and hall of secrets progress bits 2024-06-29 17:42:23 -04:00
scawful
d826917fa3 update maku tree progress flags 2024-06-29 17:38:45 -04:00
scawful
6e01c630eb fix pullpc misplacement bug 2024-06-29 17:29:53 -04:00
scawful
fe3ebd4c6d use CheckNewRButtonPress for minish form 2024-06-29 17:23:32 -04:00
scawful
9e749a0233 update LinkOAM_CheckForDrawShield 2024-06-29 17:23:16 -04:00
scawful
5a20ba213c add CheckNewRButtonPress 2024-06-29 17:23:03 -04:00
scawful
e7ea1384dc clear wolf dig anim when switching items 2024-06-29 16:15:47 -04:00
scawful
a0f0887fe8 do error beep if trying to become minish with a mask out 2024-06-29 16:05:50 -04:00
scawful
29a8ea27ee move minish shutter door to dungeons.asm 2024-06-29 16:05:34 -04:00
scawful
2d623216d9 add experimental minecart door to object handler 2024-06-29 15:50:52 -04:00
scawful
647b629e93 cleanup portal sprite 2024-06-29 15:49:49 -04:00
scawful
5154c8be3e change OOSPROG sram, interferes with LW/DW flag 2024-06-29 15:45:38 -04:00
scawful
ab64d3b8a6 set maku status flag even after has met link, JIC 2024-06-29 15:31:03 -04:00
scawful
a1bdf2707e lower thunder ghost health and oam alloc 2024-06-29 15:30:46 -04:00
scawful
835921ce9b lower booki health 2024-06-29 15:12:05 -04:00
scawful
9ade203acc fix goriya boom velocity 2024-06-29 15:05:34 -04:00
scawful
5c59b79acf lower pols voice oam alloc, invert speed when taking damage 2024-06-29 15:02:52 -04:00
scawful
5c98136816 lower goriya health 2024-06-29 15:02:39 -04:00
scawful
998423bac2 cleanup portal rod code 2024-06-29 14:48:36 -04:00
scawful
7db29009d5 fix puffstool crash 2024-06-29 14:32:55 -04:00
scawful
17b73bb62a m bit to OOSPROG for maku tree flag 2024-06-29 10:33:00 -04:00
scawful
02d33991bd hide other map icons based on MAPICON id 2024-06-29 10:32:27 -04:00
scawful
192abc3410 check for maku tree progress flag during intro 2024-06-29 10:30:33 -04:00
scawful
c98351a042 maku tree set progress flag 2024-06-29 10:30:08 -04:00
scawful
4d22280db0 hide pyramid X draw behind MAPICON 3 2024-06-29 10:25:21 -04:00
scawful
50918c11cc move Module05_LoadFile hooks to overworld.asm 2024-06-29 10:12:24 -04:00
scawful
2d4f2b1929 set hall of secrets spawn only after talking to impa 2024-06-29 10:05:40 -04:00
scawful
a24342a75d update anti kirby death 2024-06-28 22:02:42 -04:00
scawful
eb9702fd74 add override for manhandla to die like kholdstare 2024-06-28 22:02:29 -04:00
scawful
c2699f800b remove unnecessary push/pop from LoadOverworldSongsExpanded 2024-06-28 22:01:18 -04:00
scawful
c02a7cac0a dont draw shield for deku or wolf link 2024-06-28 22:00:38 -04:00
scawful
5c4aef2555 add Palettes_GanonTowerFlash to overworld.asm 2024-06-28 21:57:25 -04:00
scawful
55db91756c remove spr frame adjustment from Sprite_BounceFromTileCollision 2024-06-28 20:01:10 -04:00
scawful
5b25e2df2b fix anti kirby full animation offsets 2024-06-28 20:00:56 -04:00
scawful
b431b2d6a6 update sucking, hatted, mirror offset for hat 2024-06-28 19:48:13 -04:00
scawful
5551f165fd add anti kirby hatted actions 2024-06-28 19:33:55 -04:00
scawful
01f9bcb9ce add AntiKirby_Sucking using DragPlayer velocities 2024-06-28 17:09:24 -04:00
scawful
ea9aae9d1a rename sprite_new_functions to sprite_functions 2024-06-28 16:55:15 -04:00
scawful
054d6dee4c fix CheckIfNight logic, now activates between 6pm-6am instead of 0-6am 2024-06-28 16:50:03 -04:00
scawful
45f564b233 add comments to CheckIfNight16Bit for the day/night system 2024-06-28 16:19:20 -04:00
scawful
2cc13d0652 update track floor any obj data 2024-06-28 16:15:29 -04:00
scawful
2773aab772 label SprFrame in BounceFromTileCollision 2024-06-28 16:13:58 -04:00
scawful
0e1e9ca2c1 add $0FEC, $0B89, $0BB0 to sprite_hooks 2024-06-28 16:13:46 -04:00
scawful
a2a04a3535 label sum sprite ram y not 2024-06-28 16:06:52 -04:00
scawful
9f33722173 add damage flash to helmet chuchu, make helmet liftable/tossable 2024-06-28 16:06:42 -04:00
scawful
c17e11e8d8 make sprite invert speed long 2024-06-28 15:16:06 -04:00
scawful
bfbe46861f add interactable helmet chuchu subtypes, wip 2024-06-28 15:15:54 -04:00
scawful
3c09d9b5a1 fix helmet chuchu animation bug where helmet wouldnt appear in frame 0 2024-06-28 15:14:15 -04:00
scawful
de10472f27 give booki a shadow 2024-06-28 15:11:43 -04:00
scawful
0758063162 make goriya pause shortly while tossing boom 2024-06-28 15:11:33 -04:00
scawful
63bef9eb26 invert goriya boom speed on impact or deflection 2024-06-28 15:11:18 -04:00
scawful
804be51ddc update deku scrub enemy prizes to be lower rupee amounts 2024-06-28 14:29:33 -04:00
scawful
9456aca329 make deku scrub enemy liftable and harmless after defeated 2024-06-28 14:29:17 -04:00
scawful
7f818d7734 add PlayerCantPassThrough to mask salesman 2024-06-28 10:49:28 -04:00
scawful
196b8dd0c3 Add DontTeleportWithoutFlippers 2024-06-28 10:46:32 -04:00
scawful
e539d0e764 dismiss bottle anim when changing items 2024-06-28 10:43:04 -04:00
scawful
42d80dba36 dismiss fishing rod from menu when changing items 2024-06-28 10:25:15 -04:00
scawful
c52a30cbf0 add oot great deku tree theme 2024-06-28 00:20:46 -04:00
scawful
32984b8e76 Add RoomTag_MinishShutterDoor 2024-06-28 00:18:57 -04:00
scawful
ede818c57f handle portal sprite dismissal on tile collision 2024-06-28 00:18:14 -04:00
scawful
ee8cc02955 rename HaltLinkWhenUsingItems for fishing rod, move position slightly 2024-06-28 00:17:34 -04:00
scawful
a6fed4353c update darknut ai, damage, movement, collision 2024-06-27 23:46:39 -04:00
scawful
890111b108 use custom Sprite_MoveXyz for puffstool 2024-06-27 20:27:03 -04:00
scawful
a9f0d73ed8 Add Guard_ParrySwordAttacks to gbc darknut 2024-06-27 20:26:51 -04:00
scawful
136d108358 cleanup sprite_new_functions, label sprite ram values 2024-06-27 20:17:27 -04:00
scawful
c3017570bb add SprSlot and SprFreeze to sprite_hooks 2024-06-27 20:17:10 -04:00
scawful
e10d933a79 update darknut draw code 2024-06-27 19:27:19 -04:00
scawful
a68649ff1d Give puffstool randomized movement 2024-06-27 19:27:03 -04:00
scawful
a9b10e5d46 add Sprite_SelectNewDirection based on Buzzblob random movement 2024-06-27 19:26:38 -04:00
scawful
07d7c57d9d Add Sprite_BounceOffWall, Sprite_InvertSpeed_XY 2024-06-27 19:26:23 -04:00
scawful
ce0b6772cc new sprite function lib cleanup 2024-06-27 19:04:02 -04:00
scawful
99cf2085ac update sea urchin draw 2024-06-27 12:49:56 -04:00
scawful
b277654945 fix darknut speed 2024-06-27 12:49:44 -04:00
scawful
bbe0e27212 add eon abyss darknut enemy 2024-06-27 11:33:22 -04:00
scawful
40351fdc2e update deku leaf sprite ID 2024-06-27 11:32:18 -04:00
scawful
e2a2fa3606 inc goriya health, add timer on boom attack to decrease freq 2024-06-27 09:09:00 -04:00
scawful
e326fa83c7 add sparkles to boomerang, dismiss on impact 2024-06-27 09:06:55 -04:00
scawful
c8d9bd1f3a fix goriya left right movement velocity and animation starting frame 2024-06-27 09:06:35 -04:00
scawful
5bf0424913 add goriya boomerang subtype w basic velocity and damage 2024-06-27 08:50:24 -04:00
scawful
037d95c47d goriya redirect movement from tile collision 2024-06-27 08:36:24 -04:00
scawful
ea8e38994f update goriya animation and movement udlr -> 0123 2024-06-27 08:10:39 -04:00
scawful
ccc2dc5454 include goriya, update sprite hooks 2024-06-26 23:44:13 -04:00
scawful
2e1e2e1f24 cleanup pols voice, alloc more oam for shadow 2024-06-26 23:43:16 -04:00
scawful
5f7bb05039 add goriya movement logic 2024-06-26 23:42:58 -04:00
scawful
274c74a8ea cleanup sprite hooks library 2024-06-25 23:12:56 -04:00
scawful
61701360ba add Goriya sprite enemy template with draw data 2024-06-25 20:05:48 -04:00
scawful
d86aab98a9 add tile behavior pit label for cart tracks soon 2024-06-25 19:42:44 -04:00
scawful
5f20b40c2c add expanded music bank override WIP 2024-06-25 19:25:07 -04:00
scawful
a61858c96a Add expanded message IDs with help from Zarby89 2024-06-25 17:22:57 -04:00
scawful
f5978be4a2 add n-spc vcmd documentation to music_macros 2024-06-25 17:22:04 -04:00
scawful
e2e7b82ec4 update oam allocation labels 2024-06-24 11:38:52 -04:00
scawful
b784c45cbb fix sprite draw roller, make link appear above 2024-06-24 11:37:42 -04:00
scawful
20e886a0c3 add wip ww great sea 2024-06-24 09:09:06 -04:00
scawful
d2ff911dde add wip ww ganondorf battle 2024-06-24 09:08:46 -04:00
scawful
bd0aad0f85 update music macros 2024-06-24 09:00:09 -04:00
scawful
1acdb8f09d add song of healing 2024-06-21 22:59:51 -04:00
scawful
bb5a5eb7a3 add Chuchu_SpawnBlast 2024-06-21 22:54:42 -04:00
scawful
74b1a61b18 add chuchu blast draw chr 2024-06-21 22:52:41 -04:00
scawful
21b59501d5 add custom chuchu blast attack 2024-06-21 22:52:24 -04:00
scawful
63561dc97e improve deku hover collision and drag velocity 2024-06-21 20:10:26 -04:00
scawful
25d6905148 add Sprite_FloatAwayFromPlayer 2024-06-21 19:26:14 -04:00
scawful
26a668d147 remove unused sfx from deku mask hover 2024-06-21 19:21:32 -04:00
scawful
b42d045cb0 update manhandla gfx 2024-06-21 19:19:33 -04:00
scawful
391fddd923 add big chuchu phase to manhandla boss 2024-06-21 19:19:24 -04:00
scawful
65c0ad2f70 make Kydreeok MoveBody long for use with Manhandla 2024-06-21 12:59:10 -04:00
scawful
46f3ce1c7a move deku scrub bro out of boss sprite bank 2024-06-21 12:57:30 -04:00
scawful
dec147375a add GetDistance8bit_Long to sprite_new_functions 2024-06-21 12:57:01 -04:00
scawful
a58482a72f get prize for beating deku scrub bro, add shield deflection 2024-06-21 12:56:42 -04:00
scawful
5ff116af19 rearrange all_items into exclusively bank 0x2B 2024-06-21 10:42:08 -04:00
scawful
5c97bd3ffc rename SomariaOrByrna free ram to FishingOrPortalRod 2024-06-21 10:06:08 -04:00
scawful
b9a0dbdf34 add credit to ram map, include music.txt and sfx.txt content for convenience 2024-06-21 10:05:42 -04:00
scawful
f5b6e5e70c Add ShowMessageOnContact to sprite_macros 2024-06-21 10:00:40 -04:00
scawful
fb40e55d65 Add Sprite_ApplySpeedTowardsPlayerXOrY_Long to zsprite lib 2024-06-21 10:00:02 -04:00
scawful
0005130520 fix deku scrub enemy pea shot collision 2024-06-21 09:59:02 -04:00
scawful
d24b4cd17d include manhandla in all_sprites 2024-06-21 00:03:18 -04:00
scawful
589f9225e8 add manhandla body object 2024-06-21 00:02:27 -04:00
scawful
5e197c69e4 add manhandla gfx transfer and bin 2024-06-21 00:02:07 -04:00
scawful
8add7c15a4 add manhandla head and big chuchu AI, draw code 2024-06-21 00:01:47 -04:00
scawful
52e9a8a411 update manhandla prep and properties 2024-06-21 00:00:51 -04:00
scawful
be06598787 update all items cheat to give portal rod, all pendants, lv2 sword 2024-06-19 14:19:19 -04:00
scawful
71e05d7c45 add frame to zora temple overlay, restore camera 2024-06-19 12:26:02 -04:00
scawful
17840716d0 add expanded special areas table, allow for additional entry points 2024-06-19 11:26:18 -04:00
scawful
d338d4bc0a make song of storms trigger zora event, dismiss rain 2024-06-19 11:25:33 -04:00
scawful
adfeb30ed5 add lava lands house entrance tile type 2024-06-19 11:18:14 -04:00
scawful
2c8f59ca69 update global ceiling collision for minish tunnels 2024-06-19 10:56:13 -04:00
scawful
94d3d53999 update mushroom grotto collision for minish tunnels 2024-06-19 10:55:54 -04:00
scawful
3786cb16e4 make puffstool persist offscreen 2024-06-19 10:54:28 -04:00
scawful
175bba4524 add basic collision detection to puffstool 2024-06-19 09:23:07 -04:00
scawful
5c1905f43c add ancillary object IDs to ram.asm 2024-06-18 20:56:11 -04:00
scawful
dbd1d1d6ff cleanup portal rod, remove old ancilla collision attempt 2024-06-18 20:35:55 -04:00
scawful
85ae27a046 add ancillae collision to portal rod sprites 2024-06-18 20:24:56 -04:00
scawful
59bbc4b3ee fix village elder draw 2024-06-18 19:42:33 -04:00
scawful
f8d9acc281 add portal rod as swappable with fishing rod 2024-06-18 18:46:13 -04:00
scawful
b359fb6937 disallow song of storms on maps with overlays, dismiss maps with rain already 2024-06-18 17:48:45 -04:00
scawful
c643fb8a91 remove book activation for zora waterfall overlay event 2024-06-18 17:34:20 -04:00
scawful
c340485a35 move the mermaid splash spawn code 2024-06-18 10:58:59 -04:00
scawful
b637195ffe add link control handler and items to tables reference 2024-06-18 10:58:34 -04:00
scawful
739aa21a51 move entrances to overworld dir 2024-06-18 10:58:19 -04:00
scawful
dcc61db456 add sparkle to minish platforms when standing on 2024-06-17 21:41:26 -04:00
scawful
c6f57b8f3e add mermaid swim logic 2024-06-17 20:45:30 -04:00
scawful
5c6da58146 various housekeeping 2024-06-17 20:03:53 -04:00
scawful
44d37bb327 update village dog lifting gravity 2024-06-17 20:02:43 -04:00
scawful
990fcceaf3 add ranch flower subsprite to bean vendor 2024-06-17 19:49:34 -04:00
scawful
437531c1a0 cleanup mermaid/maple 2024-06-17 19:09:42 -04:00
scawful
cf122b85a4 add wolf mask item icon for link to hold after wolfos fight 2024-06-17 19:09:27 -04:00
scawful
02c34d0229 add maple sprite as subtype to mermaid slot 2024-06-17 18:19:10 -04:00
scawful
2e212baf2a update anti-kirby draw code 2024-06-17 17:51:27 -04:00
scawful
d22fc4f59a add eon abyss mermaid underwater hint sprite 2024-06-17 16:43:38 -04:00
scawful
08b499a889 update ram.asm formatting 2024-06-17 12:03:07 -04:00
scawful
6ae174bf9a add tables.asm for reference 2024-06-17 12:02:48 -04:00
scawful
afcf00fd85 add stone tower temple v2 2024-06-17 11:53:53 -04:00
scawful
9d7f837bad update includes for sprites 2024-06-17 11:51:58 -04:00
scawful
202d5c6037 rename old_man to followers, handle all followers 2024-06-17 11:51:15 -04:00
scawful
c35754d8a6 cleanup octoboss 2024-06-17 11:47:39 -04:00
scawful
570fa2a211 fix inside tree sprite settings 2024-06-17 11:44:11 -04:00
scawful
249f00d0d9 add crumbling floor room tag puzzle 2024-06-17 00:58:02 -04:00
scawful
cdbb6ff8ae include puffstool in all_sprites 2024-06-17 00:55:44 -04:00
scawful
afe78e55f6 refactor deku scrub enemy 2024-06-17 00:43:35 -04:00
scawful
95a6ee24cd add ThrownSprite_TileAndSpriteInteraction to puffstool, use gravity timer 2024-06-17 00:39:36 -04:00
scawful
3319e775c1 Add shutter door which requires link to be in a minecart to open 2024-06-17 00:21:12 -04:00
scawful
e3428ff808 dont change to gbc form if minish in dungeons 2024-06-16 22:09:36 -04:00
scawful
96c3486072 lower puffstool health 2024-06-16 22:09:01 -04:00
scawful
ac074fa5f7 update anti kirby draw data and ai logic 2024-06-16 22:08:37 -04:00
scawful
202eb058f3 cleanup sprite hooks and add new long labels 2024-06-16 21:14:12 -04:00
scawful
7b7ffa294c update puffstool ai, add damage flash to draw code 2024-06-16 21:02:14 -04:00
scawful
12dc64ba3f add puffstool ai states, optimize draw code 2024-06-16 19:52:41 -04:00
scawful
aea4470095 add puffstool enemy code skeleton 2024-06-16 19:47:12 -04:00
scawful
cafe477833 random cart stuff 2024-06-16 17:42:50 -04:00
scawful
376b4e7e79 update minecart directional logic 2024-06-16 17:41:47 -04:00
scawful
c103739041 add directional labels to minecart 2024-06-16 17:41:32 -04:00
scawful
cdf329119c update minecart switch sprite 2024-06-16 11:05:17 -04:00
scawful
64a2036ad2 add any direction track over pits in unused custom object slot 2024-06-16 11:04:54 -04:00
scawful
e13575f593 update track object gfx bins 2024-06-16 11:04:14 -04:00
scawful
2af931ece5 update global minish pot collision 2024-06-16 11:03:47 -04:00
scawful
1f335fd0fb update goron mines collision for tracks 2024-06-16 11:03:37 -04:00
scawful
2beb6e1846 add minish tiles to underworld 2024-06-16 11:03:24 -04:00
scawful
02aa9844da rearrange boots and flippers in menu 2024-06-16 08:40:21 -04:00
scawful
62c9c188e2 update tunic icon menu 2024-06-16 08:40:13 -04:00
scawful
b72053ce83 add wip credits.txt 2024-06-16 08:29:49 -04:00
scawful
20b572214c update pendant and music note icons 2024-06-16 08:29:34 -04:00
scawful
87d508bdbb remove old follower code 2024-06-15 15:44:01 -04:00
scawful
ef05b2160b make deku scrub pea blockable by shield 2024-06-15 15:43:43 -04:00
scawful
27d267f93e update helmet chuchu health 2024-06-15 15:43:32 -04:00
scawful
102ec125a1 fix wolfos dialogue 2024-06-15 15:43:11 -04:00
scawful
0bc9e2e8ed include new dungeon walls with pillars 2024-06-15 13:59:55 -04:00
scawful
059f9e8068 dont change sprites based on time during intro 2024-06-15 00:46:29 -04:00
scawful
0d21e18a54 add lost woods v2 2024-06-15 00:30:57 -04:00
scawful
3b1b70b2a1 clear bottle the bean came from when releasing it 2024-06-15 00:29:45 -04:00
scawful
94e1c57218 add annoying dialogue restart to KB :) 2024-06-14 23:50:36 -04:00
scawful
a1c4cc0b05 add TailPalace_EntranceAnimation to slot 03 2024-06-14 23:40:56 -04:00
scawful
f368a1daf8 allow bean to be pulled out at the ranch 2024-06-14 23:40:45 -04:00
scawful
09b795478b add thunder ghost lightning attack 2024-06-14 23:26:41 -04:00
scawful
8e10ae4c15 update booki behavior, hide from player 2024-06-14 22:41:54 -04:00
scawful
f9aacc7bf8 helmet chuchu housekeeping 2024-06-14 22:25:58 -04:00
scawful
1b42d1f42b dismiss KB if player has song of soaring already 2024-06-14 22:20:15 -04:00
scawful
f8bfadca9b add kaepora gaebora gives song of soaring after 6 crystals at hall of secrets 2024-06-14 22:12:58 -04:00
scawful
813b91a1a9 add prize pack to sea urchin 2024-06-14 21:48:36 -04:00
scawful
1325330e1f Make Kydreeok head recoil Link 2024-06-14 21:46:52 -04:00
scawful
95190dda3c update thunder ghost movement AI 2024-06-14 21:43:36 -04:00
scawful
5b31ae3b29 manage sprite death, make helmet chuchu recoil link on attack 2024-06-14 21:43:27 -04:00
scawful
f6bc9a812b update booki movement 2024-06-14 21:11:54 -04:00
scawful
c5379a39d9 Make Dark Link scream die like sidenexx 2024-06-14 21:11:44 -04:00
scawful
b0fa338e87 make kydreeok head die like a sidenexx 2024-06-14 21:04:38 -04:00
scawful
d70b1f6cca optimize draw code, swap horiz prop based on direction of player 2024-06-14 20:13:10 -04:00
scawful
5115f1a01d include booki and thunder ghost in game 2024-06-14 19:46:29 -04:00
scawful
26f7b28ae3 update helmet chuchu speed 2024-06-14 19:23:35 -04:00
scawful
652dc84eff update follower camera triggers 2024-06-14 19:15:13 -04:00
scawful
c811e57361 add SprBulletproof 2024-06-14 19:14:51 -04:00
scawful
0afd8e570a add kiki overridesfor tail palace 2024-06-14 19:14:44 -04:00
scawful
47a43c9cdd add Follower_Disable override 2024-06-14 18:47:12 -04:00
scawful
2219aff335 update helmet chuchu movement 2024-06-14 18:46:33 -04:00
scawful
85f8d334f4 add local jump table for helmet chuchu 2024-06-14 18:09:30 -04:00
scawful
110e9a1753 update dialogue IDs 2024-06-14 18:09:18 -04:00
scawful
6dcfe1bcda Add TailPalace_EntranceAnimation 2024-06-14 16:31:18 -04:00
scawful
1392d8d883 include new ram symbols 2024-06-14 15:16:47 -04:00
scawful
37bd734ad8 combine wram, sram and registers into ram.asm 2024-06-14 15:16:13 -04:00
scawful
22a980b0a3 update sprite hooks 2024-06-14 15:15:41 -04:00
scawful
27761a6dac label sprite ram in anti_kirby 2024-06-14 15:15:29 -04:00
scawful
555f5383a4 add magic bean bottle to menu and hud 2024-06-14 11:04:22 -04:00
scawful
c23f638956 village dog talks to minish and wolf link 2024-06-14 02:25:27 -04:00
scawful
dff78e01de fix wolf mask grant item bug 2024-06-14 02:15:08 -04:00
scawful
0ef2e07925 fix 0:00 time sprite bug 2024-06-14 02:14:59 -04:00
scawful
c789a413fc add pyramid map marker 2024-06-14 01:24:46 -04:00
scawful
886599aa0d update village elder dialogue and map marker 2024-06-14 01:21:26 -04:00
scawful
a1362d05fa add hall of secrets map marker from maku tree 2024-06-14 01:05:33 -04:00
scawful
bc9654d556 fix cheat check bug 2024-06-14 00:37:23 -04:00
scawful
2d443f4302 add deku butler and deku princess dialogue 2024-06-14 00:02:11 -04:00
scawful
3ee83ccfe6 add magic bean bottle logic with todo to finish storage and release 2024-06-14 00:02:02 -04:00
scawful
52eb8abb92 update magic bean sprite 2024-06-13 22:27:15 -04:00
scawful
606a7221fa update bean vendor 2024-06-13 22:21:13 -04:00
scawful
ec05fac8ee subtract rupees when buying magic bean 2024-06-13 22:08:19 -04:00
scawful
12acfb15fe add SprDefl $0CAA to sprite_hooks 2024-06-13 21:59:33 -04:00
scawful
7915583c8c update village elder subsprite 2024-06-13 21:59:18 -04:00
scawful
64e589d215 add kaeopora gaebora as separate subtype to bean vendor NPC 2024-06-13 21:34:47 -04:00
scawful
bce7a88458 add movement to darknut enemy 2024-06-13 21:29:45 -04:00
scawful
2e2143d8bf only allow debug in main game, require L+R+X 2024-06-13 21:20:59 -04:00
scawful
450c84ecfb include bean vendor and helmet chuchu 2024-06-13 21:11:27 -04:00
scawful
4752e4cba4 add booki ghost enemy template code 2024-06-13 21:11:14 -04:00
scawful
1aa5b2a732 optimize helmet chuchu draw code 2024-06-13 21:10:56 -04:00
scawful
39ecedf63f add bean vendor / village elder sprite logic 2024-06-13 20:56:01 -04:00
scawful
3533df3d38 add helmet chuchu subtypes, basic hopping movement 2024-06-13 20:36:33 -04:00
scawful
5e97ef3c42 add deku butler and deku princess subtypes 2024-06-13 12:00:31 -04:00
scawful
74306f80cd add thunder ghost code skeleton and draw data 2024-06-13 11:05:57 -04:00
scawful
d64314d38e add bean vendor npc code skeleton and draw data 2024-06-13 11:03:59 -04:00
scawful
f655e1d800 add eon abyss darknut code skeleton and draw data 2024-06-13 11:03:14 -04:00
scawful
d25b58650f add helmet chuchu enemy code skeleton and draw data 2024-06-13 11:02:19 -04:00
scawful
5fa44e73cb add withered deku, deku butler, and deku princess to deku scrub npc 2024-06-13 11:00:44 -04:00
scawful
29f3bd0b11 add pit entrances to new ow map ids 2024-06-12 19:17:34 -04:00
scawful
c4ddb42d8c allow wolf link to dig up random prizes anywhere 2024-06-11 23:54:05 -04:00
scawful
d262a0a2f2 remove finished todo 2024-06-11 23:25:40 -04:00
scawful
8ee3504629 fix bug where impa kills the music 2024-06-11 23:23:06 -04:00
scawful
6697f55908 allow two way mirror with all pendants 2024-06-11 23:21:25 -04:00
scawful
751818f61e update kydrog cutscene 2024-06-11 22:48:30 -04:00
scawful
080cc3c28c update kydreeok gfx 2024-06-11 22:15:14 -04:00
scawful
2ab3535775 restore BG2 after kydreeok fight 2024-06-11 22:14:55 -04:00
scawful
c9e3a8bc0f remove bad reference to song in dungeon bank from overworld cutscene, likely cause of snes9x core crashes 2024-06-11 22:14:38 -04:00
scawful
83f599d50a dont draw shield as minish link 2024-06-11 10:15:28 -04:00
scawful
74c9143baa fix silver bow menu/hud bug 2024-06-11 09:45:01 -04:00
scawful
31c1335da1 update old man trigger room for dialogue 2024-06-11 01:12:07 -04:00
scawful
04578628c7 add attract_scenes to dungeons 2024-06-11 01:11:28 -04:00
scawful
a4fb1b4203 update screen char data 2024-06-11 01:11:18 -04:00
scawful
a076ee3657 add attract_scenes for title cutscene 2024-06-10 20:11:43 -04:00
scawful
4233ae7f49 add registers.asm 2024-06-10 20:11:31 -04:00
scawful
6b6b3103c8 change cutscene kydrog to blue palette 2024-06-10 17:05:33 -04:00
scawful
b14bfe1e94 increase damage class of stalfos offspring in kydrog fight 2024-06-10 17:04:53 -04:00
scawful
c2c252b59b change kydrog boss to blue palette 2024-06-10 17:04:32 -04:00
scawful
56d45d5a74 add flying state to kydreeok body sprite 2024-06-10 14:52:18 -04:00
scawful
42f58837aa update kydreeok neck draw 2024-06-10 14:52:01 -04:00
scawful
95c147809d update gfx 2024-06-10 13:26:21 -04:00
scawful
66b21e9394 kydreeok head cleanup 2024-06-10 13:26:12 -04:00
scawful
61aa373ba8 add chance of respawning head if the other isnt killed soon after 2024-06-10 13:25:57 -04:00
scawful
fd01d53da7 optimize kydreeok draw code slightly 2024-06-10 11:32:54 -04:00
scawful
8dae6494b7 remove third head code for now 2024-06-10 11:32:41 -04:00
scawful
53572d6232 prevent impa from despawning in the hall of secrets 2024-06-10 10:34:33 -04:00
scawful
b4c2f575ad update dark link gfx 2024-06-10 09:43:39 -04:00
scawful
6251d770be add far left and far right head anims to kydreeok head 2024-06-10 09:43:27 -04:00
scawful
30cf49cd3a update kydreeok gfx 2024-06-10 09:42:03 -04:00
scawful
077cd929d0 handle kydreeok boss death, restore stairs palette 2024-06-10 09:41:54 -04:00
scawful
1a70609c3e update kydreeok phase2 gfx 2024-06-10 00:59:55 -04:00
scawful
9edd5624a5 update kydreeok head 2024-06-10 00:57:31 -04:00
scawful
01e8678588 update kydreeok gfx 2024-06-10 00:57:03 -04:00
scawful
cec96536fb add kydreeok left head anim and handle death 2024-06-10 00:56:57 -04:00
scawful
097adf16e7 update dark link boss 2024-06-10 00:56:27 -04:00
scawful
e646153907 add phase 2 kydreeok gfx when health is low 2024-06-09 21:53:24 -04:00
scawful
62d045b82e update kydreeok phase 1 gfx and add phase 2 2024-06-09 21:53:01 -04:00
scawful
92c627b149 only allow bunny hood speed when mask is active 2024-06-09 21:52:41 -04:00
scawful
e3478ddf13 update ow banks 2024-06-09 20:47:42 -04:00
scawful
e68b755159 update deku hover camera and drag ram 2024-06-09 20:47:31 -04:00
scawful
9e5cd0b5ac rearrange sprite banks and ow banks 2024-06-09 20:47:14 -04:00
scawful
ca4b2d572c add Core/player.asm for reference 2024-06-09 16:14:37 -04:00
scawful
bb03dfffdc all_sprites cleanup 2024-06-09 16:14:22 -04:00
scawful
773e295188 refactor all masks fns 2024-06-09 16:14:12 -04:00
scawful
11382f070c update deku hover 2024-06-09 16:14:00 -04:00
scawful
d96f88cf5c update dark link gfx and fight 2024-06-09 16:13:50 -04:00
scawful
3a2d529dca cleanup dungeons.asm 2024-06-09 11:35:54 -04:00
scawful
5c175ff255 update mask routines, deku hover, init camera 2024-06-09 11:35:42 -04:00
scawful
eb3b8bf7ef override Overworld_FindEntrance for future use 2024-06-09 11:35:22 -04:00
scawful
10a17debc0 remove sanctuary_transition.asm 2024-06-09 11:35:01 -04:00
scawful
a9b1b4772a Add SprState explanations to sprite_hooks.asm 2024-06-09 10:21:53 -04:00
scawful
b3e9130f66 fix jump feather spike dungeon bug 2024-06-09 10:21:36 -04:00
scawful
60e13874c5 update wolfos mini boss 2024-06-08 12:08:18 -04:00
scawful
f7483d4f6a fix reset mask bug 2024-06-08 11:53:08 -04:00
scawful
787c88f252 fix zora mask resurface bug hopefully finally 2024-06-08 11:43:14 -04:00
scawful
c7de0d9e96 add updated fortune teller logic 2024-06-08 10:47:40 -04:00
scawful
ee9a118405 add multiple pit areas which lead to entrances, graveyard and lava lands 2024-06-08 09:28:24 -04:00
scawful
774faf345c update deku mask transform logic 2024-06-08 08:53:45 -04:00
scawful
abb26b4e11 remove bad deku flower check code 2024-06-08 08:53:26 -04:00
scawful
27a14ccaf9 move LinkState_ResetMaskAnimated, update logic 2024-06-08 08:53:13 -04:00
scawful
8cc0442cdd update kydreeok formatting 2024-06-07 23:16:51 -04:00
scawful
9a6917304f update Sprite_KydrogBoss_CheckIfDead 2024-06-07 23:12:53 -04:00
scawful
1c08111c59 update Sprite_Wolfos_CheckIfDefeated 2024-06-07 23:12:42 -04:00
scawful
50983b44c5 Add RestoreFloorTile to TwinrovaBoss 2024-06-07 23:12:29 -04:00
scawful
bdaca1757f fix typo 2024-06-07 22:50:31 -04:00
scawful
7cbc26dcbe update menu item refresh 2024-06-07 22:34:18 -04:00
scawful
d288b739a6 add SprDmg label 2024-06-07 22:31:27 -04:00
scawful
1f5d72ac1f cleanup mask routines 2024-06-07 22:31:19 -04:00
scawful
a80ee5bebb rename all_items to item_cheat 2024-06-07 21:27:28 -04:00
scawful
2ec907d0f6 update goldstar 2024-06-07 21:23:42 -04:00
scawful
9d932373c8 Add offspring 3 neck control and formatting to kydreeok 2024-06-07 18:10:58 -04:00
scawful
acb3000fbc update kydreeok head formatting 2024-06-07 18:10:37 -04:00
scawful
7c047621a0 adjust kydreeok movement boundaries 2024-06-07 17:24:57 -04:00
scawful
d1ba08edb5 prevent gbc form from resetting minish form 2024-06-07 17:19:26 -04:00
scawful
e7c43fdff1 add Neck3_OffsetX/Y 2024-06-07 00:55:55 -04:00
scawful
348a9ee80c add third neck and head draw control to kydreeok head 2024-06-07 00:55:31 -04:00
scawful
1c73035a74 kydreeok replace spr ram w labels 2024-06-07 00:55:09 -04:00
scawful
4622b45724 add letterbomb color dungeon theme 2024-06-07 00:43:07 -04:00
scawful
1b55482ba8 use SprBump define for kydrog boss and minecart 2024-06-06 22:49:16 -04:00
scawful
4448677987 set kydreeok head health to 0x80 and bump damage to 9 2024-06-06 22:48:58 -04:00
scawful
15fb683cc3 add SprBump to sprite_hooks 2024-06-06 22:48:36 -04:00
scawful
cacef8df49 rearrange sprite banks 2024-06-06 22:43:11 -04:00
scawful
1265116ec6 add Kydreeok center head 2024-06-06 22:42:36 -04:00
scawful
d0a1a57e37 update kydreeok gfx bin 2024-06-06 22:12:34 -04:00
scawful
4530174bd9 Add kydreeok.bin gfx with multi phase body 2024-06-06 22:03:24 -04:00
scawful
af7bd19c79 Add ApplyKydreeokGraphics 2024-06-06 22:03:03 -04:00
scawful
d1af80fb52 update jump feather spike damage handling 2024-06-06 21:49:15 -04:00
scawful
8816d394b9 Add Link_HandleAPress to LinkState_Bunny 2024-06-06 21:47:00 -04:00
scawful
8d2edbe964 add korok to all_sprites 2024-06-06 21:45:45 -04:00
scawful
70273ef3b2 overwrite sprite $B1 for korok 2024-06-06 21:44:53 -04:00
scawful
2b7cbc1f91 korok draw based on subtype 2024-06-06 21:44:39 -04:00
scawful
2c083cdf90 update korok draw routines 2024-06-06 21:44:25 -04:00
scawful
7ce008b08b dont spawn wolfos if flag set 2024-06-06 21:37:35 -04:00
scawful
8ce20d53a3 update wolfos grant mask sequence 2024-06-06 21:35:33 -04:00
scawful
2483619407 Add Wolfos_Subdued and Wolfos_GrantMask 2024-06-06 21:28:58 -04:00
scawful
0d202a1142 Add Sprite_Wolfos_CheckIfDefeated 2024-06-06 21:27:38 -04:00
scawful
748c6d65fb add TODO for triggering fortress of secrets cutscene 2024-06-06 21:23:06 -04:00
scawful
34d5b704ce more DarkLink formatting 2024-06-06 21:22:30 -04:00
scawful
38bb68ee72 cleanup DarkLink 2024-06-06 21:03:12 -04:00
scawful
aa6a39a7da add ApplyDarkLinkGraphics function 2024-06-06 21:03:06 -04:00
scawful
4bcf4fcab2 add dark_link.bin gfx 2024-06-06 20:57:53 -04:00
scawful
b453b88ce2 add CRYSTALS define 2024-06-06 20:47:58 -04:00
scawful
36cc549e6e add PROGLITE and SPAWNPT define 2024-06-06 20:46:33 -04:00
scawful
67920c2753 set SprTimerA after deciding minecart direction 2024-06-06 20:44:34 -04:00
scawful
c20cab23d1 add vert/horiz tile check to minecart 2024-06-06 20:44:01 -04:00
scawful
c83eaf0446 cleanup goldstar 2024-06-06 20:42:52 -04:00
scawful
bd78b17573 update dark link spawn ID 2024-06-06 10:37:25 -04:00
scawful
8a0ffc014d add DarkLink boss in place of CutsceneAgahnim 2024-06-06 10:25:25 -04:00
scawful
b19c05f48c make KydrogBoss reset his stalfos offspring when absconding after too many consecutive strikes 2024-06-06 10:04:53 -04:00
scawful
e5ec12fd31 add Sprite_CheckIfFrozen to KydrogBoss 2024-06-06 09:58:58 -04:00
scawful
1c6d7153fd increase kydrog boss health and damage class 2024-06-06 09:51:39 -04:00
scawful
b837163f99 fix minish form removing shield bug 2024-06-06 09:48:57 -04:00
scawful
a8f864bc19 update king dodongo phase table 2024-06-06 09:47:19 -04:00
scawful
b33231d3da update bunny hood speed value annotations 2024-06-06 09:46:14 -04:00
scawful
62946af5f0 decrease goldstar damage class 2024-06-06 09:44:21 -04:00
scawful
f0805eac00 increase twinrova stun timer 2024-06-05 18:15:22 -04:00
scawful
8e005f5430 king dodongo increase change of spitting fireballs 2024-06-05 18:03:29 -04:00
scawful
5769b1e820 increase king dodongo speed values 2024-06-05 18:01:42 -04:00
scawful
ddf272be34 fix king dodongo hammer crash, increase phase table size 2024-06-05 17:57:15 -04:00
scawful
8902cb927b add switch track subtype 2 position adjustment 2024-06-05 17:31:21 -04:00
scawful
8b667cbffe add todo for overworld map icons palette day/night 2024-06-05 17:30:23 -04:00
scawful
ac4484dbd4 fix king dodongo helmet fireball bug 2024-06-05 17:28:50 -04:00
scawful
bc6fcf1741 shock palette preserve A register 2024-06-05 11:25:32 -04:00
scawful
7b6f0c8a45 add gbc link red mail, fix palette bugs 2024-06-05 11:25:01 -04:00
scawful
2d6808c0ca only fix shock palette outside 2024-06-05 11:19:49 -04:00
scawful
2e05e32442 maku tree gives link heart container instead of moon pearl 2024-06-05 11:11:53 -04:00
scawful
cdb748f413 fix goldstar damage class applying to other items 2024-06-04 22:11:49 -04:00
scawful
5f550c330b update dw intro check 2024-05-30 15:28:59 -04:00
scawful
b36ac1e162 add list of entrances 2024-05-30 15:24:44 -04:00
scawful
4c347ac060 have cutscene kydrog play music 2024-05-30 15:23:22 -04:00
scawful
a8c3c783e6 SpriteSetupHitbox and LinkSetupHitbox long, disable deku mask hover (for now) 2024-05-30 15:06:56 -04:00
scawful
736b8c1cdc add pushpc in bank 33 collision tables file 2024-05-30 14:29:21 -04:00
scawful
f80b161eb9 update dark world intro load conditions 2024-05-30 14:28:46 -04:00
scawful
3fa67907e3 add pendant from chest position adjustment 2024-05-30 14:26:28 -04:00
scawful
27c97c6d8f add todos for deku mask movement 2024-05-30 14:24:25 -04:00
scawful
917b71bd7f move gbc link dw update code 2024-05-30 00:23:59 -04:00
scawful
dc29ce3fae fix minish form bug while normal link 2024-05-30 00:23:43 -04:00
scawful
b9f66d21b0 add overlays include 2024-05-29 23:46:47 -04:00
scawful
e3662d7863 add warnpc to stone tower temple 2024-05-29 23:46:32 -04:00
scawful
6664dc52ca change ow pit transport map loc 2024-05-29 23:46:17 -04:00
scawful
de2ea7116e add dark world intro spawn config 2024-05-29 23:38:35 -04:00
scawful
3b39e0d9c7 allow gbc form link to minish transform on tile 2024-05-29 23:37:59 -04:00
scawful
718faad081 fix minish form tile bug 2024-05-29 23:35:44 -04:00
scawful
19d6907380 update lv4 sword dialogue ID 2024-05-29 11:41:58 -04:00
scawful
8019c55c76 update wolfos movement ai 2024-05-29 11:41:44 -04:00
scawful
0e64fee271 update ow pit damage todo 2024-05-29 09:53:27 -04:00
scawful
581c8bd39a cleanup world map module 2024-05-29 09:16:23 -04:00
scawful
f728e8d346 update interior dungeon menu names 2024-05-29 08:41:29 -04:00
scawful
9c058dc923 update main 2024-05-29 08:41:12 -04:00
scawful
df97557437 update floor puzzle formatting 2024-05-29 08:37:10 -04:00
scawful
99cdb909ad add stone tower temple theme 2024-05-29 00:10:02 -04:00
scawful
6ed91dfa20 silence the indoor ambient rain sound 2024-05-28 21:11:50 -04:00
scawful
a2994e350c add list of instruments to music macros 2024-05-28 21:11:20 -04:00
scawful
c8ca8031ce update cutscene kydrog 2024-05-28 21:10:54 -04:00
scawful
d0253bd325 fix gbc form mirror warp palette bug 2024-05-28 09:46:50 -04:00
scawful
6b396a8290 update old man trigger map and cammera location 2024-05-28 09:43:07 -04:00
scawful
2f2bb41ee4 update old man sprite to not spawn in cave if you have him following you 2024-05-28 08:57:47 -04:00
scawful
c6cbb8f7af Add temporary palette and form fix for gbc dw link 2024-05-28 08:09:16 -04:00
scawful
acd4730bcc fix zora mask resurface bug when entering dungeons from ow after diving 2024-05-28 08:00:35 -04:00
scawful
15b502ed54 update Palette_ArmorAndGloves for Zora palette 2024-05-28 07:55:56 -04:00
scawful
d31aef97cd update main dungeon map markers 2024-05-28 07:50:02 -04:00
scawful
f46f840594 update world map crystal icons 2024-05-28 07:27:01 -04:00
scawful
cf2be70f1a remove moon pearl requirement for gbc form 2024-05-27 22:55:13 -04:00
scawful
81d579a78b set the link form id for gbc link 2024-05-27 22:54:52 -04:00
scawful
9b62e05f08 update wolfos AI movement 2024-05-27 22:34:50 -04:00
scawful
27ae1796ad Remove rain sound effects from beginning 2024-05-27 22:34:36 -04:00
scawful
09a6e277cd change spawn point 03 room and song 2024-05-27 20:57:44 -04:00
scawful
922190d48c remove ganon tower flash palette from lava lands 2024-05-27 20:57:25 -04:00
scawful
0f83c25932 replace Player_DoSfx2 in %PlayerTransform() 2024-05-27 20:56:34 -04:00
scawful
b29302c2cc add gbc form palette to Palette_ArmorAndGloves 2024-05-27 20:56:16 -04:00
scawful
eb183ef71c fix gbc bunny palette bug in intro 2024-05-27 20:55:47 -04:00
scawful
3d62fc3449 update village dog sprite 2024-05-27 19:52:46 -04:00
scawful
5715271b60 Update wolfos sprite movement behavior, add damage flash 2024-05-27 19:49:13 -04:00
scawful
c8b92c0e8b update wolfos mini boss code 2024-05-27 17:20:59 -04:00
scawful
6ca22d195b update object handler, remove custom draw config, add todos 2024-05-27 17:17:34 -04:00
scawful
8837ef875e update deku link gfx bin 2024-05-27 17:12:45 -04:00
scawful
c20ce18cf2 move maku tree and make salesman sprite to bank 30 2024-05-27 17:11:05 -04:00
scawful
026d8c593f update village dog behavior, make liftable 2024-05-27 17:10:13 -04:00
scawful
a5d964271c Prevent Impa from changing the song 2024-05-26 09:45:08 -04:00
scawful
3ecfc3367d Prevent Impa from setting spawn point 2024-05-26 09:40:58 -04:00
scawful
823a76f151 Change overlay that Impa activates after DW dialogue 2024-05-26 09:40:06 -04:00
scawful
290dee574b check for goldstar instead of mirror for mountain spawn point option 2024-05-26 09:38:00 -04:00
scawful
dd032d0639 Prevent mantle from setting spawn point 7ef3c8 2024-05-26 09:25:48 -04:00
scawful
c0f56b1565 remove rain from intro house tag 2024-05-26 09:13:22 -04:00
scawful
32d0b2839c fix syntax error in overlays 2024-05-26 09:12:21 -04:00
scawful
0d86b560ad reload sprite gfx props on hour inc for day/night spriteset change 2024-05-26 08:45:50 -04:00
scawful
b6797a8d4e fix impa telepathic dialogue opening castle bridge overlay 2024-05-26 08:44:50 -04:00
scawful
e11c003ba6 Add wolfos sprite skeleton 2024-05-26 08:16:36 -04:00
scawful
5b0a02cd97 fix dynamic track logic and clamp position on redirection 2024-05-24 20:42:28 -04:00
scawful
ecd99b22c3 set minecart sprite direction on prep 2024-05-24 20:41:55 -04:00
scawful
236b763769 add old man sprite hooks 2024-05-24 20:41:39 -04:00
scawful
3eff3fde72 add various minor sprite hooks 2024-05-24 20:41:27 -04:00
scawful
12924d65cb move farore and kydrog sprite 2024-05-24 20:41:17 -04:00
scawful
410f2ccaef update goron mines collision set 2024-05-24 09:28:07 -04:00
scawful
8b7d9352f8 update book overlay anim activation checks 2024-05-24 09:22:18 -04:00
scawful
1493130d6d cleanup overlay animation code 2024-05-24 09:22:04 -04:00
scawful
daeb2b4061 Add castle draw bridge overlay anim 2024-05-24 09:21:45 -04:00
scawful
81fbb1599f update switch track sprite 2024-05-24 09:21:24 -04:00
scawful
88d723241e change lanmola boss palette 2024-05-24 08:42:10 -04:00
scawful
86d237d77a change switch track hitbox 2024-05-22 22:57:50 -04:00
scawful
b5d7d2740c change mineswitch hitbox 2024-05-22 22:57:14 -04:00
scawful
3880cd5648 clamp pos to grid on direction change tile type 2024-05-22 22:56:51 -04:00
scawful
7b68c27570 adjust cart follower position based on direction when spawning sprite 2024-05-22 20:18:55 -04:00
scawful
9a79237251 remove ClampSpritePositionToGrid 2024-05-22 20:18:34 -04:00
scawful
45ac08bd3c update minecart direction values in movement tile section 2024-05-22 20:18:17 -04:00
scawful
f92f2d2b2e release the player if the cart disconnects from them 2024-05-22 20:17:32 -04:00
scawful
9bbb49b83f update cart release wait state based on direction 2024-05-22 20:16:50 -04:00
scawful
5f4e6b6908 Remove bounce from tile collision from movement fns 2024-05-22 20:16:30 -04:00
scawful
5a13d69569 clamp toss landing to 16x16 grid 2024-05-22 20:16:05 -04:00
scawful
845e285a33 change subtype on cart based on toss direction 2024-05-22 20:15:45 -04:00
scawful
50a99fcdc3 Remove debug hitbox draw 2024-05-20 17:57:11 -04:00
scawful
269702a41d Set cart follower during Interroom Transition 2024-05-20 17:57:02 -04:00
scawful
f30c7d9ea4 Spawn minecart sprite from follower in the correct movement state 2024-05-20 17:56:31 -04:00
scawful
58e0e9f7cc Swap minecart x and y offset work ram variables for draw 2024-05-20 17:56:03 -04:00
scawful
bdcb7d638b Remove unused lookup tile routine 2024-05-20 17:55:40 -04:00
scawful
32cb18e20c Add auto-move flag to WaitHoriz and WaitVert 2024-05-20 17:55:16 -04:00
scawful
156322bebc Remove dummy carts, setup auto-move flag 2024-05-20 17:55:00 -04:00
scawful
1ee0878313 Update DrawMinecartFollower 2024-05-20 15:01:31 -04:00
scawful
e9ffc8ad04 Minecart_Follower skeleton code, wip oam draw routine 2024-05-20 11:54:36 -04:00
scawful
ea935506d8 update minecart hitbox 2024-05-19 23:34:55 -04:00
scawful
2ce94f90c6 Update cart tossing gravity 2024-05-19 23:34:36 -04:00
scawful
465bea502d Update cart tile directions function 2024-05-19 23:34:23 -04:00
scawful
6d12a4356b Remove recoil eject from cart 2024-05-19 23:34:08 -04:00
scawful
df96ae9c5a add zora temple waterfall animation overlay 2024-05-19 17:17:21 -04:00
scawful
fd1e8a097e Fix minecart tossing bug and increase distance tossed 2024-05-19 17:16:54 -04:00
scawful
8f30f03f75 cart track tile types collision from pit to nothing 2024-05-18 20:02:29 -04:00
scawful
26397a191d Add dialogue to twinrova, set bombable floor room for maiden intro 2024-05-18 18:32:17 -04:00
scawful
da8e238a50 Make goldstar do big damage instead of stun 2024-05-17 22:50:50 -04:00
scawful
1869ea99c3 Add CheckForSomariaBlock name to goldstar 2024-05-17 22:50:34 -04:00
scawful
085ee2c16e add special area overrides for gfx, sprites, palettes 2024-05-17 21:55:15 -04:00
scawful
835341c309 add cant pass through to deku scrub enemy 2024-05-17 21:54:00 -04:00
scawful
a2e82ad82e fix hud item update code 2024-05-17 21:53:19 -04:00
scawful
fbcab3d875 draw current time to quest status menu 2024-05-17 18:20:16 -04:00
scawful
42b959ebe5 Add CheckIfFrozen with todo for timer 2024-05-16 09:49:46 -04:00
scawful
89ccd5ba2e Update KydrogBoss to be frozen by ice rod 2024-05-16 09:49:08 -04:00
scawful
cc9a517844 Fix KydrogBoss phase transition health refill bug 2024-05-16 09:46:53 -04:00
scawful
a345bbb4ff Add Manhandla sprite with head char data 2024-05-16 00:19:41 -04:00
scawful
118571cdc4 Add Sprite_FloatTowardPlayer 2024-05-16 00:19:09 -04:00
scawful
f6d0e037bd housekeeping for m'lady 2024-05-16 00:17:48 -04:00
scawful
d042a50872 Add variable speed to fire/ice attacks 2024-05-16 00:17:01 -04:00
scawful
2f7c88bcbb update RageModeMove with strafing, target position launch, dodging 2024-05-16 00:16:45 -04:00
scawful
4dd39bc38e Add strafing, update attacks, retaliation on hurt state 2024-05-16 00:16:07 -04:00
scawful
72585962ba add lightning to twinrova bin 2024-05-16 00:13:11 -04:00
scawful
e01ed60dce update deku scrub enemy hitbox detection and state management 2024-05-12 19:43:00 -04:00
scawful
5d0a79191a Update Anti-Kirby based on Pikit steal 2024-05-12 19:25:50 -04:00
scawful
aa3da8e8ad cleanup deku mask and bunny hood code 2024-05-12 12:39:26 -04:00
scawful
f98a83559a Add DragPlayer for Minecart and DekuHover, uses Y index as parameter for drag direction 2024-05-12 10:43:46 -04:00
scawful
8f9bc12e3c fix gbc link death respawn dark world 2024-05-12 10:23:41 -04:00
scawful
7f7650b5a1 Apply Kydreeok palette during prep, set Ganon fight song 2024-05-12 08:33:22 -04:00
scawful
c7e4bee65b Move portal sprite to objects, update sprite ID, move other NPC sprites 2024-05-12 08:32:02 -04:00
scawful
90eb4279e8 update deku leaf sprite override 2024-05-10 22:02:51 -04:00
scawful
4d23b0bed6 Add SpriteBodyObjects for ID 0x54 2024-05-10 22:02:02 -04:00
scawful
7653e9e465 Add HandleTossedCart fn for gravity 2024-05-10 17:06:53 -04:00
scawful
dc5ab707fd clamp cart position to 16x16 grid before changing directions 2024-05-10 17:06:12 -04:00
scawful
2d794c876f add timer to HandleTileDirections to avoid overtriggering 2024-05-10 17:05:56 -04:00
scawful
8a65a7ead9 HandleLiftAndToss movement speed based on link direction 2024-05-10 17:05:34 -04:00
scawful
21f43af75e Retain mask/form palette when accessing OW map 2024-05-07 09:55:50 -04:00
scawful
6c499a0f2d Retain GBC sprite when exiting DW dungeons 2024-05-07 09:42:37 -04:00
scawful
cfdbb27947 cleanup deku scrub enemy sprite 2024-05-06 17:19:28 -04:00
scawful
2b05733eef Add DekuLink HandleMovement based on somaria drag velocity 2024-05-04 18:09:57 -04:00
scawful
1d203b0f12 Add DekuLink HandleCamera 2024-05-04 18:09:42 -04:00
scawful
2128aba55d Add Link_Transform mask, uses A for mask id and sets carry on successful transformation 2024-05-04 18:09:22 -04:00
scawful
675d442a3f add maiden and mantle sprite code 2024-05-04 13:35:20 -04:00
scawful
452009ad77 add final boss pit transition 2024-05-04 13:34:31 -04:00
scawful
78b9f6e85b grant lv4 sword for master sword sprite 2024-05-04 01:19:24 -04:00
scawful
7abdc90d12 add environmental hazards to twinrova boss fight 2024-05-03 23:02:53 -04:00
scawful
81125cc33b add whirlpool to underwater sprite 2024-05-03 23:00:26 -04:00
scawful
367b5abe78 random cleanup 2024-05-03 22:58:03 -04:00
scawful
de1bbfae55 cleanup sprite movement functions lib 2024-05-03 22:57:00 -04:00
scawful
aa2f687e3f update zora princess hitbox and set harmless 2024-05-03 22:55:57 -04:00
scawful
bae34e1acd add todo for zora mask resurfacing bug 2024-05-02 01:48:24 -04:00
scawful
4a00ba331d add deku link palette 2024-05-02 01:47:15 -04:00
scawful
435d42e9a1 charge 650 rupees for stone mask 2024-05-02 01:45:56 -04:00
scawful
d51a1818a9 daynight dungeon map fix 2024-05-02 01:44:57 -04:00
scawful
fe9a995495 daynight game over and save screen fix 2024-05-02 01:44:40 -04:00
scawful
e21955aa73 Fix Trinexx breath movement shake speed values 2024-05-02 01:43:48 -04:00
scawful
f0294c966a Twinrova_AddPitHazard 2024-05-02 01:43:23 -04:00
scawful
2769000fd3 Add fireball lasers to twinrova 2024-05-02 01:43:04 -04:00
scawful
e55c4b0084 cleanup Twinrova 2024-05-02 01:42:49 -04:00
scawful
ee22d0a728 Update Glacia Estate group 0x0B collision to include trinexx ice tile 2024-05-01 08:52:31 -04:00
scawful
02e93ed604 Store the high bytes of XY position for block reset 2024-05-01 08:02:47 -04:00
scawful
a09c2995db Add furnace, firewood, and ice chair object bins 2024-05-01 08:02:07 -04:00
scawful
8a67cfa88a Add new custom object handler for id 0x32 2024-05-01 08:01:49 -04:00
scawful
8efb24fa3c Fix Twinrova disappearing after Maiden code 2024-05-01 08:01:08 -04:00
scawful
51a4f8ea57 Add sliding ice block spirte 2024-04-29 20:28:20 -04:00
scawful
d3e27af904 fix day night palette bugs 2024-04-28 13:36:10 -04:00
scawful
13147aabdf Add Zora Princess sprite, grants Zora Mask on Song of Healing trigger 2024-04-28 12:29:01 -04:00
scawful
77ded4e213 add item receipt text to mask salesman 2024-04-28 11:20:12 -04:00
scawful
5e5aa12e11 Mask salesman bunny hood and stone mask vendor code 2024-04-28 11:07:55 -04:00
scawful
f5d64dbfb0 increase size of maku tree hitbox for talking 2024-04-28 09:24:00 -04:00
scawful
7f81b36cf5 increase length of phase 02 in king dodongo 2024-04-28 00:00:01 -04:00
scawful
107bb881dd fix syntax error in goldstar 2024-04-27 23:59:49 -04:00
scawful
89efbac54a Fix ZCustomOverworld hook which was previously wrong 2024-04-27 23:59:42 -04:00
scawful
f0900c631e King dodongo increased health phase table 2024-04-27 19:26:20 -04:00
scawful
d20724b1db Adjust king dodongo leg position 2024-04-27 19:26:00 -04:00
scawful
f128f767b8 Make king dodongo mask weakness bombs instead of hammer 2024-04-27 18:42:23 -04:00
scawful
77116c89b4 blank key icon on hud when not in dungeon 2024-04-27 18:24:08 -04:00
scawful
ea58141a4d fix goldstar hud crash 2024-04-27 18:14:25 -04:00
scawful
34a665db59 zora mask resurface bug fix 2024-04-27 18:07:35 -04:00
scawful
4ab6cd175a set start time to 8:00am 2024-04-27 18:01:38 -04:00
scawful
7becd5e658 GBC link retain form when hour changes fix 2024-04-27 18:01:09 -04:00
scawful
388f1a4e80 Zarby day and night intro and triforce room fix 2024-04-27 18:00:57 -04:00
scawful
513da6dbd0 fix ocarina right scroll 2024-04-27 17:59:41 -04:00
scawful
d19626513a fix maku tree dismiss intro bug 2024-04-27 15:53:16 -04:00
scawful
9a430f9fc0 sick kid item trigger by song of healing 2024-04-27 13:28:09 -04:00
scawful
3f5e194708 update ocarina song id branches 2024-04-27 12:50:39 -04:00
scawful
a0d0a60f62 Finish ranch girl NPC quest 2024-04-27 12:50:22 -04:00
scawful
a518ffc43c Rearrange menu song name text order 2024-04-27 12:00:07 -04:00
scawful
8090edab31 Add SRAM to Ocarina menu icons 2024-04-27 11:59:57 -04:00
scawful
d5ae9495dc Add SRAM to Ocarina scroll 2024-04-27 11:59:04 -04:00
scawful
c3311e22bf add ranch girl npc 2024-04-27 01:34:56 -04:00
scawful
64247a062c Update mask salesman NPC quest interaction 2024-04-27 01:34:35 -04:00
Justin Scofield
3777650c7e Merge pull request #61 from scawful/kydreeok-boss
Kydreeok Boss and Kydreeok Head Sprite Refactor
2024-04-19 09:13:57 -04:00
Justin Scofield
7335229c46 Merge pull request #53 from scawful/minecart-review
Minecart, Mineswitch, and Switch Track Sprite Refactor
2024-04-19 09:13:35 -04:00
Justin Scofield
9010e364fa Merge pull request #62 from scawful/goldstar-item
Goldstar Item Refactor
2024-04-19 09:13:19 -04:00
Justin Scofield
61e9e34844 Merge pull request #60 from scawful/twinrova-boss
Twinrova Boss and Blind Maiden refactor
2024-04-19 09:12:45 -04:00
scawful
9fabccdb12 Upload dragon ship custom spritesheets dynamically 2024-04-12 14:46:08 -04:00
scawful
dff09b5f6b Goldstar item formatting and comments 2024-03-30 12:35:56 -04:00
scawful
039be63412 Add todo to handle boss death based on kydreeok head health 2024-03-30 12:07:15 -04:00
scawful
33846cda98 More Sprite action formatting 2024-03-30 12:07:01 -04:00
scawful
23fb2d928b Update Sprite_Kydreeok_Draw formatting 2024-03-30 12:04:52 -04:00
scawful
761fbce7d8 Update MoveBody formatting 2024-03-30 12:04:34 -04:00
scawful
9d1cd684d7 Update SpawnLeftHead and SpawnRightHead formatting 2024-03-30 12:04:04 -04:00
scawful
1dcdfaffa0 Update Kydreeok sprite actions 2024-03-30 12:03:49 -04:00
scawful
55f7de64ca Update Sprite_Kydreeok_Prep formatting 2024-03-30 12:03:35 -04:00
scawful
0b173ce212 Update Sprite_Kydreeok_Long formatting 2024-03-30 12:03:21 -04:00
scawful
446ccf0d7f Update Kydreeok Head header comment 2024-03-30 11:53:31 -04:00
scawful
6842ac956c Add Sprite_KydreeokHead_DrawNeck for neck pieces draw 2024-03-30 11:52:57 -04:00
scawful
4b727b870d Format movement and random attack code 2024-03-30 11:52:20 -04:00
scawful
8c0dc13f1f Format head rotation code 2024-03-30 11:51:49 -04:00
scawful
2e5a5908c0 Reformat Kydreeok Head sprite actions 2024-03-30 11:51:32 -04:00
scawful
8f5d58560e Move and rename SpeedTable 2024-03-30 11:51:16 -04:00
scawful
425d84f5c2 Add TODO for Kydreeok Head properties 2024-03-30 11:50:26 -04:00
scawful
2312452d28 Update Sprite_KydreeokHead_Long 2024-03-30 11:50:12 -04:00
scawful
436da5736e Add todo for whether to use blind laser garnish 2024-03-30 11:05:45 -04:00
scawful
c4e4564749 Add todo for boss disappearring from blind maiden bug 2024-03-30 11:05:26 -04:00
scawful
622b7d950b Update fire/ice attack garnish formatting and comments 2024-03-30 11:04:38 -04:00
scawful
cc753b9d47 Add todo to create parent sprite for Trinexx garnish attacks 2024-03-30 11:04:04 -04:00
scawful
6cd013e6d6 Reformat sprite actions 2024-03-30 11:03:43 -04:00
scawful
7f87622f00 Add TODO for implementing cart toss distance/gravity 2024-03-30 10:20:19 -04:00
scawful
716a681d6d Cleanup HandleTileDirections fn 2024-03-30 10:12:03 -04:00
scawful
b0b3ca242b Add B button check to start riding, allows for easier lifting with A button 2024-03-30 09:53:19 -04:00
scawful
58dd5aab1f Add comments and update formatting 2024-03-30 09:43:58 -04:00
scawful
e0a20a98cd Replace $0DE0 with !SpriteDirection label 2024-03-30 09:29:53 -04:00
scawful
0f241bfddd Add comments to switch track sprite 2024-03-28 20:19:39 -04:00
scawful
12ef39ff79 Apply ASM code formatter 2024-03-28 20:17:56 -04:00
scawful
3324a13fb2 Move minecart ram, macros, update formatting and comments 2024-03-28 20:10:33 -04:00
scawful
53561eab31 Add small diff to minecart sprite to make it commentable 2024-03-28 20:02:12 -04:00
scawful
4c4f531929 Update switch and track sprite format for code review 2024-03-28 19:57:08 -04:00
scawful
dad37bdee7 Move mincart to Sprites/Objects for code review 2024-03-28 19:55:07 -04:00
304 changed files with 80004 additions and 18114 deletions

147
.gitignore vendored
View File

@@ -10,3 +10,150 @@ oos111x.sfc
oos111x.smp.sym
oos111x.srm
oos111x.sym
zcompress.exe
oos165.sfc
oos165x-1.bst
oos165x-2.bst
oos165x-3.bst
oos165x.bp
oos165x.cpu.sym
oos165x.sfc
oos165x.smp.sym
oos165x.srm
buildJ.bat
oos165x.cht
Roms
Dungeons/Assets
Items/gfx/jump_frames.xcf
Masks/etc
Menu/rings/
Overworld/project_files/DarkWorldMainSet.xcf
Sprites/Project Files/
Thumbs.db
.favorites.json
Dungeons/Assets/
Roms/oos111.bps
Roms/oos112.sfc
Sprites/Enemies/deku_scrub_enemy.zsm
Dungeons/Objects/object_files/kydreeok_body.zob
Sprites/Objects/Minecart/
Util/tools
Util/rom_map.txt
Sprites/NPCs/korok_hollo.asm
Sprites/NPCs/korok_makar.asm
Sprites/NPCs/korok_rown.asm
Overworld/world_map/test_dw.bmp
Overworld/world_map/zelda3.sfc
Overworld/world_map/maptest.bmp
Sprites/Objects/whirlpool_export.asm
Sprites/Objects/ice_block_export.asm
Masks/gfx/[108]tlp11
Masks/gfx/extra/
Overworld/project_files/OverworldCastleBridge.png
Overworld/project_files/OverworldCastleBridge.xcf
Overworld/gfx/boat2_1.bin
Overworld/gfx/boat2_3.bin
Overworld/gfx/boat2_4.bin
Overworld/gfx/boat2_2.bin
Sprites/NPCs/zora_princess_proj.zsm
Util/SpcToASM/SpcConverter.deps.json
Util/SpcToASM/SpcConverter.dll
Util/SpcToASM/SpcConverter.exe
Util/SpcToASM/SpcConverter.pdb
Util/SpcToASM/SpcConverter.runtimeconfig.json
Masks/gfx/deku_link.pal
Masks/gfx/deku_new.pal
Masks/gfx/dekulinkpal.pal
Masks/gfx/dekulinkpal.pal.bak
Masks/gfx/gbc-link.pal
Masks/gfx/image.bin
Masks/gfx/image.png
Overworld/project_files/zora_overlay_2.zsa
Overworld/project_files/zora_temple_overlay.zsa
Sprites/wolfos_export.asm
Sprites/wolf_boss.zsm
Sprites/NPCs/project_files/korok_hollo.asm
Sprites/NPCs/project_files/korok_makar.asm
Sprites/NPCs/project_files/korok_rown.asm
Sprites/NPCs/project_files/zora_princess_proj.zsm
Util/zelda3.sfc
Util/templatemusic.asm
Util/ZSCustomOverworld.asm
Sprites/Objects/Project Files/ice_block_export.asm
Sprites/Objects/Project Files/whirlpool_export.asm
Overworld/world_map/dw_gfx_new.bmp
Menu/tilemaps/dung_map.bin
Dungeons/intro_cutscene.asm
Dungeons/water_switch.asm
run.sh
Sprites/Bosses/left_kydreeok_head.asm
Sprites/Bosses/kydreeok_wings.asm
Sprites/Bosses/kydreeok_body.zsm
Sprites/Bosses/dark_link.pal
Sprites/NPCs/deku_scrub_npcs.asm
Sprites/Enemies/anti_kirby_v2.asm
Masks/gfx/gbc_dark_link.4bpp
Sprites/kydrog_intro.asm
Util/ZScreamNew/ZScream.exe
Util/ZScreamNew/ZSCustomOverworld.asm
Util/dark_link.bin
Sprites/NPCs/project_files/deku_scrub_npcs.asm
Util/ZScreamNew/asar.dll
Util/ZScreamNew/CustomCollision.asm
Util/ZScreamNew/debug.asm
Util/ZScreamNew/DefaultNames.txt
Util/ZScreamNew/DW.png
Util/ZScreamNew/Lidgren.Network.dll
Util/ZScreamNew/Lidgren.Network.pdb
Util/ZScreamNew/Logs.txt
Util/ZScreamNew/LW.png
Util/ZScreamNew/MapTest.png
Util/ZScreamNew/newgraves.asm
Util/ZScreamNew/ScratchPad.dat
Util/ZScreamNew/SP.png
Util/ZScreamNew/spritesmove.asm
Util/ZScreamNew/tempPatch.asm
Util/ZScreamNew/ZScream.application
Util/ZScreamNew/ZScream.exe.config
Util/ZScreamNew/ZScream.exe.manifest
Util/ZScreamNew/ZS_Patches/Version.txt
Util/ZScreamNew/ZS_Patches/Hex Edits/Misc Small Patches.asm
Util/ZScreamNew/ZS_Patches/Items/AST Boots.asm
Util/ZScreamNew/ZS_Patches/Misc/Big Bomb Requirements.asm
Util/ZScreamNew/ZS_Patches/Misc/IntroSkip.asm
Util/ZScreamNew/ZS_Patches/Misc/JP1.0 Glitches.asm
Util/ZScreamNew/ZS_Patches/Misc/Link Bed Start Position.asm
Util/ZScreamNew/ZS_Patches/Misc/NoRocks.asm
Util/ZScreamNew/ZS_Patches/Misc/Rainstate Skip.asm
Util/ZScreamNew/ZS_Patches/Misc/TorchTags.asm
Util/ZScreamNew/ZS_Patches/Misc/Weathervane.asm
Util/ZScreamNew/ZS_Patches/Music/LostWoodsExitMusic.asm
Util/ZScreamNew/ZS_Patches/Npcs/Bottle Vendor.asm
Util/ZScreamNew/ZS_Patches/Sprites/Crystalswitch Conveyor.asm
Util/ZScreamNew/ZS_Patches/Sprites/Elemental Trinexx.asm
Util/ZScreamNew/ZS_Patches/Sprites/Eye Lasers Active.asm
Util/ZScreamNew/ZS_Patches/Sprites/Khodstare Speeds.asm
Util/ZScreamNew/ZS_Patches/Sprites/Spike Damage.asm
Util/ZScreamNew/ZS_Patches/Sprites/Spikes_Subtype.asm
Sprites/Bosses/bigchuchu_grow.asm
Sprites/Bosses/manhandla_chuchu_blast.asm
Sprites/Bosses/manhandla_export_2.asm
Sprites/Bosses/manhandla_export.asm
Music/Z3_SongOfHealingThemeV1-00.asm
Dungeons/experimental/HitBoxProperties.asm
Dungeons/experimental/intro_cutscene.asm
Dungeons/experimental/KillSprites
Dungeons/experimental/warpswitch.asm
Dungeons/experimental/water_switch.asm
Overworld/weathervane.asm
Util/banana.asm
Menu/tilemaps/sheet.png
Sprites/NPCs/project_files/eon_owl.zsm
Music/wip/oot_title.asm
Music/wip/phantom_ganon.asm
Music/wip/template_song.asm
Music/wip/twinrova_battle.asm
Sprites/NPCs/piratian.zsm
Masks/gfx/moosh.png
Masks/gfx/moosh.pal
Dungeons/DungeonMaps.asm

47
Core/ZS ROM MAP.txt Normal file
View File

@@ -0,0 +1,47 @@
Expanded space used by ZScream as of 02/28/2025
Addresses are PC unless stated otherwise.
ZS reserves everything up to 1.5MB or up to 0x150000
And an additional 3 banks at the end of the 2.0MB 0x1E8000 to 0x1FFFFF
0x100000 - 0x107FFF: 1 Bank
Nothing?
0x108000 - 0x10FFFF: 1 Bank
Title screen data
Dungeon map data
0x110000 - 0x117FFF: 1 Bank
Default room header location
Seems to have been some old dungeon object data expansion but that has since been moved.
0x118000 - 0x11FFFF: 1 Bank
Seems to have been some old dungeon object data expansion but that has since been moved.
0x120000 - 0x127FFF: 1 Bank
Expanded overlay data
0x128000 - 0x12FFFF: 1 Bank
Custom collision data
0x130000 - 0x137FFF: 1 Bank
Overworld map data overflow
0x138000 - 0x13FFFF: 1 Bank
Expanded Dungeon object data
0x140000 - 0x147FFF: 1 Bank
Custom overworld data
0x148000 - 0x14FFFF: 1 Bank
Expanded Dungeon object data
0x1E0000 - 0x1E7FFF: 1 Bank
Custom ASM Patches
0x1E8000 - 0x1EFFFF: 1 Bank
Expanded Tile16 space
0x1F0000 - 0x1FFFFF: 2 Banks
Edpanded Tile32 space

274
Core/hardware.asm Normal file
View File

@@ -0,0 +1,274 @@
; ==============================================================================
; SNES Hardware Registers
; ==============================================================================
; Shorthand legend:
; Addr = Address
; APU = Audio Processing Unit
; BG = BackGround
; CGRAM = Color Generator RAM
; Des = Designation
; H = Horizontal
; HDMA = Horizontal Direct Memory Access
; HV = H/V or Horizontal/Vertical
; Init = Initial
; IO = I/O or Input/Output
; IRQ = Interupt ReQuest
; NMI = Non-Maskable Interupt
; Num = Number
; MULT = Multiply/Multiplication
; OAM = Object Attribute Memory
; OBJ = Object
; Pos = Position
; PPU = Picture Processing Unit
; V = Vertical
; Val = Value
; VRAM = Video RAM
; Names taken from:
; https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_Hardware_Registers
; Further details on each register can be found here:
; https://github.com/gilligan/snesdev/blob/master/docs/snes_registers.txt
; https://www.youtube.com/watch?v=-4OOuRvTXrM&t=167s
org $7E2100 ; Remove for asar 2.0.
struct SNES $7E2100
{
.ScreenDisplay: skip $01 ; $2100
.OAMSizeAndDataDes: skip $01 ; $2101
.OAMAccessAddr: skip $02 ; $2102
.OMADataWrite: skip $01 ; $2104
.BGModeAndTileSize: skip $01 ; $2105
.MosaicAndBGEnable: skip $01 ; $2106
.BG1AddrAndSize: skip $01 ; $2107
.BG2AddrAndSize: skip $01 ; $2108
.BG3AddrAndSize: skip $01 ; $2109
.BG4AddrAndSize: skip $01 ; $210A
.BG1And2TileDataDes: skip $01 ; $210B
.BG3And4TileDataDes: skip $01 ; $210C
.BG1HScrollOffset: skip $01 ; $210D
.BG1VScrollOffset: skip $01 ; $210E
.BG2HScrollOffset: skip $01 ; $210F
.BG2VScrollOffset: skip $01 ; $2110
.BG3HScrollOffset: skip $01 ; $2111
.BG3VScrollOffset: skip $01 ; $2112
.BG4HScrollOffset: skip $01 ; $2113
.BG4VScrollOffset: skip $01 ; $2114
.VRAMAddrIncrementVal: skip $01 ; $2115
.VRAMAddrReadWriteLow: skip $01 ; $2116
.VRAMAddrReadWriteHigh: skip $01 ; $2117
.VRAMDataWriteLow: skip $01 ; $2118
.VRAMDataWriteHigh: skip $01 ; $2119
.Mode7Init skip $01 ; $211A
.Mode7MatrixA skip $01 ; $211B
.Mode7MatrixB skip $01 ; $211C
.Mode7MatrixC skip $01 ; $211D
.Mode7MatrixD skip $01 ; $211E
.Mode7CenterPosX skip $01 ; $211F
.Mode7CenterPosY skip $01 ; $2120
.CGRAMWriteAddr skip $01 ; $2121
.CGRAMWriteData skip $01 ; $2122
.BG1And2WindowMask skip $01 ; $2123
.BG3And4WindowMask skip $01 ; $2124
.OBJAndColorWindow skip $01 ; $2125
.Window1LeftPosDes skip $01 ; $2126
.Window1RightPosDes skip $01 ; $2127
.Window2LeftPosDes skip $01 ; $2128
.Window2RightPosDes skip $01 ; $2129
.BG123And4WindowLogic skip $01 ; $212A
.ColorAndOBJWindowLogic skip $01 ; $212B
.BGAndOBJEnableMainScreen skip $01 ; $212C
.BGAndOBJEnableSubScreen skip $01 ; $212D
.WindowMaskDesMainScreen skip $01 ; $212E
.WindowMaskDesSubScreen skip $01 ; $212F
.InitColorAddition skip $01 ; $2130
.AddSubtractSelectAndEnable skip $01 ; $2131
.FixedColorData skip $01 ; $2132
.ScreenInit skip $01 ; $2133
.MultResultLow skip $01 ; $2134
.MultResultMid skip $01 ; $2135
.MultResultHigh skip $01 ; $2136
.HVCounterSoftwareLatch skip $01 ; $2137
.OAMReadDataLowHigh skip $01 ; $2138
.VRAMReadDataLow skip $01 ; $2139
.VRAMReadDataHigh skip $01 ; $213A
.CGRAMReadDataLowHigh skip $01 ; $213B
.HCounterData skip $01 ; $213C
.VCounterData skip $01 ; $213D
.PPUStatusFlag1 skip $01 ; $213E
.PPUStatusFlag2 skip $01 ; $213F
.APUIOPort0 skip $01 ; $2140
.APUIOPort1 skip $01 ; $2141
.APUIOPort2 skip $01 ; $2142
.APUIOPort3 skip $01 ; $2143
base $2180
.IndirectWorkRAMPort: skip $01 ; $2180
.IndirectWorkRAMAddrLow: skip $01 ; $2180
.IndirectWorkRAMAddrMid: skip $01 ; $2180
.IndirectWorkRAMAddrHigh: skip $01 ; $2180
base $4200
.NMIVHCountJoypadEnable: skip $01 ; $4200
.ProgrammableIOPortOut: skip $01 ; $4201
.MultiplicandA: skip $01 ; $4202
.MultiplierB: skip $01 ; $4203
.DividendLow: skip $01 ; $4204
.DividendHigh: skip $01 ; $4205
.DivisorB: skip $01 ; $4206
.HCountTimer: skip $01 ; $4207
.HCountTimerMSB: skip $01 ; $4208
.VCountTImer: skip $01 ; $4209
.VCountTimerMSB: skip $01 ; $420A
.DMAChannelEnable: skip $01 ; $420B
.HDMAChannelEnable: skip $01 ; $420C
.CycleSpeedDes: skip $01 ; $420D
base $4210
.NMIFlagAndCPUVersionNum: skip $01 ; $4210
.IRQFlagByHVCountTimer: skip $01 ; $4211
.HVBlankFlagsAndJoyStatus: skip $01 ; $4212
.ProgrammableIOPortIn: skip $01 ; $4213
.DivideResultQuotientLow: skip $01 ; $4214
.DivideResultQuotientHigh: skip $01 ; $4215
.RemainderResultLow: skip $01 ; $4216
.RemainderResultHigh: skip $01 ; $4217
.JoyPad1DataLow: skip $01 ; $4218
.JoyPad2DataLow: skip $01 ; $4219
.JoyPad3DataLow: skip $01 ; $421A
.JoyPad4DataLow: skip $01 ; $421B
.JoyPad1DataHigh: skip $01 ; $421C
.JoyPad2DataHigh: skip $01 ; $421D
.JoyPad3DataHigh: skip $01 ; $421E
.JoyPad4DataHigh: skip $01 ; $421F
}
endstruct
struct DMA $7E4300
{
; Channel 0
.0_TransferParameters: skip $01 ; $4300
.0_DestinationAddr: skip $01 ; $4301
.0_SourceAddrOffsetLow: skip $01 ; $4302
.0_SourceAddrOffsetHigh: skip $01 ; $4303
.0_SourceAddrBank: skip $01 ; $4304
.0_TransferSizeLow: skip $01 ; $4305
.0_TransferSizeHigh: skip $01 ; $4306
.0_DataBank: skip $01 ; $4307
.0_TableAddrLow: skip $01 ; $4308
.0_TableAddrHigh: skip $01 ; $4309
.0_TransferLineNum: skip $01 ; $430A
base $4310 ; Channel 1
.1_TransferParameters: skip $01 ; $4310
.1_DestinationAddr: skip $01 ; $4311
.1_SourceAddrOffsetLow: skip $01 ; $4312
.1_SourceAddrOffsetHigh: skip $01 ; $4313
.1_SourceAddrBank: skip $01 ; $4314
.1_TransferSizeLow: skip $01 ; $4315
.1_TransferSizeHigh: skip $01 ; $4316
.1_DataBank: skip $01 ; $4317
.1_TableAddrLow: skip $01 ; $4318
.1_TableAddrHigh: skip $01 ; $4319
.1_TransferLineNum: skip $01 ; $431A
base $4320 ; Channel 2
.2_TransferParameters: skip $01 ; $4320
.2_DestinationAddr: skip $01 ; $4321
.2_SourceAddrOffsetLow: skip $01 ; $4322
.2_SourceAddrOffsetHigh: skip $01 ; $4323
.2_SourceAddrBank: skip $01 ; $4324
.2_TransferSizeLow: skip $01 ; $4325
.2_TransferSizeHigh: skip $01 ; $4326
.2_DataBank: skip $01 ; $4327
.2_TableAddrLow: skip $01 ; $4328
.2_TableAddrHigh: skip $01 ; $4329
.2_TransferLineNum: skip $01 ; $432A
base $4330 ; Channel 3
.3_TransferParameters: skip $01 ; $4330
.3_DestinationAddr: skip $01 ; $4331
.3_SourceAddrOffsetLow: skip $01 ; $4332
.3_SourceAddrOffsetHigh: skip $01 ; $4333
.3_SourceAddrBank: skip $01 ; $4334
.3_TransferSizeLow: skip $01 ; $4335
.3_TransferSizeHigh: skip $01 ; $4336
.3_DataBank: skip $01 ; $4337
.3_TableAddrLow: skip $01 ; $4338
.3_TableAddrHigh: skip $01 ; $4339
.3_TransferLineNum: skip $01 ; $433A
base $4340 ; Channel 4
.4_TransferParameters: skip $01 ; $4340
.4_DestinationAddr: skip $01 ; $4341
.4_SourceAddrOffsetLow: skip $01 ; $4342
.4_SourceAddrOffsetHigh: skip $01 ; $4343
.4_SourceAddrBank: skip $01 ; $4344
.4_TransferSizeLow: skip $01 ; $4345
.4_TransferSizeHigh: skip $01 ; $4346
.4_DataBank: skip $01 ; $4347
.4_TableAddrLow: skip $01 ; $4348
.4_TableAddrHigh: skip $01 ; $4349
.4_TransferLineNum: skip $01 ; $434A
base $4350 ; Channel 5
.5_TransferParameters: skip $01 ; $4350
.5_DestinationAddr: skip $01 ; $4351
.5_SourceAddrOffsetLow: skip $01 ; $4352
.5_SourceAddrOffsetHigh: skip $01 ; $4353
.5_SourceAddrBank: skip $01 ; $4354
.5_TransferSizeLow: skip $01 ; $4355
.5_TransferSizeHigh: skip $01 ; $4356
.5_DataBank: skip $01 ; $4357
.5_TableAddrLow: skip $01 ; $4358
.5_TableAddrHigh: skip $01 ; $4359
.5_TransferLineNum: skip $01 ; $435A
base $4360 ; Channel 6
.6_TransferParameters: skip $01 ; $4360
.6_DestinationAddr: skip $01 ; $4361
.6_SourceAddrOffsetLow: skip $01 ; $4362
.6_SourceAddrOffsetHigh: skip $01 ; $4363
.6_SourceAddrBank: skip $01 ; $4364
.6_TransferSizeLow: skip $01 ; $4365
.6_TransferSizeHigh: skip $01 ; $4366
.6_DataBank: skip $01 ; $4367
.6_TableAddrLow: skip $01 ; $4368
.6_TableAddrHigh: skip $01 ; $4369
.6_TransferLineNum: skip $01 ; $436A
base $4370 ; Channel 7
.7_TransferParameters: skip $01 ; $4370
.7_DestinationAddr: skip $01 ; $4371
.7_SourceAddrOffsetLow: skip $01 ; $4372
.7_SourceAddrOffsetHigh: skip $01 ; $4373
.7_SourceAddrBank: skip $01 ; $4374
.7_TransferSizeLow: skip $01 ; $4375
.7_TransferSizeHigh: skip $01 ; $4376
.7_DataBank: skip $01 ; $4377
.7_TableAddrLow: skip $01 ; $4378
.7_TableAddrHigh: skip $01 ; $4379
.7_TransferLineNum: skip $01 ; $437A
}
endstruct
; ==============================================================================

185
Core/link.asm Normal file
View File

@@ -0,0 +1,185 @@
; =========================================================
; Link RAM and Functions
LinkY = $20 ; Position Y of link
LinkYH = $21 ; High position Y of link
LinkX = $22 ; Position X of link
LinkXH = $23 ; High position X of link
LinkZ = $24 ; Position Z of link
; ----UDLR
; [U Up][D Down][L Left][R Right]
; Direction link is pushing against
LinkPushDir = $26
; Link's recoiling speed
; By themselves, these do not do much
; They will be reset every frame Link is not in recoil state
LinkRecoilY = $27
LinkRecoilX = $28
LinkRecoilZ = $29
; Link's subpixel velocity
; when this value overflows, Link's main velocity gains an extra pixel
; reset on direction change, so not really a positional subpixel
LinkSubVelY = $2A
LinkSubVelX = $2B
; Direction link is facing
; 00:Up, 02:Down, 04:Left, 06:Right
LinkFaceDir = $2F
; Last direction link moved towards
; 00:Up, 01:Down, 02:Left, 03:Right
LinkLastDir = $66
; ----UDLR
; [U Up][D Down][L Left][R Right]
; direction link is "walking towards"
LinkMoveDir = $67
; 0: Not moving, 1: Moving cardinal, 2: Moving diagonally
LinkMoveInfo = $6A
LinkVisible = $4B ; if set to 0x0C link will be invisible
LinkBunnyGfx = $56 ; if set to 1 link will be bunny, otherwise link
; 0x00: normal speed, 0x01-0x0F: slow,<2C>> 0x10:fast
LinkSpeed = $57
; 0x00: normal speed, 0x02: walking on stair speed, 0x10: dashing speed
LinkSpeedTbl = $5E
; if is set to 0x02 or 0x03 link is falling
LinkFalling = $5B
FallTimer = $5C
; LinkState_Default : 0x00
; LinkState_Pits : 0x01
; LinkState_Recoil : 0x02
; LinkState_SpinAttack : 0x03
; LinkState_Swimming : 0x04 (ZoraDive)
; LinkState_OnIce : 0x05
; LinkState_Recoil : 0x06
; LinkState_Zapped : 0x07
; LinkState_UsingEther : 0x08
; LinkState_UsingBombos : 0x09
; LinkState_UsingQuake : 0x0A (DekuHover)
; LinkState_HoppingSouthOW : 0x0B
; LinkState_HoppingHorizontallyOW : 0x0C
; LinkState_HoppingDiagonallyUpOW : 0x0D
; LinkState_HoppingDiagonallyDownOW : 0x0E
; LinkState_0F : 0x0F
; LinkState_0F : 0x10
; LinkState_Dashing : 0x11
; LinkState_ExitingDash : 0x12
; LinkState_Hookshotting : 0x13
; LinkState_CrossingWorlds : 0x14
; LinkState_ShowingOffItem : 0x15
; LinkState_Sleeping : 0x16
; LinkState_Bunny : 0x17
; LinkState_HoldingBigRock : 0x18
; LinkState_ReceivingEther : 0x19
; LinkState_ReceivingBombos : 0x1A
; LinkState_ReadingDesertTablet : 0x1B
; LinkState_TemporaryBunny : 0x1C
; LinkState_TreePull : 0x1D
; LinkState_SpinAttack : 0x1E
LinkState = $5D
; 0: Link is not in a doorway
; 1: is in a vertical doorway
; 2: is in horizontal doorway
LinkDoorway = $6C
; 0: Nothing
; 1: a hand in the air
; 2: 2 hands in the air (like getting triforce)
LinkGrabGfx = $02DA
; if not 0 add a poof gfx on link
LinkPoofGfx = $02E1
; Bunny timer for link before transforming back
LinkBunTimer = $02E2
; if not 0 prevent link from moving and opening the menu
LinkMenuMove = $02E4
; if not 0 prevent link from getting any damages from sprites
LinkDamage = $037B
; ----CCCC
; [C Touching chest id]
LinkColChest = $02E5
; 0: Not on somaria platform, 2: On somaria platform
LinkSomaria = $02F5
; BP-AETHR
; [B Boomerang][P Powder]
; [A Bow&Arrows][E UnusedItem]
; [T UnusedItem][H Hammer][R Rods]
LinkItemUse = $0301
LinkItemY = $0303 ; Currently equipped item on the Y button
; 0: Nothing, 1:Picking up something, 2: Throwing something
LinkCarrying = $0308
; .... ..tl
; t - tossing object
; l - lifting object
LinkCarryOrToss = $0309
; 0: Normal
; 1: Shovel
; 2: Praying
; 4: Hookshot
; 8: Somaria
; 10: Bug net
; 20: Read book
; 40: Tree pull
LinkAnim = $037A
LinkWallCheat = $037F ; If non zero can walk through walls
; Animation step/graphics for spin attack animations; including medallions.
LinkSpinGfx = $031C
LinkSpinStep = $031D
; =========================================================
Link_ReceiveItem = $0799AD ; Y = item id
Link_CancelDash = $0791B9
Link_Initialize = $07F13C
Link_ResetProperties_A = $07F1A3
Link_ResetProperties_B = $07F1E6
Link_ResetProperties_C = $07F1FA
Link_ResetSwimmingState = $07983A
Link_ResetStateAfterDamagingPit = $07984B
Link_ItemReset_FromOverworldThings = $07B107
Link_CalculateSFXPan = $0DBB67
; Used by Agahnim2 fight
CallForDuckIndoors = $07A45F
ApplyLinksMovementToCamera = $07E9D3
HandleIndoorCameraAndDoors = $07F42F
Link_HandleVelocityAndSandDrag = $07E3DD
Link_HandleMovingAnimation_FullLongEntry = $07E6A6
Link_HandleMovingAnimation_General = $07E765
Link_HandleMovingAnimationSwimming = $07E7FA
LinkHop_FindArbitraryLandingSpot = $07E370
CheckIfLinkIsBusy = $07F4D0
Refund_Magic = $07B0E9
Hookshot_CheckTileCollision = $07D576

142
Core/message.asm Normal file
View File

@@ -0,0 +1,142 @@
; Expanded Message Bank
; Special thanks to Zarby89
!addr = $0EF3FF
!looprun = $00
while !looprun == $00
if read1(!addr) == $7F
!addr #= !addr+1
;print hex(!addr) ; DEBUG LINE
!looprun = $01
endif
!addr #= !addr-1
endwhile
; Temporary fix for the message bank
; ZS does not clear message data when bank is changed
; So the end of the data bank is not as easily searchable.
org $0EEE75 : db $80
org !addr+1 : db $80
org $0ED436
JML MessageExpand
NOP #$06
org $2F8000
MessageExpand:
{
; are we already in expanded bank?
LDA.b $02 : AND.w #$00FF : CMP.w #$000E : BNE +
LDA.w #MessageExpandedData : STA.b $00
LDA.w #MessageExpandedData>>16 : STA.b $02
JML $0ED3FC ; go back to original read message code pointers
+
; Restore vanilla code
LDA.w #$DF40 : STA.b $00
LDA.w #$000E : STA.b $02
JML $0ED3FC ; go back to original read message code pointers
}
MessageExpandedData:
Message_18D:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $E3, $59, $2D, $21, $A6, $1E, $3E, $76, $03, $28, $59, $E3, $59, $D0, $1E, $24, $59, $BD, $29, $2C, $42, $59, $26, $32, $59, $1F, $2B, $22, $A5, $1D, $3F, $7E, $73, $13, $B4, $20, $25, $1E, $59, $AE, $59, $DB, $1A, $2F, $1E, $25, $A4, $1F, $1A, $2B, $59, $90, $73, $E2, $1D, $1E, $59, $1A, $1C, $2B, $28, $2C, $2C, $59, $0A, $1A, $25, $32, $31, $28, $59, $DA, $59, $1C, $B1, $2B, $2D, $73, $D8, $59, $2E, $27, $B8, $27, $3E, $59, $05, $C8, $59, $1A, $59, $2C, $26, $8E, $1F, $1E, $1E, $42, $7E, $73, $C6, $59, $1C, $28, $2E, $2B, $D0, $43, $73, $88, $44, $59, $16, $21, $91, $9F, $59, $E3, $59, $AD, $3F, $73, $88, $89, $08, $51, $26, $59, $28, $24, $1A, $32, $41, $68, $7F
Message_18E:
db $00, $21, $42, $59, $1A, $59, $30, $B5, $1E, $59, $1C, $21, $28, $22, $1C, $1E, $3E, $75, $16, $B6, $21, $59, $2D, $B0, $2C, $59, $BD, $29, $42, $59, $27, $28, $59, $D0, $1C, $CE, $2D, $76, $E2, $25, $25, $59, $97, $59, $B0, $1D, $1D, $A0, $A9, $26, $59, $E3, $3E, $7E, $73, $09, $2E, $D3, $59, $21, $8C, $28, $2F, $A1, $D8, $59, $2B, $DC, $1E, $1E, $2C, $73, $8C, $25, $1E, $2D, $59, $D8, $59, $1A, $1D, $2F, $A3, $2E, $CD, $97, $20, $B4, $3E, $7F
Message_18F:
db $0E, $21, $59, $1D, $A2, $41, $41, $41, $75, $08, $2D, $59, $D0, $1E, $26, $2C, $59, $E3, $2B, $59, $29, $28, $9C, $1E, $2D, $2C, $59, $8D, $1A, $76, $1A, $59, $1B, $B6, $59, $25, $22, $20, $21, $2D, $41, $59, $02, $28, $BE, $59, $96, $9C, $59, $E1, $A5, $7E, $73, $E3, $2B, $59, $DF, $25, $25, $1E, $2D, $59, $B5, $59, $1A, $2C, $59, $1F, $2E, $25, $25, $59, $1A, $2C, $59, $26, $B4, $1E, $3E, $73, $13, $B4, $20, $25, $1E, $59, $E2, $25, $25, $59, $DF, $B6, $42, $59, $9F, $27, $51, $2D, $73, $E3, $59, $30, $C8, $2B, $32, $3E, $7F
Message_190:
db $00, $21, $42, $59, $26, $32, $59, $97, $D3, $59, $1C, $2E, $D3, $28, $26, $A6, $3E, $75, $E8, $59, $8D, $97, $9B, $B3, $2A, $2E, $B6, $1E, $76, $D8, $59, $1C, $28, $25, $25, $1E, $1C, $2D, $C8, $59, $C6, $59, $BD, $29, $2C, $3E, $7E, $73, $0C, $1A, $32, $97, $59, $C7, $1E, $59, $1D, $1A, $32, $59, $13, $B4, $20, $25, $1E, $73, $E2, $25, $25, $59, $27, $1A, $BE, $59, $1A, $59, $29, $BA, $1C, $1E, $59, $1A, $1F, $2D, $A1, $E3, $3E, $7F
Message_191:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $D0, $1E, $24, $B3, $D8, $59, $D0, $1C, $CE, $2D, $2C, $59, $C6, $76, $D8, $59, $0C, $2E, $D1, $2B, $28, $28, $26, $59, $06, $2B, $28, $2D, $DA, $42, $59, $8D, $E3, $3F, $7E, $73, $E6, $59, $13, $28, $1A, $1D, $D3, $28, $28, $25, $59, $16, $28, $28, $1D, $2C, $59, $8D, $1A, $73, $DB, $22, $9C, $32, $59, $29, $BA, $1C, $1E, $43, $59, $29, $94, $21, $2C, $59, $D0, $1E, $26, $59, $DA, $73, $2D, $30, $B5, $2D, $59, $8C, $2D, $2E, $2B, $27, $59, $A8, $A7, $A6, $41, $7E, $73, $0C, $1A, $32, $97, $59, $D2, $BE, $C7, $1E, $59, $B4, $59, $DA, $30, $27, $59, $AE, $73, $1F, $22, $20, $2E, $2B, $A4, $C5, $21, $28, $30, $59, $DA, $59, $D2, $25, $2F, $1E, $59, $B6, $2C, $73, $26, $32, $D3, $A6, $22, $1E, $2C, $3E, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $39, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_192:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $D8, $59, $13, $1A, $22, $25, $59, $0F, $1A, $BA, $1C, $1E, $3E, $76, $7E, $73, $E6, $59, $29, $94, $21, $59, $2D, $21, $2B, $28, $2E, $20, $21, $59, $D8, $59, $2C, $DF, $26, $29, $2C, $73, $B5, $59, $D2, $BE, $2D, $B0, $27, $20, $59, $C7, $B9, $1A, $59, $03, $1E, $24, $2E, $59, $1C, $28, $2E, $25, $1D, $73, $27, $1A, $2F, $22, $20, $94, $1E, $59, $9B, $A8, $2D, $1A, $1B, $25, $32, $43, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $3B, $39, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_193:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $E6, $59, $20, $2B, $8C, $0A, $1A, $25, $32, $31, $28, $59, $02, $92, $25, $1E, $3E, $76, $7E, $73, $E6, $32, $59, $2C, $1A, $32, $59, $D8, $59, $0A, $B3, $C6, $59, $0A, $1A, $25, $32, $31, $28, $73, $B0, $1D, $59, $1A, $59, $CB, $A6, $1F, $2E, $25, $59, $E0, $1A, $29, $C7, $42, $59, $1D, $1E, $1E, $29, $73, $30, $B6, $B0, $27, $59, $D8, $59, $1C, $92, $25, $1E, $59, $DF, $25, $25, $2C, $41, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $35, $34, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_194:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $D8, $59, $19, $C8, $1A, $59, $13, $1E, $26, $CA, $3E, $76, $7E, $73, $E6, $59, $19, $C8, $1A, $59, $24, $B4, $20, $9F, $26, $59, $B5, $59, $B4, $73, $1C, $B1, $28, $2C, $41, $41, $41, $59, $D8, $59, $2B, $22, $2F, $A1, $8C, $D0, $1A, $73, $19, $C8, $1A, $2C, $59, $AD, $59, $97, $A0, $91, $28, $1D, $1D, $2C, $41, $7E, $73, $0F, $A6, $B1, $29, $2C, $59, $B6, $8B, $1C, $C7, $27, $1E, $1C, $2D, $A4, $DA, $73, $1A, $59, $1C, $A6, $2D, $8F, $41, $41, $41, $59, $2B, $28, $32, $1A, $25, $59, $2C, $1C, $90, $1A, $25, $3F, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $3C, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_195:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $E3, $59, $30, $B5, $21, $59, $DA, $59, $1E, $31, $29, $BB, $CE, $76, $06, $BA, $1C, $22, $1A, $59, $04, $D3, $94, $1E, $3F, $7E, $73, $00, $59, $29, $BA, $1C, $1E, $59, $C7, $1C, $1E, $59, $1F, $22, $25, $25, $A4, $30, $B6, $21, $59, $E0, $1A, $25, $2D, $21, $73, $8C, $CB, $A6, $41, $41, $41, $59, $1B, $2E, $2D, $59, $27, $28, $30, $3F, $59, $E6, $32, $73, $2C, $1A, $32, $59, $2C, $29, $22, $2B, $B6, $2C, $59, $DF, $25, $24, $59, $B6, $2C, $59, $B1, $25, $25, $2C, $43, $7E, $73, $00, $27, $1D, $59, $2D, $21, $91, $2D, $21, $A6, $1E, $8B, $D2, $BE, $C7, $1E, $73, $DF, $B6, $B3, $A8, $59, $E3, $41, $41, $41, $59, $1A, $59, $2F, $A6, $32, $73, $1C, $B0, $25, $25, $B3, $E0, $25, $9B, $1E, $41, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $3D, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_196:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $D8, $59, $06, $C8, $C7, $59, $0C, $B4, $1E, $2C, $3F, $76, $7E, $73, $08, $51, $2F, $1E, $59, $21, $A2, $1D, $59, $D8, $59, $06, $C8, $C7, $2C, $73, $8D, $CE, $D3, $25, $1E, $2C, $2C, $41, $41, $41, $59, $D2, $BE, $2D, $B0, $27, $20, $73, $1A, $98, $2E, $2D, $59, $26, $B5, $2C, $B3, $2B, $28, $9C, $59, $BE, $94, $3F, $7E, $73, $E8, $25, $25, $59, $27, $1E, $A4, $26, $C8, $1E, $59, $2D, $21, $93, $73, $B7, $59, $D3, $2B, $A5, $20, $2D, $21, $59, $DA, $59, $1C, $2B, $1A, $9C, $73, $2D, $21, $28, $D0, $59, $26, $B4, $1E, $2C, $59, $28, $29, $A5, $3E, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $3A, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_197:
db $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $42, $59, $0A, $28, $28, $BB, $40, $0B, $22, $26, $29, $1A, $21, $3E, $75, $00, $21, $42, $59, $0A, $32, $1D, $2B, $28, $20, $8B, $2C, $B0, $29, $3E, $76, $7E, $73, $00, $59, $1F, $A2, $D2, $BE, $59, $2F, $1E, $2C, $D0, $25, $42, $59, $D8, $32, $59, $2C, $1A, $32, $73, $C7, $B9, $2D, $21, $28, $D0, $59, $E1, $28, $59, $1C, $93, $59, $D2, $1A, $2B, $73, $E2, $25, $25, $59, $CE, $1A, $1C, $21, $59, $B6, $3E, $7E, $73, $59, $07, $28, $30, $59, $9F, $1E, $2C, $59, $35, $36, $34, $59, $2B, $DC, $1E, $1E, $2C, $59, $2C, $C4, $3F, $73, $88, $44, $59, $12, $C4, $2C, $59, $AC, $28, $1D, $73, $88, $89, $08, $51, $25, $25, $59, $2D, $1A, $24, $1E, $59, $26, $32, $59, $1C, $21, $93, $1C, $1E, $2C, $68, $7F
Message_198:
db $00, $21, $42, $59, $E0, $25, $25, $59, $2D, $21, $94, $8B, $DA, $28, $59, $96, $1D, $41, $75, $02, $28, $BE, $59, $96, $9C, $59, $22, $1F, $59, $E3, $51, $CD, $B4, $2D, $A6, $1E, $D3, $1E, $1D, $76, $B4, $59, $13, $B4, $20, $25, $1E, $8B, $BD, $29, $2C, $3E, $7E, $73, $13, $B4, $20, $25, $1E, $42, $59, $13, $B4, $20, $25, $1E, $3E, $59, $0A, $28, $28, $BB, $28, $40, $0B, $22, $26, $29, $1A, $21, $3E, $73, $43, $E6, $D0, $59, $8D, $D8, $59, $BD, $20, $22, $1C, $59, $30, $C8, $1D, $2C, $73, $2D, $21, $91, $13, $B4, $20, $25, $1E, $59, $1C, $CE, $94, $A4, $B0, $26, $D0, $25, $1F, $41, $7E, $73, $03, $28, $C0, $D3, $1E, $1A, $25, $59, $D8, $26, $3E, $7F
Message_199:
db $E6, $59, $BF, $D1, $2B, $28, $28, $26, $59, $B5, $59, $27, $28, $59, $26, $A6, $1E, $75, $20, $2B, $28, $30, $2D, $21, $59, $C6, $59, $D8, $59, $A2, $2D, $21, $41, $76, $12, $2D, $1E, $1E, $29, $A4, $B4, $59, $93, $1C, $22, $A3, $59, $BD, $20, $22, $1C, $42, $59, $B6, $7E, $73, $1B, $2B, $B4, $20, $2C, $59, $A8, $2D, $21, $59, $E1, $91, $B5, $59, $B0, $1D, $1D, $A5, $41, $73, $08, $27, $59, $B6, $2C, $59, $CB, $1D, $A1, $25, $22, $1E, $2C, $59, $D8, $59, $CB, $A6, $73, $DA, $59, $2B, $A7, $1E, $1A, $25, $59, $DB, $2E, $1E, $59, $A8, $26, $2C, $42, $59, $D0, $1C, $CE, $2D, $2C, $7E, $73, $BB, $27, $20, $59, $1C, $C7, $1C, $1E, $1A, $25, $A4, $1B, $32, $59, $27, $94, $2E, $CE, $41, $7F
Message_19A:
db $E6, $59, $30, $B4, $1D, $2C, $59, $C7, $1C, $1E, $59, $1C, $1A, $2B, $2B, $22, $A4, $2D, $21, $28, $D0, $75, $E1, $28, $59, $D2, $1A, $2B, $A4, $30, $B6, $21, $59, $1F, $1E, $94, $21, $A1, $90, $76, $25, $1E, $1A, $1F, $42, $59, $2E, $27, $B0, $27, $1D, $A6, $A4, $1B, $32, $59, $D8, $59, $A2, $2D, $21, $41, $7E, $73, $01, $2E, $2D, $59, $30, $B6, $21, $59, $D8, $59, $2B, $B5, $1E, $59, $C6, $59, $1D, $1A, $2B, $24, $27, $1E, $2C, $2C, $42, $73, $D8, $59, $2C, $24, $32, $59, $2D, $2E, $2B, $27, $A4, $1A, $20, $8F, $D3, $59, $D8, $26, $41, $73, $0D, $28, $30, $42, $59, $C7, $B9, $2D, $21, $28, $D0, $59, $E1, $28, $59, $1E, $26, $1B, $2B, $1A, $1C, $1E, $7E, $73, $D8, $59, $2C, $24, $32, $8B, $20, $22, $1F, $2D, $2C, $59, $BD, $32, $59, $2B, $22, $1D, $1E, $59, $D8, $73, $1C, $2E, $2B, $2B, $A3, $2C, $59, $C6, $59, $1F, $CE, $1E, $9F, $26, $41, $7F
Message_19B:
db $00, $59, $1B, $BA, $1D, $1E, $59, $98, $2B, $27, $59, $B4, $59, $2C, $B1, $9F, $30, $42, $59, $D8, $75, $0C, $1E, $1A, $9F, $30, $59, $01, $BA, $1D, $1E, $59, $C7, $1C, $1E, $59, $D1, $C7, $1E, $59, $B4, $76, $D8, $59, $21, $90, $2C, $59, $C6, $59, $1A, $59, $21, $A6, $28, $41, $7E, $73, $01, $2E, $2D, $59, $1D, $1A, $2B, $24, $27, $1E, $2C, $2C, $59, $1C, $25, $2E, $27, $20, $59, $DA, $59, $B6, $2C, $73, $1E, $1D, $20, $1E, $42, $59, $8C, $D8, $59, $21, $A6, $28, $59, $DF, $2C, $59, $BB, $D3, $41, $73, $0D, $28, $30, $42, $59, $D8, $59, $1B, $BA, $1D, $1E, $59, $DF, $B6, $2C, $42, $59, $1B, $2E, $2B, $22, $1E, $1D, $7E, $73, $97, $27, $1E, $94, $21, $59, $D8, $59, $E0, $B2, $C6, $73, $A8, $AC, $2D, $2D, $A0, $1A, $26, $1B, $B6, $22, $C7, $2C, $41, $7F
Message_19C:
db $05, $2B, $28, $26, $59, $1C, $2B, $32, $D3, $1A, $25, $59, $8C, $30, $94, $A6, $42, $59, $D8, $75, $19, $C8, $1A, $59, $1C, $2B, $1A, $1F, $2D, $A4, $30, $C7, $1D, $A6, $2C, $59, $2D, $21, $94, $76, $29, $22, $A6, $1C, $A4, $D8, $59, $2F, $1E, $22, $25, $59, $C6, $59, $CE, $1A, $25, $26, $2C, $41, $7E, $73, $E6, $22, $2B, $59, $30, $C8, $24, $2C, $59, $28, $29, $A5, $A4, $29, $94, $21, $2C, $59, $DA, $73, $29, $BA, $1C, $1E, $2C, $59, $2E, $27, $D0, $A5, $42, $59, $1B, $2E, $2D, $59, $91, $20, $CE, $94, $73, $1C, $28, $D3, $41, $7E, $73, $16, $21, $91, $1F, $BB, $30, $2C, $59, $2D, $21, $2B, $28, $2E, $20, $21, $59, $D8, $59, $30, $94, $A6, $73, $BD, $32, $59, $25, $1E, $1A, $1D, $59, $DA, $59, $2C, $1A, $25, $2F, $94, $22, $C7, $43, $59, $C8, $73, $2B, $2E, $B4, $41, $7F
Message_19D:
db $E6, $59, $B1, $25, $25, $2C, $59, $C6, $59, $06, $BA, $1C, $22, $1A, $59, $C7, $1C, $1E, $59, $1E, $1C, $21, $28, $1E, $1D, $75, $30, $B6, $21, $59, $DF, $2B, $26, $2D, $21, $59, $8C, $E0, $1A, $25, $2D, $21, $42, $59, $32, $1E, $2D, $76, $22, $1C, $1E, $59, $1F, $22, $25, $25, $A4, $D8, $22, $2B, $59, $21, $A2, $2D, $2C, $41, $7E, $73, $08, $27, $59, $D8, $22, $2B, $59, $20, $CE, $1E, $1D, $42, $59, $D8, $32, $59, $30, $A6, $1E, $59, $1D, $2B, $1A, $30, $27, $73, $DA, $59, $CB, $A6, $2C, $59, $2D, $21, $91, $A9, $33, $1E, $59, $D8, $26, $59, $A9, $26, $73, $30, $B6, $B0, $27, $41, $7E, $73, $0D, $28, $30, $42, $59, $D8, $22, $2B, $59, $25, $1E, $20, $1A, $1C, $32, $59, $B5, $59, $1B, $2E, $2D, $59, $1C, $28, $25, $1D, $73, $D3, $C7, $1E, $42, $59, $1A, $59, $29, $2B, $B5, $C7, $59, $A8, $59, $2D, $21, $28, $D0, $73, $E1, $28, $59, $D2, $2E, $20, $21, $2D, $59, $DA, $28, $59, $BF, $1C, $21, $41, $7F
Message_19E:
db $E6, $59, $A2, $2D, $21, $59, $2C, $B4, $20, $2C, $59, $C6, $59, $CB, $A6, $42, $75, $1B, $2E, $2B, $22, $A4, $1D, $1E, $1E, $29, $59, $B4, $59, $B6, $2C, $59, $2F, $1E, $B4, $2C, $41, $76, $02, $2B, $32, $D3, $1A, $25, $2C, $42, $59, $A8, $20, $A4, $B4, $59, $D8, $59, $93, $1C, $22, $A3, $7E, $73, $1F, $22, $CE, $2C, $42, $59, $21, $28, $25, $1D, $59, $D8, $59, $24, $1E, $32, $2C, $59, $DA, $59, $CE, $1A, $25, $26, $2C, $73, $97, $32, $C7, $1D, $41, $59, $01, $2E, $2D, $59, $CB, $A1, $9B, $1E, $2C, $59, $91, $1A, $73, $29, $2B, $22, $1C, $1E, $42, $59, $A8, $59, $D8, $59, $AC, $1D, $9D, $D0, $2C, $7E, $73, $2C, $1C, $94, $2D, $A6, $A4, $D8, $22, $2B, $59, $20, $22, $1F, $2D, $2C, $59, $1A, $1C, $2B, $28, $2C, $2C, $73, $D8, $59, $25, $90, $42, $59, $B0, $1D, $1D, $A0, $A9, $26, $59, $26, $C8, $2D, $1A, $25, $2C, $41, $7F
Message_19F:
db $00, $59, $21, $A6, $28, $59, $C7, $1C, $1E, $59, $2C, $1A, $22, $25, $A4, $D8, $59, $D0, $1A, $2C, $42, $75, $1B, $2E, $2D, $59, $1F, $94, $1E, $59, $2D, $2E, $2B, $27, $A4, $B0, $26, $59, $DA, $59, $2B, $2E, $B4, $42, $76, $1D, $1E, $1E, $29, $59, $B4, $59, $D8, $59, $BE, $1A, $9F, $30, $2C, $43, $7E, $73, $05, $2B, $28, $26, $59, $27, $28, $95, $59, $21, $A2, $2D, $59, $DA, $59, $1C, $2E, $2B, $D0, $1D, $73, $1C, $1A, $29, $2D, $8F, $42, $59, $0A, $32, $1D, $2B, $28, $20, $59, $27, $28, $30, $59, $2B, $22, $9D, $73, $D8, $59, $DF, $2F, $1E, $2C, $59, $C6, $59, $D8, $59, $00, $1B, $32, $2C, $2C, $41, $7E, $73, $08, $27, $59, $B0, $2C, $59, $2A, $2E, $1E, $D3, $59, $DA, $59, $1D, $1E, $1F, $32, $59, $D8, $59, $AC, $1D, $2C, $42, $73, $21, $1E, $59, $D0, $1E, $24, $2C, $59, $C2, $59, $20, $BB, $2B, $32, $42, $59, $1B, $2E, $2D, $59, $1A, $73, $CE, $2D, $2E, $2B, $27, $59, $DA, $59, $E1, $91, $DF, $2C, $59, $BB, $D3, $41, $7F
Message_1A0:
db $00, $21, $42, $59, $93, $28, $2D, $21, $A1, $D0, $1C, $CE, $2D, $59, $2C, $1C, $2B, $28, $25, $25, $3E, $75, $E6, $D0, $59, $93, $1C, $22, $A3, $59, $30, $2B, $B6, $B4, $20, $2C, $59, $21, $28, $25, $1D, $76, $26, $32, $D3, $A6, $22, $1E, $2C, $59, $BB, $27, $20, $59, $BB, $D3, $59, $DA, $59, $2D, $22, $BE, $41, $7E, $73, $12, $21, $8E, $08, $59, $DB, $93, $2C, $25, $94, $1E, $59, $B6, $2C, $59, $A8, $AC, $2D, $2D, $A5, $73, $30, $C8, $1D, $2C, $59, $A8, $59, $E3, $3F, $73, $7E, $73, $44, $59, $13, $2B, $93, $2C, $25, $94, $1E, $59, $D8, $59, $2C, $1C, $2B, $28, $25, $25, $73, $89, $11, $1E, $1A, $1D, $59, $29, $2B, $A7, $22, $28, $2E, $2C, $59, $2C, $1C, $2B, $28, $25, $25, $73, $89, $03, $28, $C0, $DA, $2E, $1C, $21, $59, $26, $32, $59, $D3, $2E, $1F, $1F, $71, $7F
Message_1A1:
db $15, $A6, $32, $59, $E0, $25, $25, $41, $59, $0B, $1E, $2D, $59, $2E, $2C, $59, $2E, $27, $2F, $1E, $22, $25, $59, $D8, $75, $D0, $1C, $CE, $2D, $2C, $59, $B0, $1D, $1D, $A0, $30, $B6, $B0, $27, $59, $2D, $B0, $2C, $76, $93, $1C, $22, $A3, $59, $2D, $1E, $31, $2D, $41, $7E, $73, $0B, $B5, $2D, $A0, $1C, $BB, $D0, $25, $32, $42, $59, $A8, $59, $D8, $D0, $73, $30, $C8, $1D, $2C, $59, $1C, $1A, $2B, $2B, $32, $59, $20, $CE, $91, $E0, $22, $20, $21, $2D, $41, $7F
Message_1A2:
db $E6, $59, $2C, $1C, $2B, $28, $25, $25, $59, $AE, $59, $97, $A0, $DB, $93, $2C, $25, $94, $1E, $1D, $41, $75, $00, $C2, $21, $A1, $29, $22, $1E, $1C, $1E, $59, $C6, $59, $0A, $1A, $25, $32, $31, $28, $2C, $76, $B0, $D3, $C8, $32, $59, $2B, $A7, $1E, $1A, $25, $1E, $1D, $41, $7E, $73, $E6, $D0, $59, $30, $C8, $1D, $2C, $59, $BD, $32, $59, $2C, $A6, $2F, $1E, $59, $E3, $73, $E0, $25, $25, $42, $59, $22, $1F, $59, $E3, $59, $21, $1E, $A4, $D8, $26, $41, $7F
Message_1A3:
db $08, $2D, $59, $D0, $1E, $26, $2C, $59, $E3, $51, $2F, $1E, $59, $1C, $28, $25, $25, $1E, $1C, $2D, $A4, $1A, $25, $25, $75, $D8, $59, $2C, $1C, $2B, $28, $25, $25, $2C, $59, $B4, $59, $D8, $59, $25, $8C, $C6, $76, $0A, $1A, $25, $32, $31, $28, $3E, $59, $E8, $59, $DB, $2E, $B9, $8D, $D8, $59, $21, $A6, $28, $41, $7F
Message_1A4:
db $E6, $59, $29, $2B, $B4, $1C, $1E, $2C, $2C, $43, $59, $2D, $1A, $24, $A0, $A9, $26, $59, $2E, $2C, $3E, $75, $16, $1E, $59, $D1, $28, $2E, $25, $1D, $59, $AD, $59, $D0, $A0, $B6, $59, $9B, $B4, $20, $41, $76, $E6, $59, $11, $22, $2F, $A1, $19, $C8, $1A, $2C, $59, $20, $2B, $28, $30, $59, $98, $25, $1D, $A6, $7E, $73, $1E, $1A, $1C, $21, $59, $1D, $1A, $32, $41, $59, $0D, $28, $30, $42, $59, $D8, $32, $51, $2F, $1E, $59, $D3, $28, $25, $A5, $73, $28, $2E, $2B, $59, $26, $28, $D3, $59, $29, $CE, $1C, $22, $28, $2E, $2C, $59, $2D, $CE, $1A, $2C, $2E, $CE, $3E, $73, $16, $21, $28, $59, $E2, $25, $25, $59, $CC, $2D, $1E, $1C, $2D, $59, $2E, $2C, $59, $27, $28, $30, $3F, $7F
Message_1A5:
db $E8, $59, $1C, $93, $2D, $59, $2C, $E2, $26, $42, $59, $1C, $93, $59, $E3, $3F, $59, $08, $2D, $51, $2C, $75, $27, $28, $59, $2C, $2E, $2B, $29, $2B, $B5, $1E, $43, $59, $D8, $59, $30, $94, $A6, $2C, $59, $21, $A6, $1E, $76, $8D, $2D, $CE, $1A, $9A, $2B, $28, $2E, $2C, $41, $7E, $73, $01, $2E, $2D, $59, $08, $51, $2F, $1E, $59, $21, $A2, $1D, $59, $30, $B0, $2C, $29, $A6, $2C, $59, $C6, $59, $D8, $73, $00, $1B, $32, $2C, $2C, $43, $59, $B4, $59, $2D, $21, $91, $1D, $1A, $2B, $24, $59, $29, $BA, $1C, $1E, $42, $59, $D8, $73, $1F, $25, $22, $29, $29, $A6, $2C, $59, $8D, $2C, $1A, $22, $1D, $59, $DA, $59, $97, $59, $B0, $1D, $1D, $A5, $41, $7E, $73, $08, $1F, $59, $E3, $59, $1C, $28, $2E, $25, $1D, $59, $1F, $B4, $1D, $59, $D8, $26, $42, $59, $29, $A6, $B1, $29, $2C, $73, $D8, $59, $30, $94, $A6, $2C, $59, $30, $28, $2E, $25, $1D, $59, $27, $28, $59, $BB, $27, $20, $A6, $73, $21, $28, $25, $1D, $59, $E3, $59, $96, $9C, $41, $7F
Message_1A6:
db $E6, $59, $29, $2B, $B4, $1C, $1E, $2C, $2C, $59, $BD, $32, $59, $97, $59, $AC, $27, $1E, $59, $A9, $26, $75, $2D, $B0, $2C, $59, $30, $C8, $25, $1D, $42, $59, $1B, $2E, $2D, $59, $21, $A1, $2C, $29, $22, $2B, $B6, $59, $AE, $76, $1F, $C4, $59, $27, $1E, $30, $59, $25, $22, $1F, $1E, $59, $B4, $59, $E3, $41, $7E, $73, $E6, $59, $19, $C8, $1A, $59, $0C, $1A, $2C, $24, $59, $1C, $1A, $2B, $2B, $22, $1E, $2C, $59, $21, $A6, $73, $2F, $28, $22, $1C, $1E, $42, $59, $21, $A1, $30, $B5, $9F, $26, $43, $59, $8C, $1A, $73, $29, $22, $1E, $1C, $1E, $59, $C6, $59, $28, $2E, $2B, $59, $21, $A2, $2D, $2C, $41, $7E, $73, $0F, $2B, $28, $2D, $1E, $1C, $2D, $59, $B6, $59, $E0, $25, $25, $42, $59, $1B, $2B, $1A, $2F, $1E, $59, $C7, $1E, $41, $7F
Message_1A7:
db $07, $1E, $32, $42, $59, $DB, $1A, $2F, $1E, $25, $A6, $3E, $59, $E6, $D0, $59, $26, $B4, $1E, $2C, $75, $8D, $D0, $1A, $25, $A4, $2D, $22, $20, $21, $2D, $41, $59, $16, $B6, $21, $C5, $11, $28, $9C, $76, $12, $22, $2B, $BB, $B4, $2C, $42, $59, $08, $59, $9F, $27, $2D, $59, $AD, $59, $D8, $7E, $73, $D3, $2B, $A5, $20, $2D, $21, $59, $DA, $59, $1B, $CE, $1A, $24, $59, $2D, $21, $2B, $28, $2E, $20, $21, $3E, $73, $16, $1E, $59, $06, $C8, $C7, $2C, $59, $27, $1E, $A4, $2D, $21, $91, $21, $A2, $2D, $32, $73, $BE, $91, $DA, $59, $1F, $2E, $1E, $25, $59, $2E, $2C, $43, $7E, $73, $C2, $B0, $27, $20, $59, $1E, $25, $D0, $59, $29, $1A, $9C, $2C, $59, $D8, $59, $29, $2E, $27, $1C, $21, $3E, $73, $01, $2B, $B3, $BE, $59, $1F, $22, $2F, $1E, $42, $59, $8C, $08, $51, $25, $25, $59, $28, $29, $A5, $73, $D8, $59, $DF, $32, $59, $A8, $59, $E3, $3E, $7F
Message_1A8:
db $07, $26, $26, $43, $59, $2D, $B0, $2C, $59, $B5, $59, $1A, $59, $D3, $1A, $2B, $2D, $42, $59, $1B, $2E, $2D, $59, $08, $75, $27, $1E, $A4, $1F, $22, $2F, $1E, $59, $11, $28, $9C, $59, $12, $22, $2B, $BB, $B4, $2C, $59, $DA, $76, $AB, $59, $D8, $59, $23, $28, $1B, $59, $9F, $27, $1E, $3E, $7E, $73, $0A, $1E, $1E, $29, $59, $2C, $A2, $1C, $B0, $27, $20, $42, $59, $1F, $2B, $22, $A5, $1D, $3E, $59, $13, $21, $28, $D0, $73, $2B, $28, $9C, $2C, $59, $1A, $2B, $A5, $51, $2D, $59, $AC, $B3, $DA, $59, $1B, $2E, $1D, $20, $1E, $73, $C7, $59, $D8, $22, $2B, $59, $28, $30, $27, $3E, $7F
Message_1A9:
db $00, $21, $3E, $59, $0D, $28, $30, $59, $2D, $21, $94, $8B, $E1, $91, $08, $51, $26, $59, $2D, $1A, $25, $24, $B4, $51, $75, $1A, $98, $2E, $2D, $3E, $59, $05, $22, $2F, $1E, $59, $11, $28, $9C, $59, $12, $22, $2B, $BB, $B4, $2C, $3E, $76, $13, $B0, $2C, $59, $B5, $59, $CE, $1A, $25, $B9, $B6, $3E, $7E, $73, $16, $B6, $21, $59, $2D, $B0, $2C, $42, $59, $08, $51, $2F, $1E, $59, $AC, $2D, $59, $8E, $D8, $73, $D3, $2B, $A5, $20, $2D, $21, $59, $08, $59, $27, $1E, $A4, $DA, $59, $1C, $2B, $1A, $9C, $59, $D8, $D0, $73, $26, $B4, $1E, $2C, $59, $28, $29, $A5, $3E, $7E, $73, $12, $2D, $8C, $96, $9C, $42, $59, $1F, $2B, $22, $A5, $1D, $43, $D8, $D0, $73, $D3, $C7, $1E, $2C, $59, $8D, $1A, $98, $2E, $2D, $59, $DA, $59, $1F, $1E, $1E, $25, $59, $D8, $73, $26, $B2, $C6, $59, $1A, $59, $DB, $2E, $1E, $59, $06, $C8, $C7, $3E, $7F
Message_1AA:
db $00, $21, $42, $59, $DB, $1A, $2F, $1E, $25, $A1, $A9, $26, $59, $97, $32, $C7, $1D, $41, $41, $41, $75, $E3, $59, $D3, $8C, $27, $A2, $59, $D8, $59, $13, $1E, $26, $29, $C8, $1A, $25, $76, $0F, $32, $2B, $1A, $26, $22, $1D, $42, $59, $1A, $59, $29, $BA, $1C, $1E, $59, $C6, $59, $97, $20, $B4, $27, $B4, $20, $2C, $41, $7E, $73, $E6, $59, $12, $21, $2B, $B4, $1E, $59, $C6, $59, $0E, $2B, $22, $20, $B4, $2C, $59, $25, $22, $1E, $2C, $59, $E0, $D3, $42, $73, $1A, $59, $29, $BA, $1C, $1E, $59, $C6, $59, $93, $1C, $22, $A3, $59, $CB, $A6, $41, $7E, $73, $0E, $27, $B9, $D8, $59, $2C, $26, $8E, $BD, $32, $59, $2D, $CE, $1A, $1D, $59, $B6, $2C, $73, $29, $94, $21, $2C, $42, $59, $A8, $59, $D8, $59, $D0, $1C, $CE, $2D, $2C, $59, $30, $B6, $B0, $27, $73, $8D, $B0, $1D, $1D, $A0, $A9, $26, $59, $D8, $59, $2E, $27, $30, $C8, $2D, $21, $32, $41, $7E, $73, $0B, $1E, $20, $A5, $1D, $2C, $59, $2C, $1A, $32, $59, $B6, $59, $20, $2B, $93, $2D, $2C, $59, $1A, $59, $CE, $25, $22, $1C, $73, $2D, $21, $91, $21, $28, $25, $1D, $2C, $59, $A8, $26, $59, $D3, $1E, $1A, $1D, $32, $59, $A7, $A0, $B4, $73, $2D, $B0, $2C, $59, $2E, $27, $D3, $1A, $95, $59, $CE, $1A, $25, $26, $41, $7F
Message_1AB:
db $E8, $51, $2F, $1E, $59, $9B, $1E, $59, $1F, $1A, $2B, $59, $DA, $59, $2D, $B0, $2C, $59, $29, $BA, $1C, $1E, $41, $75, $E6, $59, $12, $21, $2B, $B4, $1E, $59, $C6, $59, $0F, $28, $30, $A1, $25, $22, $1E, $2C, $59, $30, $B6, $B0, $27, $76, $D8, $59, $26, $28, $2E, $27, $2D, $8F, $2C, $42, $59, $E1, $A6, $1E, $59, $D8, $59, $25, $90, $7E, $73, $B6, $D0, $25, $1F, $59, $20, $2B, $28, $93, $2C, $59, $2E, $27, $1D, $A1, $B6, $2C, $59, $E0, $22, $20, $21, $2D, $41, $73, $13, $21, $A6, $1E, $42, $59, $E3, $59, $E2, $25, $25, $59, $1F, $B4, $1D, $59, $1A, $59, $2D, $CE, $1A, $2C, $2E, $CE, $73, $2D, $21, $91, $20, $2B, $93, $2D, $2C, $59, $D8, $59, $D3, $2B, $A5, $20, $2D, $21, $59, $DA, $7E, $73, $26, $28, $2F, $1E, $59, $A7, $A0, $D8, $59, $2E, $27, $26, $28, $2F, $1A, $95, $41, $73, $01, $2E, $2D, $59, $97, $DF, $CE, $42, $59, $2C, $2E, $1C, $21, $59, $CB, $A1, $B5, $73, $27, $A7, $A1, $20, $22, $2F, $A0, $1F, $CE, $1E, $25, $32, $41, $59, $0E, $27, $B9, $2D, $21, $28, $D0, $7E, $73, $30, $B6, $21, $59, $2E, $27, $DF, $2F, $A6, $B3, $CE, $D2, $25, $2F, $1E, $59, $A5, $1D, $2E, $CE, $41, $7F
Message_1AC:
db $E6, $59, $30, $94, $A6, $2C, $59, $C6, $59, $2D, $B0, $2C, $59, $CE, $1A, $25, $26, $59, $1A, $CE, $75, $C2, $59, $24, $B4, $1D, $59, $DA, $59, $28, $2E, $2D, $2C, $22, $1D, $A6, $2C, $59, $25, $22, $24, $1E, $59, $E3, $41, $76, $01, $1E, $32, $C7, $1D, $59, $2D, $B0, $2C, $59, $2C, $DF, $26, $29, $59, $25, $22, $1E, $2C, $7E, $73, $D8, $59, $12, $21, $2B, $B4, $1E, $59, $C6, $59, $16, $B5, $9F, $26, $42, $59, $E1, $A6, $1E, $73, $D8, $59, $1F, $25, $22, $29, $29, $A6, $2C, $59, $CE, $D3, $41, $73, $16, $B6, $21, $59, $D8, $26, $42, $59, $C7, $1E, $59, $BD, $32, $59, $2C, $E2, $26, $59, $D8, $7E, $73, $1D, $1E, $1E, $29, $1E, $D3, $59, $1C, $2E, $2B, $2B, $A3, $2C, $59, $8C, $2E, $27, $1C, $28, $2F, $A6, $73, $E1, $91, $D8, $59, $00, $1B, $32, $2C, $2C, $59, $B0, $9D, $41, $73, $01, $2E, $2D, $59, $DA, $59, $1C, $BA, $22, $26, $59, $D8, $26, $42, $59, $E3, $59, $BF, $D3, $7E, $73, $29, $94, $21, $59, $D8, $59, $DF, $32, $59, $A8, $DF, $2B, $1D, $59, $2D, $21, $2B, $28, $2E, $20, $21, $73, $D2, $BE, $59, $28, $2D, $21, $A1, $BE, $93, $2C, $43, $7F
Message_1AD:
db $0A, $32, $1D, $2B, $28, $20, $59, $DF, $2C, $59, $C7, $1C, $1E, $59, $1A, $59, $21, $A6, $28, $42, $75, $1C, $21, $28, $2C, $A0, $1B, $32, $59, $D8, $59, $0C, $1E, $1A, $9F, $30, $59, $01, $BA, $1D, $1E, $76, $B4, $59, $D8, $59, $0C, $1E, $1A, $9F, $30, $59, $C6, $59, $12, $B1, $9F, $30, $2C, $41, $7E, $73, $01, $2E, $2D, $59, $1A, $26, $1B, $B6, $22, $C7, $59, $1C, $BB, $2E, $1D, $A4, $B0, $2C, $59, $21, $A2, $2D, $42, $73, $8C, $21, $1E, $59, $1F, $1E, $25, $25, $59, $DA, $59, $D8, $59, $DB, $22, $9C, $2C, $59, $C6, $73, $06, $93, $C7, $9F, $2B, $1F, $42, $59, $24, $B3, $C6, $59, $2D, $B0, $A7, $1E, $2C, $41, $7E, $73, $16, $21, $A0, $0A, $32, $1D, $2B, $28, $20, $8B, $1D, $1E, $1E, $1D, $2C, $59, $2D, $2E, $2B, $27, $A4, $DA, $73, $1D, $1A, $2B, $24, $27, $1E, $2C, $2C, $42, $59, $D8, $59, $AC, $1D, $9D, $D0, $2C, $59, $1C, $92, $73, $B0, $26, $59, $B4, $DA, $59, $D8, $59, $00, $1B, $32, $2C, $2C, $43, $7E, $73, $18, $1E, $2D, $59, $A7, $A0, $21, $A6, $1E, $42, $59, $B0, $2C, $59, $21, $2E, $27, $20, $A1, $20, $CE, $30, $42, $73, $8C, $21, $1E, $59, $2B, $28, $D0, $59, $1A, $20, $8F, $42, $59, $27, $28, $59, $BB, $27, $20, $A6, $73, $1A, $59, $21, $A6, $28, $42, $59, $1B, $2E, $2D, $59, $1A, $59, $24, $B3, $C6, $59, $29, $22, $2B, $94, $1E, $2C, $41, $7F
Message_1AE:
db $0E, $21, $42, $59, $E1, $94, $8B, $2D, $B0, $2C, $3F, $59, $00, $59, $2B, $B4, $20, $3F, $59, $08, $75, $1F, $C4, $59, $B6, $59, $DF, $D1, $A4, $DC, $59, $C7, $59, $D8, $76, $00, $1B, $32, $2C, $2C, $1A, $25, $59, $12, $21, $C8, $1E, $41, $7E, $73, $08, $2D, $59, $20, $25, $22, $26, $26, $A6, $2C, $59, $D3, $2B, $93, $20, $1E, $25, $32, $42, $59, $25, $22, $24, $1E, $59, $B6, $73, $21, $28, $25, $1D, $2C, $59, $D2, $BE, $59, $B0, $1D, $1D, $A0, $CB, $A6, $41, $59, $08, $59, $AD, $73, $27, $28, $59, $2E, $D0, $59, $A8, $59, $B6, $42, $59, $1B, $2E, $2D, $59, $E3, $59, $26, $22, $20, $21, $2D, $41, $7E, $73, $13, $1A, $24, $1E, $59, $B6, $59, $DA, $59, $1A, $59, $23, $1E, $E0, $25, $A6, $42, $59, $2D, $21, $A6, $1E, $51, $2C, $73, $C7, $1E, $59, $27, $A2, $59, $D8, $59, $15, $22, $25, $BA, $20, $1E, $59, $C6, $59, $04, $1C, $21, $28, $1E, $2C, $42, $73, $E1, $28, $59, $1A, $29, $29, $2B, $1A, $B5, $1E, $2C, $59, $2C, $2E, $1C, $21, $59, $2D, $CE, $1A, $2C, $2E, $CE, $2C, $41, $7F
Message_1AF:
db $E6, $59, $05, $C8, $2D, $CE, $2C, $2C, $59, $C6, $59, $12, $1E, $1C, $CE, $2D, $2C, $59, $25, $22, $1E, $2C, $75, $1D, $1E, $1E, $29, $59, $30, $B6, $B0, $27, $59, $D8, $59, $00, $1B, $32, $2C, $2C, $42, $59, $D0, $1A, $25, $1E, $1D, $76, $1B, $32, $59, $93, $1C, $22, $A3, $59, $CB, $A6, $41, $7E, $73, $13, $28, $59, $28, $29, $A0, $B6, $2C, $59, $20, $94, $1E, $2C, $42, $59, $E3, $59, $BF, $D3, $73, $2E, $27, $B6, $1E, $59, $D8, $59, $04, $2C, $2C, $A5, $1C, $1E, $2C, $59, $C6, $59, $D8, $73, $13, $2B, $22, $A8, $1C, $1E, $59, $A9, $26, $59, $0A, $1A, $25, $32, $31, $28, $41, $7E, $73, $01, $2E, $2D, $59, $97, $DF, $CE, $42, $59, $A8, $59, $97, $32, $C7, $1D, $59, $D8, $73, $A8, $2D, $CE, $2C, $2C, $59, $25, $22, $1E, $2C, $59, $0A, $32, $1D, $2B, $28, $20, $42, $59, $D8, $73, $1F, $1A, $25, $25, $A0, $21, $A6, $28, $42, $59, $2D, $30, $B5, $2D, $A4, $1B, $32, $59, $20, $CE, $1E, $1D, $41, $7E, $73, $E6, $59, $0C, $92, $A1, $12, $30, $C8, $1D, $59, $B5, $59, $D8, $59, $C7, $25, $32, $73, $1B, $BA, $1D, $1E, $59, $2D, $21, $91, $1C, $93, $59, $1B, $CE, $1A, $24, $59, $B0, $2C, $59, $1C, $2E, $2B, $D0, $42, $73, $32, $1E, $2D, $59, $B6, $59, $CE, $D3, $2C, $59, $20, $2E, $1A, $2B, $1D, $A4, $1B, $32, $59, $DB, $22, $1A, $25, $2C, $42, $73, $D1, $2B, $B4, $1E, $2C, $59, $1B, $2E, $22, $25, $2D, $59, $1B, $32, $59, $D8, $59, $AC, $1D, $9D, $D0, $2C, $41, $7E, $73, $13, $28, $59, $1C, $BA, $22, $26, $59, $B6, $42, $59, $E3, $59, $BF, $D3, $59, $1C, $C7, $2A, $2E, $A6, $73, $1E, $1A, $1C, $21, $59, $1C, $B1, $25, $25, $A5, $20, $1E, $59, $8C, $2D, $21, $A0, $CE, $2D, $2E, $2B, $27, $73, $DA, $59, $E1, $A6, $1E, $59, $B6, $59, $8E, $97, $20, $93, $43, $7F
Message_1B0:
db $E6, $59, $12, $21, $2B, $B4, $1E, $59, $C6, $59, $0F, $28, $30, $A6, $3F, $59, $00, $59, $DB, $22, $9C, $32, $75, $29, $BA, $1C, $1E, $42, $59, $2D, $21, $91, $C7, $1E, $41, $59, $E6, $59, $1C, $1A, $2F, $1E, $2C, $76, $8D, $1F, $2E, $25, $25, $59, $C6, $59, $2C, $2E, $2B, $29, $2B, $B5, $1E, $2C, $41, $7E, $73, $E6, $32, $59, $2C, $1A, $32, $59, $D8, $59, $29, $94, $21, $59, $A8, $DF, $2B, $1D, $59, $B5, $73, $B0, $1D, $1D, $A5, $42, $59, $C7, $B9, $2B, $A7, $1E, $1A, $25, $A4, $DA, $59, $2D, $21, $28, $D0, $73, $E2, $25, $25, $B3, $DA, $59, $2D, $1A, $24, $1E, $59, $1A, $59, $25, $1E, $1A, $29, $59, $C6, $59, $1F, $1A, $B6, $21, $41, $7E, $73, $08, $2D, $8B, $C2, $59, $A8, $59, $D8, $59, $1F, $8F, $2D, $59, $C6, $59, $21, $A2, $2D, $41, $73, $E8, $51, $1D, $59, $97, $D3, $59, $DB, $2E, $D3, $59, $E3, $2B, $73, $B4, $D3, $B4, $1C, $2D, $2C, $42, $59, $DB, $1A, $2F, $1E, $25, $A6, $41, $7F
Message_1B1:
db $0C, $26, $26, $42, $59, $D8, $59, $2C, $BE, $25, $25, $59, $C6, $59, $11, $28, $9C, $59, $12, $22, $2B, $BB, $B4, $2C, $3E, $75, $0D, $28, $2D, $B0, $27, $20, $59, $1F, $2E, $1E, $25, $2C, $59, $1A, $59, $06, $C8, $C7, $59, $25, $22, $24, $1E, $76, $2D, $21, $28, $D0, $59, $21, $A2, $2D, $32, $59, $1C, $21, $2E, $27, $24, $2C, $59, $C6, $59, $D3, $C7, $1E, $41, $7E, $73, $E8, $51, $25, $25, $59, $1F, $B4, $1D, $59, $D8, $26, $59, $2C, $1C, $94, $2D, $A6, $1E, $1D, $73, $1A, $2B, $C4, $59, $21, $A6, $1E, $42, $59, $1B, $2E, $2D, $59, $25, $22, $1F, $2D, $B3, $D8, $26, $3F, $73, $13, $21, $94, $8B, $93, $28, $2D, $21, $A1, $26, $94, $2D, $A6, $41, $7E, $73, $0E, $27, $B9, $D2, $BE, $C7, $1E, $59, $30, $B6, $21, $59, $CE, $1A, $25, $59, $CB, $A6, $73, $1C, $28, $2E, $25, $1D, $59, $26, $28, $2F, $1E, $59, $2D, $21, $28, $D0, $59, $97, $1A, $2E, $2D, $22, $1E, $2C, $41, $59, $06, $28, $2D, $73, $1A, $59, $0F, $28, $30, $A1, $06, $BB, $2F, $1E, $59, $21, $90, $32, $3F, $7F
Message_1B2:
db $E8, $59, $29, $25, $93, $27, $B3, $DA, $59, $21, $1E, $1A, $1D, $59, $B4, $DA, $59, $D8, $75, $12, $21, $2B, $B4, $1E, $59, $C6, $59, $0F, $28, $30, $A6, $3F, $76, $07, $1E, $21, $42, $59, $AC, $28, $1D, $59, $25, $2E, $9C, $3E, $7E, $73, $E6, $59, $1F, $BB, $C8, $2C, $59, $9F, $27, $2D, $59, $1A, $25, $DF, $32, $2C, $59, $D0, $1E, $26, $41, $41, $41, $73, $CE, $1A, $25, $42, $59, $22, $1F, $59, $E3, $59, $1C, $94, $1C, $21, $59, $26, $32, $59, $1D, $2B, $22, $1F, $2D, $41, $73, $00, $27, $1D, $59, $2D, $21, $28, $D0, $59, $11, $28, $9C, $59, $12, $22, $2B, $BB, $B4, $2C, $3F, $59, $7E, $73, $07, $1E, $1A, $2F, $32, $59, $1A, $2C, $59, $98, $2E, $25, $1D, $A6, $2C, $41, $59, $16, $B6, $21, $C5, $D8, $73, $0F, $28, $30, $A1, $06, $BB, $2F, $1E, $42, $59, $E3, $CD, $C5, $C6, $59, $25, $2E, $9C, $41, $7F
Message_1B3:
db $0E, $21, $28, $40, $21, $28, $3E, $59, $16, $1E, $25, $25, $42, $59, $BB, $28, $24, $59, $E1, $28, $59, $D3, $2E, $26, $95, $1D, $75, $B4, $DA, $59, $26, $32, $59, $03, $CE, $1A, $26, $59, $07, $2E, $2D, $3E, $59, $02, $21, $1E, $9C, $B4, $20, $76, $C5, $D8, $59, $04, $C7, $59, $00, $1B, $32, $2C, $2C, $42, $59, $8D, $E0, $3F, $7E, $73, $08, $51, $26, $59, $0C, $1A, $CA, $42, $59, $32, $1E, $2C, $42, $59, $2D, $21, $91, $0C, $1A, $CA, $3E, $73, $16, $1E, $51, $2F, $1E, $59, $1C, $2B, $28, $2C, $2C, $A4, $29, $94, $21, $2C, $59, $97, $A8, $1E, $59, $B4, $73, $07, $28, $BB, $1D, $2B, $2E, $26, $43, $59, $C8, $59, $DF, $2C, $59, $B6, $59, $0B, $1A, $1B, $2B, $32, $27, $27, $1A, $3F, $7E, $73, $07, $1E, $21, $42, $59, $E3, $59, $30, $A6, $1E, $59, $1A, $59, $1B, $B6, $59, $C6, $59, $1A, $59, $29, $1E, $D3, $73, $C7, $59, $26, $32, $59, $1B, $2B, $28, $28, $26, $59, $2B, $28, $2E, $2D, $1E, $42, $59, $1B, $2E, $2D, $59, $08, $59, $D0, $1E, $73, $E3, $2F, $1E, $59, $9B, $1E, $59, $1A, $59, $BB, $27, $20, $59, $DF, $32, $3E, $7E, $73, $44, $59, $0B, $C7, $20, $59, $2D, $22, $BE, $59, $27, $28, $59, $D0, $1E, $42, $59, $0C, $1A, $CA, $3E, $73, $89, $16, $21, $91, $B5, $59, $2D, $B0, $2C, $59, $29, $BA, $1C, $1E, $3F, $73, $89, $08, $51, $25, $25, $59, $9B, $1E, $59, $96, $9C, $59, $25, $94, $A6, $41, $71, $7F
Message_1B4:
db $07, $1A, $3E, $59, $E8, $59, $9F, $59, $CE, $BE, $26, $97, $2B, $59, $BE, $3E, $75, $06, $2E, $1E, $2C, $2C, $59, $8E, $2D, $21, $91, $1C, $AE, $B3, $1A, $2B, $C4, $76, $25, $1E, $1F, $2D, $59, $93, $59, $22, $26, $29, $CE, $2C, $2C, $22, $C7, $41, $7E, $73, $0D, $28, $30, $59, $08, $51, $2F, $1E, $59, $D0, $2D, $59, $DC, $59, $D1, $28, $29, $59, $21, $A6, $1E, $42, $73, $9E, $2F, $B3, $B4, $DA, $59, $1D, $CE, $1A, $26, $2C, $59, $B4, $D3, $1E, $1A, $1D, $73, $C6, $59, $1C, $2B, $1A, $2C, $B0, $27, $20, $59, $1B, $2B, $28, $28, $26, $2C, $41, $7E, $73, $05, $1E, $1E, $25, $59, $1F, $CE, $1E, $59, $DA, $59, $25, $1E, $2D, $59, $BE, $59, $29, $28, $24, $1E, $73, $1A, $2B, $C4, $59, $B4, $59, $E3, $2B, $59, $26, $B4, $1D, $43, $73, $B6, $59, $1C, $28, $2E, $25, $1D, $59, $97, $59, $1F, $2E, $27, $3E, $7E, $73, $44, $59, $12, $2E, $CE, $42, $59, $D1, $28, $30, $59, $BE, $59, $1A, $59, $1D, $CE, $1A, $26, $41, $73, $89, $07, $28, $30, $59, $9F, $1E, $2C, $59, $2D, $B0, $2C, $59, $30, $C8, $24, $3F, $73, $89, $0C, $1A, $32, $97, $59, $D2, $BE, $59, $28, $2D, $21, $A1, $2D, $22, $BE, $41, $71, $7F
Message_1B5:
db $13, $B0, $2C, $59, $25, $B6, $2D, $25, $1E, $59, $B1, $2F, $A5, $3F, $59, $08, $59, $1C, $8E, $B6, $59, $26, $32, $75, $03, $CE, $1A, $26, $59, $07, $2E, $2D, $43, $59, $C2, $59, $2C, $DC, $A1, $C8, $22, $20, $B4, $1A, $25, $42, $76, $1B, $2E, $2D, $59, $B6, $59, $AB, $2C, $59, $D8, $59, $29, $28, $B4, $2D, $59, $1A, $1C, $2B, $28, $2C, $2C, $41, $7E, $73, $07, $A6, $1E, $42, $59, $08, $59, $2D, $2E, $20, $59, $91, $D8, $59, $1E, $1D, $20, $1E, $2C, $59, $C6, $73, $E3, $2B, $59, $26, $B4, $1D, $42, $59, $2C, $29, $B4, $27, $B3, $1D, $CE, $1A, $26, $2C, $59, $2D, $21, $94, $73, $26, $B2, $2B, $A7, $1E, $1A, $25, $59, $D2, $BE, $2D, $B0, $27, $20, $59, $2E, $D0, $1F, $2E, $25, $41, $7E, $73, $09, $2E, $D3, $59, $97, $DF, $CE, $40, $D8, $59, $04, $C7, $59, $00, $1B, $32, $2C, $2C, $73, $2D, $1A, $24, $1E, $2C, $59, $B6, $2C, $59, $DA, $25, $25, $42, $59, $A7, $A0, $B4, $59, $2C, $25, $1E, $1E, $29, $41, $73, $16, $1E, $22, $2B, $1D, $59, $D3, $2E, $1F, $1F, $59, $B1, $29, $29, $A5, $2C, $59, $21, $A6, $1E, $41, $7F
Message_1B6:
db $0E, $28, $21, $42, $59, $08, $59, $1C, $93, $59, $2C, $A5, $D0, $59, $B6, $43, $75, $2D, $21, $91, $29, $A5, $1D, $93, $2D, $59, $E3, $59, $AD, $59, $2D, $21, $A6, $1E, $41, $76, $0F, $A6, $1F, $1E, $1C, $2D, $59, $A8, $59, $1D, $CE, $1A, $26, $40, $E0, $1A, $2F, $B4, $20, $3E, $7E, $73, $02, $BB, $D0, $59, $2D, $21, $28, $D0, $59, $1E, $32, $1E, $2C, $42, $59, $07, $A6, $28, $41, $59, $0B, $1E, $2D, $51, $2C, $73, $D0, $1E, $59, $E1, $91, $D0, $1C, $CE, $2D, $2C, $59, $8D, $25, $2E, $2B, $24, $B3, $B4, $73, $2D, $21, $91, $27, $28, $20, $20, $B4, $59, $C6, $59, $E3, $2B, $2C, $41, $7F
Message_1B7:
db $07, $2E, $21, $42, $59, $27, $28, $59, $2C, $29, $1A, $2B, $24, $59, $B4, $59, $2C, $22, $20, $21, $2D, $41, $75, $0D, $28, $59, $0F, $A5, $1D, $93, $2D, $42, $59, $27, $28, $59, $1D, $CE, $1A, $26, $42, $59, $2C, $C8, $2B, $32, $3E, $76, $01, $2E, $2D, $59, $21, $1E, $32, $42, $59, $2B, $28, $1A, $26, $59, $D8, $59, $00, $1B, $32, $2C, $2C, $59, $1A, $59, $1B, $B6, $41, $7E, $73, $08, $51, $26, $59, $2C, $2E, $CD, $E3, $51, $25, $25, $59, $2C, $1C, $2B, $28, $2E, $27, $20, $1E, $59, $C7, $1E, $59, $DC, $73, $A7, $A3, $2E, $1A, $25, $25, $32, $43, $59, $00, $27, $1D, $59, $E1, $A0, $E3, $59, $9F, $42, $73, $08, $51, $25, $25, $59, $97, $59, $21, $A6, $1E, $42, $59, $DF, $B6, $B4, $20, $41, $7F
Message_1B8:
db $0E, $21, $28, $3E, $59, $02, $2E, $2B, $22, $28, $2E, $2C, $59, $1A, $98, $2E, $2D, $59, $26, $32, $59, $25, $B6, $2D, $25, $1E, $75, $1D, $CE, $1A, $26, $40, $E0, $1A, $2F, $B3, $1A, $1C, $2D, $42, $59, $8D, $E0, $3F, $76, $0B, $B5, $2D, $A0, $1C, $BB, $D0, $42, $59, $07, $A6, $28, $41, $7E, $73, $12, $1E, $1E, $42, $59, $B4, $59, $D8, $59, $04, $C7, $59, $00, $1B, $32, $2C, $2C, $42, $59, $2D, $21, $A6, $1E, $73, $8D, $2D, $21, $CE, $1E, $59, $29, $A5, $1D, $93, $2D, $2C, $42, $59, $1A, $2B, $2D, $22, $1F, $1A, $1C, $2D, $2C, $73, $25, $1E, $1F, $2D, $59, $97, $B0, $27, $1D, $59, $1B, $32, $59, $D8, $59, $06, $28, $1D, $9D, $D0, $2C, $41, $7E, $73, $16, $21, $A0, $E3, $59, $20, $94, $21, $A1, $1E, $1A, $1C, $21, $59, $29, $A5, $1D, $93, $2D, $42, $73, $D8, $32, $59, $CE, $2C, $C7, $94, $1E, $59, $30, $B6, $21, $59, $E3, $2B, $59, $2C, $29, $22, $2B, $B6, $42, $73, $B4, $2F, $28, $24, $B3, $1D, $CE, $1A, $26, $2C, $59, $C6, $59, $D8, $59, $29, $92, $43, $7E, $73, $13, $21, $94, $8B, $E1, $A6, $1E, $59, $08, $59, $9B, $1E, $59, $B4, $42, $59, $21, $1E, $25, $29, $B4, $20, $73, $DA, $59, $27, $1A, $2F, $22, $20, $94, $1E, $59, $D8, $59, $1D, $CE, $1A, $26, $2C, $59, $90, $73, $2B, $A7, $1E, $1A, $25, $59, $D0, $1C, $CE, $2D, $2C, $59, $C6, $59, $D8, $59, $29, $92, $41, $7E, $73, $01, $2E, $2D, $59, $D8, $59, $20, $2B, $8C, $29, $2B, $22, $33, $1E, $3F, $59, $0E, $27, $1C, $1E, $73, $E3, $51, $2F, $1E, $59, $CC, $2F, $A0, $E3, $2B, $D0, $25, $1F, $42, $73, $D8, $59, $0C, $92, $A1, $12, $30, $C8, $1D, $59, $1A, $DF, $B6, $2C, $41, $7E, $73, $13, $21, $91, $1B, $BA, $1D, $1E, $8B, $B0, $1D, $1D, $A0, $1D, $1E, $1E, $29, $59, $B4, $59, $D8, $73, $00, $1B, $32, $2C, $2C, $42, $59, $8C, $C7, $B9, $D8, $59, $C7, $1E, $59, $30, $B6, $21, $73, $D8, $59, $29, $A5, $1D, $93, $2D, $2C, $59, $1C, $93, $59, $1A, $DF, $24, $A0, $B6, $41, $7E, $73, $12, $28, $42, $59, $2D, $B0, $27, $24, $59, $C6, $59, $D8, $D0, $59, $25, $B6, $2D, $25, $1E, $59, $1D, $CE, $1A, $26, $2C, $73, $1A, $2C, $59, $D3, $1E, $29, $29, $B3, $D3, $C7, $1E, $2C, $59, $DA, $59, $E3, $2B, $73, $9D, $2D, $B4, $32, $3E, $7F
Message_1B9:
db $0C, $32, $59, $1D, $1E, $1E, $29, $1E, $D3, $59, $20, $2B, $94, $B6, $2E, $1D, $1E, $42, $59, $21, $A6, $28, $41, $75, $01, $1E, $1C, $1A, $2E, $D0, $59, $C6, $59, $E3, $2B, $59, $2F, $1A, $BB, $2B, $42, $76, $13, $1A, $22, $25, $59, $0F, $1A, $BA, $1C, $1E, $59, $2C, $B0, $27, $1E, $2C, $59, $C7, $1C, $1E, $59, $26, $C8, $1E, $41, $7E, $73, $16, $1E, $59, $03, $1E, $24, $2E, $59, $28, $E0, $59, $E3, $59, $1A, $59, $1D, $1E, $1B, $2D, $28, $2E, $2B, $73, $21, $28, $BE, $59, $DF, $2C, $59, $B4, $59, $2D, $2E, $2B, $26, $28, $22, $25, $59, $1A, $1F, $2D, $A6, $73, $0A, $32, $1D, $2B, $28, $20, $8B, $BE, $1D, $1D, $25, $B4, $20, $41, $7E, $73, $01, $2E, $2D, $59, $30, $B6, $21, $59, $D8, $59, $0C, $28, $25, $9F, $2B, $26, $59, $1C, $1A, $25, $BE, $1D, $42, $73, $29, $1E, $1A, $1C, $1E, $59, $CE, $2D, $2E, $2B, $27, $2C, $59, $DA, $59, $28, $2E, $2B, $59, $B1, $25, $25, $2C, $42, $73, $2D, $21, $93, $24, $2C, $59, $DA, $59, $E3, $3E, $7F
Message_1BA:
db $00, $21, $42, $59, $E3, $59, $29, $25, $93, $59, $DA, $59, $21, $1E, $1A, $1D, $59, $C7, $DF, $2B, $1D, $42, $75, $32, $1E, $2C, $3F, $59, $E6, $59, $27, $1E, $31, $2D, $59, $2D, $21, $CE, $91, $BB, $28, $26, $2C, $76, $B4, $59, $0A, $1A, $25, $32, $31, $28, $59, $02, $92, $25, $1E, $41, $7E, $73, $08, $51, $2F, $1E, $59, $2D, $1A, $24, $A0, $D8, $59, $25, $22, $97, $2B, $2D, $32, $59, $C6, $73, $BD, $2B, $24, $B3, $D8, $59, $1C, $92, $25, $1E, $59, $C7, $59, $E3, $2B, $59, $BD, $29, $41, $73, $01, $1E, $DF, $CE, $59, $B6, $2C, $59, $2C, $B1, $9F, $30, $2C, $59, $2B, $2E, $27, $59, $1D, $1E, $1E, $29, $41, $7E, $73, $12, $1E, $1E, $24, $59, $D8, $59, $0C, $1E, $1A, $9F, $30, $59, $01, $BA, $1D, $1E, $59, $2D, $21, $A6, $1E, $42, $73, $25, $1E, $20, $A5, $1D, $2C, $59, $2C, $1A, $32, $59, $B6, $59, $21, $28, $25, $1D, $2C, $59, $CB, $A1, $1F, $B6, $73, $A8, $59, $E3, $2B, $59, $2A, $2E, $1E, $D3, $41, $7F
Message_1BB:
db $00, $21, $28, $32, $42, $59, $26, $94, $1E, $32, $3E, $59, $E8, $51, $CD, $BB, $28, $24, $B4, $51, $75, $A8, $59, $D8, $59, $0F, $22, $2B, $94, $1E, $59, $0A, $B4, $20, $42, $59, $1E, $21, $3F, $76, $16, $1E, $25, $25, $42, $59, $08, $59, $1C, $93, $51, $2D, $59, $21, $1E, $25, $29, $59, $E3, $59, $2D, $21, $A6, $1E, $41, $7E, $73, $01, $2E, $2D, $59, $08, $59, $1C, $93, $59, $2D, $1E, $25, $25, $59, $E3, $59, $2D, $B0, $2C, $59, $D8, $73, $0F, $22, $2B, $94, $1E, $59, $0A, $B3, $B1, $1D, $59, $93, $59, $28, $25, $1D, $59, $2C, $B0, $29, $42, $73, $21, $A6, $1E, $59, $B4, $59, $D8, $59, $1A, $1B, $32, $2C, $2C, $59, $D2, $BE, $E1, $A6, $1E, $41, $7E, $73, $08, $1F, $59, $E3, $51, $CD, $BB, $28, $24, $B4, $51, $59, $DA, $59, $1F, $B4, $1D, $59, $B0, $26, $42, $73, $2D, $21, $94, $8B, $1A, $59, $AC, $28, $1D, $59, $29, $BA, $1C, $1E, $59, $DA, $59, $D3, $1A, $2B, $2D, $41, $7F
db $FF ; end of message pointers checks
print "End of expanded dialogue ", pc
assert pc() <= $2FFFFF

1876
Core/messages.org Normal file

File diff suppressed because it is too large Load Diff

1212
Core/messages_es.org Normal file

File diff suppressed because it is too large Load Diff

440
Core/music_macros.asm Normal file
View File

@@ -0,0 +1,440 @@
; ==============================================
; 1/4 = $48
; 1/4 double = $6C
; 1/4 triplet = $30
; 1/8 = $24
; 1/8 double = $36
; 1/8 triplet = $18
; 1/16 = $12
; 1/16 double = $1B
; 1/32 = $09
; db C4, !Tie, !Tie, !Tie : whole note (1/1)
; db C4, !Tie : half note (1/2)
!4th = $48
!4thD = $6C
!4thT = $30
!8th = $24
!8thD = $36
!8thT = $18
!16th = $12
!16thD = $1B
!32nd = $09
; Note Parameters ($01-$7F)
; [xy]
; When $xy &lt; $80
; $x = Duration Rate (0-7)
; $y = Velocity Rate (0-15)
; VByte itself means the length of the following note
; (48 = quarter note, usually).
macro SetDuration(v)
db <v>
endmacro
; n default is $7F
macro SetDurationN(v, n)
db <v>, <n>
endmacro
; ==============================================
; N-SPC Instruments
; 00 Noise
; 01 Rain
; 02 Tympani
; 03 Square wave
; 04 Saw wave
; 05 Sine wave (clink)
; 06 Wobbly lead
; 07 Compound saw wave
; 08 Tweet
; 09 Strings A
; 0A Strings B
; 0B Trombone
; 0C Cymbal
; 0D Ocarina
; 0E Chime
; 0F Harp
; 10 Splash
; 11 Trumpet
; 12 Horn
; 13 Snare A
; 14 Snare B
; 15 Choir
; 16 Flute
; 17 Oof
; 18 Piano
macro SetInstrument(v)
db $E0, <v>
endmacro
macro Tympani()
%SetInstrument($02)
endmacro
macro Trombone()
%SetInstrument($0B)
endmacro
macro Ocarina()
%SetInstrument($0D)
endmacro
macro Harp()
%SetInstrument($0F)
endmacro
macro Splash()
%SetInstrument($10)
endmacro
macro Trumpet()
%SetInstrument($11)
endmacro
macro Horn()
%SetInstrument($12)
endmacro
macro Snare()
%SetInstrument($13)
endmacro
macro Choir()
%SetInstrument($15)
endmacro
macro Flute()
%SetInstrument($16)
endmacro
macro Piano()
%SetInstrument($18)
endmacro
macro Cymbal()
%SetInstrument($0C)
endmacro
macro Strings()
%SetInstrument($09)
endmacro
macro Sawtooth()
%SetInstrument($04)
endmacro
macro Sine()
%SetInstrument($05)
endmacro
; ==============================================
macro SetChannelVolume(v)
db $ED, <v>
endmacro
macro SetMasterVolume(v)
db $E5, <v>
endmacro
macro SetTempo(v)
db $E7, <v>
endmacro
; - Play block $yyxx for $zz+1 times.
; - Subroutine call cannot be nested.
; - See also $00
; The block $yyxx is played zz + 1 times. Subroutines cannot be nested.
macro CallSubroutine(addr, repeat)
db $EF
dw <addr>
db <repeat>
endmacro
; Set the left and right position of the sound.
; The range of values is as narrow as 0 to 20
; (the actual setting ratio is defined in the internal table).
; Depending on the version, it depends on whether the large value is left or right.
; The upper 2 bits are used for phase inversion.
; Lower-5bit for pan value (0-20), higher-2bit is used for phase reverse switch.
macro SetPan(v)
db $E1, <v>
endmacro
; The position of the sound fades from the current value to yy over xx time.
macro PanFade(length, dest)
db $E2, <length>, <dest>
endmacro
; Enables vibrato (pitch fluctuation / pitch swing).
; Set zz-sized vibrato at yy speed after xx time.
macro VibratoOn(delay, rate, depth)
db $E3, <delay>, <rate>, <depth>
endmacro
macro VibratoOff()
db $E4
endmacro
; The volume of the entire song fades from the current value to yy over xx time.
macro MasterVolumeFade(length, dest)
db $E6, <length>, <dest>
endmacro
; Specifies the playing speed of the song.
; Value of about 24/60 is written.
macro TempoFade(length, dest)
db $E8, <length>, <dest>
endmacro
; Raises the playing pitch of all channels by xx
; (negative numbers can be specified).
macro GlobalTranspose(tone)
db $E9, <tone>
endmacro
; Raises the playing pitch of a single channel by xx
; (negative numbers can also be specified).
macro ChannelTranspose(tone)
db $EA, <tone>
endmacro
; Enable tremolo (volume fluctuation).
; Set the tremolo of the size of zz to be applied at the speed of yy after xx time.
macro TremoloOn(delay, rate, depth)
db $EB, <delay>, <rate>, <depth>
endmacro
macro TremoloOff()
db $EC
endmacro
macro ChannelVolumeFade(length, dest)
db $EE, <length>, <dest>
endmacro
; After temporarily setting the vibrato depth to 0,
; it will smoothly return to the original value over xx time.
macro VibratoFade(length)
db $F0, <length>
endmacro
; Specifies that subsequent sounds will be
; "higher by zz over yy time after xx time."
; zz is a semitone unit, and you can specify a negative number.
macro PitchEnvelopeTo(delay, length, key)
db $F1, <delay>, <length>, <key>
endmacro
; Specifies that subsequent notes will be
; "played at a pitch that is zz higher than normal,
; and will return to normal pitch over yy time after xx time."
; zz is a semitone unit, and you can specify a negative number.
macro PitchEnvelopeFrom(delay, length, key)
db $F2, <delay>, <length>, <key>
endmacro
macro PitchEnvelopeOff()
db $F3
endmacro
; Change the pitch slightly.
; Only positive numbers can be specified, so the pitch cannot be lowered.
; xx = Unsigned. Make the pitch xx/256 semitones higher.
macro Tuning(v)
db $F4, <v>
endmacro
; Specifies the channel and volume at which echo is enabled.
; The value set in the register remains the same.
; xx = Echo Switch (EON)
; yy = Echo Left Volume (EVOL (L))
; zz = Echo Right Volume (EVOL (R))
macro EchoVBits(switch, left, right)
db $F5, <switch>, <left>, <right>
endmacro
macro EchoOff()
db $F6
endmacro
macro EchoParams(delay, feedback, filter)
db $F7, <delay>, <feedback>, <filter>
endmacro
macro EchoVolumeFade(length, left, right)
db $F8, <length>, <left>, <right>
endmacro
; This VCMD is handled at different timing than other VCMDs.
; utter note $90, (wait), set instrument to $01, utter note $92
; $90, $e0 $01, $92
; utter note $90 then change the key immediately to note $91, (wait),
; utter note $92.
; $90, $f9 $00 $01 $91, $92
; utter note $90 then change the key immediately to note $91, (wait),
; set instrument to $01, utter note $92.
; $90, $f9 $00 $01 $91, $e0 01, $92
; <weird example> utter note $90, (wait), set instrument to $01,
; (pitch slide vcmd appears but note $90 has been end), utter note $92.
; $90, $e0 01, $f9 $00 $01 $91, $92
; Smoothly changes the pitch of the sound being pronounced.
; After xx time from play, it will be changed to the zz pitch
; (absolute designation) over yy time.
; If you want to raise or lower the sound in the middle of one note,
; write this command continuously.
; If the pronunciation time is long, you can write it with Thai.
; Normally, after one Note, it waits for the length of the note
; and then processes the next byte, but only this command
; is read and processed immediately.
macro PitchSlide(delay, length, note)
db $F9, <delay>, <length>, <note>
endmacro
; Determines the correspondence between the percussion value and the sound you hear.
macro PercussionPatchBass(instrument)
db $FA, <instrument>
endmacro
; ==============================================
macro PlayQuarterNotes(...)
if sizeof(...) > 0
db !4th, <...>
else
db !4th
endif
endmacro
macro PlayEighthNotes(...)
if sizeof(...) > 0
db !8th, <...>
else
db !8th
endif
endmacro
macro PlayHalfNotes(...)
if sizeof(...) > 0
db !4th, <...>
else
db !4th
endif
; db !4th, <note>, $C8
endmacro
macro SustainNoteN(note, num)
db note
if num > 1
db $C8
%SustainNoteN(note, num - 1)
endif
endmacro
End = $00
Tie = $C8
Rest = $C9
; Percussion Note ($CA-DF)
; VByte itself means percussion note (#).
; Relations between percussion note and SRCN depends on $FA.
; By default, percussion uses the same instrument set as the song,
; and all percussion is keyed on with a note of $A4.
; The starting ID to use for all channels can be redefined by VCMD $FA.
; =========================================================
; Tone Map
;
; C C+ D D+ E F F+ G G+ A A+ B
; Oc1 80 81 82 83 84 85 86 87 88 89 8A 8B
; Oc2 8C 8D 8E 8F 90 91 92 93 94 95 96 97
; Oc3 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3
; Oc4 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
; Oc5 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB
; Oc6 BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7
C1 = $80
C1s = $81
D1 = $82
D1s = $83
E1 = $84
F1 = $85
F1s = $86
G1 = $87
G1s = $88
A1 = $89
A1s = $8A
B1 = $8B
C2 = $8C
C2s = $8D
D2 = $8E
D2s = $8F
E2 = $90
F2 = $91
F2s = $92
G2 = $93
G2s = $94
A2 = $95
A2s = $96
B2 = $97
C3 = $98
C3s = $99
D3 = $9A
D3s = $9B
E3 = $9C
F3 = $9D
F3s = $9E
G3 = $9F
G3s = $A0
A3 = $A1
A3s = $A2
B3 = $A3
C4 = $A4
C4s = $A5
D4 = $A6
D4s = $A7
E4 = $A8
F4 = $A9
F4s = $AA
G4 = $AB
G4s = $AC
A4 = $AD
A4s = $AE
B4 = $AF
C5 = $B0
C5s = $B1
D5 = $B2
D5s = $B3
E5 = $B4
F5 = $B5
F5s = $B6
G5 = $B7
G5s = $B8
A5 = $B9
A5s = $BA
B5 = $BB
C6 = $BC
C6s = $BD
D6 = $BE
D6s = $BF
E6 = $C0
F6 = $C1
F6s = $C2
G6 = $C3
G6s = $C4
A6 = $C5
A6s = $C6
B6 = $C7

159
Core/patches.asm Normal file
View File

@@ -0,0 +1,159 @@
; This file contains all direct patches to the original ROM.
; It is included from Oracle_main.asm.
; UnderworldTransition_ScrollRoom
org $02BE5E : JSL Graphics_Transfer
; Whirlpool
org $1EEEE4 : JSL DontTeleportWithoutFlippers
; SpriteDraw_Roller
org $058EE6 : JSL PutRollerBeneathLink
; =========================================================
; Sprite Recoil and Death
; TODO: Sprite_AttemptKillingOfKin
; Kydreeok Head die like Sidenexx
org $06F003 : CMP.b #$CF
; Remove sidenexx death from booki
org $06EFFF : NOP #4
; Make Dark Link die like sidenexx
org $06F003 : CMP.b #$C1
; Make Helmet ChuChu recoil link
org $06F37D : CMP.b #$05
; Make Kydreeok head recoil Link
org $06F381 : CMP.b #$CF
; =========================================================
InCutScene = $7EF303
; Player2JoypadReturn
org $0083F8
LDA InCutScene : BEQ .notInCutscene
STZ $F0
STZ $F2
STZ $F4
STZ $F6
STZ $F8
STZ $FA ; kill all input
.notInCutscene
RTS
assert pc() <= $00841E
; =========================================================
org $1EF27D
ShopItem_Banana:
{
JSR $F4CE ; SpriteDraw_ShopItem
JSR $FE78 ; Sprite_CheckIfActive_Bank1E
JSL $1EF4F3 ; Sprite_BehaveAsBarrier
JSR $F391 ; ShopItem_CheckForAPress
BCC .exit
LDA.l Bananas : CMP.b #$0A : BCS .error
LDA.b #$1E : LDY.b #$00
JSR $F39E ; ShopItem_HandleCost
BCC $F1A1 ; ShopItem_GiveFailureMessage
STZ.w SprState,X
INC.b Bananas
LDY.b #$42 : JSR $F366 ; ShopItem_HandleReceipt
.exit
RTS
.error
JSR $F38A ; ShopItem_PlayBeep
}
assert pc() <= $1EF2AB
; =========================================================
; Shop item heart OAM
; SpriteDraw_ShopItem
org $1EF42E
dw -4, 16 : db $03, $02, $00, $00 ; 3
dw -4, 16 : db $03, $02, $00, $00 ; 3
dw 4, 16 : db $30, $02, $00, $00 ; 0
dw 0, 0 : db $E5, $03, $00, $02 ; item
dw 4, 11 : db $38, $03, $00, $00 ; shadow
; =========================================================
; Octoballoon_FormBabby
; Reduce by half the number of babies spawned
org $06D814 : LDA.b #$02
; SpritePrep_HauntedGroveOstritch
org $068BB2 : NOP #11
; HauntedGroveRabbit_Idle
org $1E9A8F : NOP #5
; MedallionTablet (Goron)
org $05F274 : LDA.l $7EF378 ; Unused SRAM
org $08C2E3 : dw $006F ; BUTTER SWORD DIALOGUE
; Fix the capital 'B' debug item cheat.
org $0CDC26 : db $80 ; replace a $F0 (BEQ) with a $80 (BRA).
; Update Catfish Item Get to Bottle
org $1DE184 : LDA.b #$16 : STA.w $0D90, X
; Follower_Disable
; Don't disable Kiki so we can switch maps with him.
org $09ACF3 : LDA.l $7EF3CC : CMP.b #$0E
; Kiki, don't care if we're not in dark world
org $099FEB : LDA.b $8A : AND.b #$FF
org $1EE48E : NOP #6
; Kiki activate cutscene 3 (tail palace)
org $1EE630 : LDA.b #$03 : STA.w $04C6
; Kid at ranch checks for flute
org $05FF7D : LDA.l $7EF34C : CMP.b #$01
; Raven Damage (LW/DW)
org $068963 : db $81, $84
; Running Man draw palette
org $05E9CD
SpriteDraw_RunningBoy:
#_05E9CD: dw 0, -8 : db $2C, $00, $00, $02
#_05E9D5: dw 0, 0 : db $EE, $0E, $00, $02
#_05E9DD: dw 0, -7 : db $2C, $00, $00, $02
#_05E9E5: dw 0, 1 : db $EE, $4E, $00, $02
#_05E9ED: dw 0, -8 : db $2A, $00, $00, $02
#_05E9F5: dw 0, 0 : db $CA, $0E, $00, $02
#_05E9FD: dw 0, -7 : db $2A, $00, $00, $02
#_05EA05: dw 0, 1 : db $CA, $4E, $00, $02
#_05EA0D: dw 0, -8 : db $2E, $00, $00, $02
#_05EA15: dw 0, 0 : db $CC, $0E, $00, $02
#_05EA1D: dw 0, -7 : db $2E, $00, $00, $02
#_05EA25: dw 0, 1 : db $CE, $0E, $00, $02
#_05EA2D: dw 0, -8 : db $2E, $40, $00, $02
#_05EA35: dw 0, 0 : db $CC, $4E, $00, $02
#_05EA3D: dw 0, -7 : db $2E, $40, $00, $02
#_05EA45: dw 0, 1 : db $CE, $4E, $00, $02
; Sword Barrier Sprite Prep
; Skip overworld flag check, sprite is indoors now
org $06891B : NOP #12

8439
Core/ram.asm Normal file

File diff suppressed because it is too large Load Diff

321
Core/sfx.asm Normal file
View File

@@ -0,0 +1,321 @@
; =========================================================
; SFX instruments - Table: ARAM $3E00, ROM $1A:9C04
; ID VOL L,R Pitch SRCN ADSR Gain Mult Name
; -----------------------------------------------------------------------------
; $00 $70, $70 $1000 $00 $F6 $6A $B8 $03 Fwoosh
; $01 $70, $70 $1000 $01 $8E $E0 $B8 $02 Swish
; $02 $70, $70 $1000 $14 $FE $6A $B8 $02 Bomp
; $03 $70, $70 $1000 $03 $FE $F8 $B8 $0D Ting
; $04 $70, $70 $1000 $04 $FE $6A $7F $03 Rrrrr
; $05 $70, $70 $1000 $02 $FE $6A $7F $03 Clunk
; $06 $70, $70 $1000 $05 $FE $6A $70 $03 Ching
; $07 $70, $70 $1000 $06 $FE $6A $70 $03 Fwomp
; $08 $70, $70 $1000 $08 $FA $6A $70 $03 Squee
; $09 $70, $70 $1000 $06 $FE $6A $70 $01 Unused
; $0A $70, $70 $1000 $07 $FE $6A $70 $05 Bzzzrt
; $0B $70, $70 $1000 $0B $FE $6A $B8 $03 Brrfft
; $0C $70, $70 $1000 $0C $FE $E0 $B8 $02 Brrwwww
; $0D $70, $70 $1000 $0D $F9 $6E $B8 $03 Twee
; $0E $70, $70 $1000 $0E $FE $F5 $B8 $07 Pwing
; $0F $70, $70 $1000 $0F $FE $F5 $B8 $06 Pling
; $10 $70, $70 $1000 $01 $FE $FC $B8 $03 Chshtsh
; $11 $70, $70 $1000 $10 $8E $E0 $B8 $03 Splssh
; $12 $70, $70 $1000 $08 $8E $E0 $B8 $02 Weewoo
; $13 $70, $70 $1000 $14 $8E $E0 $B8 $02 Brbrbrb
; $14 $70, $70 $1000 $0A $88 $E0 $B8 $02 Bwow
; $15 $70, $70 $1000 $17 $8E $E0 $B8 $02 Uughf
; $16 $70, $70 $1000 $15 $FF $E0 $B8 $04 Aaaaaa
; $17 $70, $70 $1000 $03 $DF $11 $B8 $0F Twing
; $18 $70, $70 $1000 $01 $88 $E0 $B8 $01 Whooo
; -----------------------------------------------------------------------------
; SFX instruments by usage
; $00 SFX1.13, SFX1.14
; SFX2.07, SFX2.09, SFX2.0D, SFX2.0E, SFX2.2C, SFX2.3A
; SFX3.05, SFX3.26
; SFXU2533
; $01 SFX1.01, SFX1.02, SFX1.03, SFX1.04
; SFX2.01, SFX2.02, SFX2.12, SFX2.1A, SFX2.1E, SFX2.1F
; SFX2.21, SFX2.23, SFX2.29, SFX2.32, SFX2.39
; SFX3.02, SFX3.1E, SFX3.23, SFX3.31
; $02 SFX2.03, SFX2.04, SFX2.08, SFX2.0B, SFX2.12, SFX2.1F, SFX2.21
; SFX3.06, SFX3.0E
; SFXU2831
; $03 SFX2.06
; SFX3.0A, SFX3.30
; $04 SFX2.3C
; SFX3.32
; SFXU2831
; $05 SFX2.10, SFX2.11, SFX2.22
; SFX3.18, SFX3.3E
; SFXU252D
; $06 SFX2.05, SFX2.0A, SFX2.0F, SFX2.3B
; SFX3.04, SFX3.14, SFX3.25
; $07 SFX2.14, SFX2.15, SFX2.33
; SFX3.01, SFX3.11, SFX3.12, SFX3.19, SFX3.27, SFX3.28, SFX3.29, SFX3.35, SFX3.39
; SFXU26A2
; $08 SFX3.17
; $09 nothing
; $0A SFX1.15, SFX1.16
; SFX3.1C, SFX3.2A, SFX3.2B, SFX3.2C
; $0B SFX2.27
; SFX3.0B, SFX3.0F, SFX3.2E, SFX3.34, SFX3.35, SFX3.36, SFX3.3C, SFX3.3D, SFX3.3F
; $0C SFX2.2A
; SFX3.07, SFX3.08, SFX3.09
; $0D SFX1.0B, SFX1.0C, SFX1.17, SFX1.18, SFX1.1B, SFX1.1C
; SFX2.13, SFX2.20, SFX2.31, SFX2.3E, SFX2.3F
; SFX3.0C, SFX3.13, SFX3.24
; SFXU1EE2, SFXU279D, SFXU27F6, SFXU2807, SFXU2818
; $0E SFX1.0D, SFX1.0E, SFX1.0F, SFX1.10, SFX1.1D, SFX1.1E, SFX1.1F, SFX1.20
; SFX2.2B, SFX2.37
; SFX3.0D, SFX3.10, SFX3.1B, SFX3.2F, SFX3.33, SFX3.3A, SFX3.3B
; $0F SFX2.2D
; SFX3.1A, SFX3.1D, SFX3.20, SFX3.2D, SFX3.37
; SFXU1D1C
; $10 SFX2.16, SFX2.17, SFX2.18, SFX2.19
; $11 SFX2.1B, SFX2.1C, SFX2.24, SFX2.25, SFX2.28, SFX2.2E, SFX2.34, SFX3.28, SFX2.3D
; $12 SFX3.04
; $13 SFX1.07, SFX1.08
; SFX2.0C, SFX2.35, SFX2.36
; SFX3.03, SFX3.15, SFX3.16, SFX3.25, SFX3.38
; $14 SFX3.21, SFX3.22
; SFXU277E
; $15 SFX2.26, SFX2.30
; SFXU1F13
; $16 SFX1.11, SFX1.12
; SFX2.1D
; SFX3.1F
; $17 SFX2.2C, SFX2.3A
; $18 SFX1.09, SFX1.0A
; -----------------------------------------------------------------------------
; SFX1 - queued via $012D | Table: ARAM $17C0, ROM $1A:8B70
; ID ARAM ROM Name
; -----------------------------------------------------------------------------
; SFX1.01 $2652 $1A9A02 Rain / Zora area
; SFX1.02 $2662 $1A9A12 Rain / Zora area (packaged with $01)
; SFX1.03 $2677 $1A9A27 Rain
; SFX1.04 $2687 $1A9A37 Rain (packaged with $03)
; SFX1.05 $284F $1A9BFF Silence
; SFX1.06 $284F $1A9BFF Silence (packaged with $05)
; SFX1.07 $2739 $1A9AE9 The Rumbling
; SFX1.08 $2736 $1A9AE6 The Rumbling (packaged with $08)
; SFX1.09 $1C8E $1A903E Wind
; SFX1.0A $1CBC $1A906C Wind (packaged with $09 by APU)
; SFX1.0B $1BA3 $1A8F53 Flute song by flute boy
; SFX1.0C $1B62 $1A8F12 Flute song by flute boy (packaged with $0B)
; SFX1.0D $1B0E $1A8EBE Magic jingle
; SFX1.0E $1B1D $1A8ECD Magic jingle (packaged with $0D)
; SFX1.0F $1B2C $1A8EDC Crystal / Save and quit
; SFX1.10 $1B3E $1A8EEE Crystal / Save and quit (packaged with $0F)
; SFX1.11 $1EAC $1A925C Choir melody
; SFX1.12 $1EC8 $1A9278 Choir countermelody (packaged with $11)
; SFX1.13 $1AD2 $1A8E82 Large boss swoosh
; SFX1.14 $1AE1 $1A8E91 Large boss swoosh (packaged with $13)
; SFX1.15 $1AF0 $1A8EA0 Triforce door / Pyramid hole opening
; SFX1.16 $1AFF $1A8EAF VOMP (packaged with $15)
; SFX1.17 $1C24 $1A8FD4 Flute song for weathervane
; SFX1.18 $1BE3 $1A8F93 Flute song for weathervane (packaged with $17)
; SFX1.19 $0000 ------- Nothing (unused)
; SFX1.1A $0000 ------- Nothing (unused; packaged with $19)
; SFX1.1B $1BA3 $1A8F53 Flute song by flute boy duplicate (unused)
; SFX1.1C $1B62 $1A8F12 Flute song by flute boy duplicate (unused; packaged with $1B)
; SFX1.1D $1B0E $1A8EBE Magic jingle duplicate (unused)
; SFX1.1E $1B1D $1A8ECD Magic jingle duplicate (unused; packaged with $1D)
; SFX1.1F $1B2C $1A8EDC Crystal / Save and quit duplicate (unused)
; SFX1.20 $1B3E $1A8EEE Crystal / Save and quit duplicate (unused; packaged with $1F)
; $80..$FF Initiates a fade to half volume for SFX1
; -----------------------------------------------------------------------------
; SFX2 - queued via $012E | Table: ARAM $1820, ROM $1A:8BD0
; ID ARAM ROM Name
; -----------------------------------------------------------------------------
; 00 $0020 ------- Undefined; when queued value of $40, $C0, $80
; SFX2.01 $2614 $1A99C4 Slash
; SFX2.02 $2625 $1A99D5 Slash
; SFX2.03 $2634 $1A99E4 Slash
; SFX2.04 $2643 $1A99F3 Slash
; SFX2.05 $25DD $1A998D Clink
; SFX2.06 $25D7 $1A9987 Bombable door clink
; SFX2.07 $25B7 $1A9967 Fwoosh
; SFX2.08 $25E3 $1A9993 Arrow smash
; SFX2.09 $25AD $1A995D Boomerang fwish
; SFX2.0A $25C7 $1A9977 Hookshot clink
; SFX2.0B $2478 $1A9828 Placing bomb
; SFX2.0C $269C $1A9A4C Explosion
; SFX2.0D $2414 $1A97C4 Powder (paired $0D→$3F)
; SFX2.0E $2404 $1A97B4 Fire rod shot
; SFX2.0F $24C3 $1A9873 Ice rod shot
; SFX2.10 $23FA $1A97AA Hammer use
; SFX2.11 $23F0 $1A97A0 Hammering peg
; SFX2.12 $23CD $1A977D Digging
; SFX2.13 $23A0 $1A9750 Flute (paired $13→$3E)
; SFX2.14 $2380 $1A9730 Cape on
; SFX2.15 $2390 $1A9740 Cape off / Wallmaster grab
; SFX2.16 $232C $1A96DC Staircase
; SFX2.17 $2344 $1A96F4 Staircase
; SFX2.18 $2356 $1A9706 Staircase
; SFX2.19 $236E $1A971E Staircase
; SFX2.1A $2316 $1A96C6 Tall grass / Hammer hitting bush
; SFX2.1B $2307 $1A96B7 Shallow water
; SFX2.1C $2301 $1A96B1 Mire shallow water
; SFX2.1D $22BB $1A966B Lifting object
; SFX2.1E $2577 $1A9927 Cutting grass
; SFX2.1F $22E9 $1A9699 Item breaking
; SFX2.20 $22DA $1A968A Item falling in pit
; SFX2.21 $22CF $1A967F Bomb hitting ground / General thud
; SFX2.22 $2107 $1A94B7 Pushing object / Armos bounce
; SFX2.23 $22B1 $1A9661 Boots dust
; SFX2.24 $22A5 $1A9655 Splashing (paired $24→$3D)
; SFX2.25 $2296 $1A9646 Mire shallow water again?
; SFX2.26 $2844 $1A9BF4 Link taking damage
; SFX2.27 $2252 $1A9602 Fainting
; SFX2.28 $2287 $1A9637 Item splash
; SFX2.29 $243F $1A97EF Rupee refill (paired $29→$3B)
; SFX2.2A $2033 $1A93E3 Fire splash / Bombos spell
; SFX2.2B $1FF2 $1A93A2 Heart beep / Text box
; SFX2.2C $1FD9 $1A9389 Sword up (paired $2C→$3A) (also uses instrument $17)
; SFX2.2D $20A6 $1A9456 Magic drain
; SFX2.2E $1FCA $1A937A GT opening (paired $2E→$39)
; SFX2.2F $1F47 $1A92F7 GT opening / Water drain (paired $2F→$38)
; SFX2.30 $1EF1 $1A92A1 Cucco
; SFX2.31 $20CE $1A947E Fairy
; SFX2.32 $1D47 $1A90F7 Bug net
; SFX2.33 $1CDC $1A908C Teleport (paired $34→$33)
; SFX2.34 $1F6F $1A931F Teleport (paired $34→$33)
; SFX2.35 $1C67 $1A9017 Shaking
; SFX2.36 $1C64 $1A9014 Mire entrance (extends above; paired $35→$36)
; SFX2.37 $1A43 $1A8DF3 Spin charged
; SFX2.38 $1F6F $1A931F Water sound (paired $2F→$38)
; SFX2.39 $1F9C $1A934C Thunder (paired $2E→$39)
; SFX2.3A $1FE7 $1A9397 Sword up (paired $2C→$3A)
; SFX2.3B $2462 $1A9812 Rupee refill (paired $29→$3B)
; SFX2.3C $1A37 $1A8DE7 Error beep
; SFX2.3D $22AB $1A965B Big splash (paired $24→$3D)
; SFX2.3E $23B5 $1A9765 Flute (paired $13→$3E)
; SFX2.3F $2435 $1A97E5 Powder (paired $0D→$3F)
; -----------------------------------------------------------------------------
; SFX3 - queued via $012F | Table: ARAM $191C, ROM $1A:8CCC
; ID ARAM ROM Name
; -----------------------------------------------------------------------------
; 00 $003C ------- Undefined; when queued value of $40, $C0, $80
; SFX3.01 $1A18 $1A8DC8 Sword beam
; SFX3.02 $254E $1A98FE TR opening
; SFX3.03 $224A $1A95FA Pyramid hole
; SFX3.04 $220E $1A95BE Angry soldier
; SFX3.05 $25B7 $1A9967 Lynel shot / Javelin toss
; SFX3.06 $21F5 $1A95A5 Swoosh
; SFX3.07 $223D $1A95ED Cannon fire
; SFX3.08 $21E6 $1A9596 Damage to enemy; $0BEX.4=1
; SFX3.09 $21C1 $1A9571 Enemy death
; SFX3.0A $21A9 $1A9559 Collecting rupee
; SFX3.0B $2198 $1A9548 Collecting heart
; SFX3.0C $218E $1A953E Non-blank text character
; SFX3.0D $21B5 $1A9565 HUD heart
; SFX3.0E $2182 $1A9532 Opening chest
; SFX3.0F $24B9 $1A9869 ♪Do do do doooooo♫ (paired $0F→$3C→$3D→$3E→$3F)
; SFX3.10 $216D $1A951D Map (paired $10→$3B)
; SFX3.11 $214F $1A94FF Opening item menu / Bomb shop guy breathing
; SFX3.12 $215E $1A950E Closing item menu / Bomb shop guy breathing
; SFX3.13 $213B $1A94EB Throwing object / Stalfos jump
; SFX3.14 $246C $1A981C Key door
; SFX3.15 $212F $1A94DF Door / Chest (used with SFX2.29)
; SFX3.16 $2123 $1A94D3 Armos Knight thud
; SFX3.17 $25A6 $1A9956 Rat squeak
; SFX3.18 $20DD $1A948D Dragging
; SFX3.19 $250A $1A98BA Fireball / Laser shot
; SFX3.1A $1E8A $1A923A Chest reveal jingle (paired $1A→$38)
; SFX3.1B $20B6 $1A9466 Puzzle jingle (paired $1B→$3A)
; SFX3.1C $1A62 $1A8E12 Damage to enemy
; SFX3.1D $20A6 $1A9456 Magic meter
; SFX3.1E $2091 $1A9441 Wing flapping
; SFX3.1F $204B $1A93FB Link falling
; SFX3.20 $276C $1A9B1C Menu / Text cursor moved
; SFX3.21 $27E2 $1A9B92 Damage to boss
; SFX3.22 $26CF $1A9A7F Boss dying / Deleting file
; SFX3.23 $2001 $1A93B1 Spin attack swoosh (paired $23→$39)
; SFX3.24 $2043 $1A93F3 OW map perspective change
; SFX3.25 $1E9D $1A924D Pressure switch (also uses instrument $06)
; SFX3.26 $1E7B $1A922B Lightning / Game over / Laser / Ganon bat / Trinexx lunge
; SFX3.27 $1E40 $1A91F0 Agahnim charge
; SFX3.28 $26F7 $1A9AA7 Agahnim / Ganon teleport
; SFX3.29 $1E21 $1A91D1 Agahnim shot
; SFX3.2A $1E12 $1A91C2 Somaria / Byrna / Ether spell / Helma fire ball
; SFX3.2B $1DF3 $1A91A3 Electrocution
; SFX3.2C $1DC0 $1A9170 Bees
; SFX3.2D $1DA9 $1A9159 Milestone jingle (paired $2D→$37)
; SFX3.2E $1D5D $1A910D Heart container jingle (paired $2E→$35→$34)
; SFX3.2F $1D80 $1A9130 Key jingle (paired $2F→$33)
; SFX3.30 $1B53 $1A8F03 Magic zap / Plop
; SFX3.31 $1ACA $1A8E7A Sprite falling / Moldorm shuffle
; SFX3.32 $1A78 $1A8E28 BOING
; SFX3.33 $1D93 $1A9143 Key jingle (paired $2F→$33)
; SFX3.34 $1D66 $1A9116 Heart container jingle (paired $2E→$35→$34)
; SFX3.35 $1D73 $1A9123 Heart container jingle (paired $2E→$35→$34)
; SFX3.36 $1AA7 $1A8E57 Magic attack
; SFX3.37 $1DB4 $1A9164 Milestone jingle (paired $2D→$37)
; SFX3.38 $1E93 $1A9243 Chest reveal jingle (paired $1A→$38)
; SFX3.39 $2017 $1A93C7 Swish (paired $23→$39)
; SFX3.3A $20C0 $1A9470 Puzzle jingle (paired $1B→$3A)
; SFX3.3B $2176 $1A9526 Map (paired $10→$3B)
; SFX3.3C $248A $1A983A Item jingle (paired $0F→$3C→$3D→$3E→$3F)
; SFX3.3D $2494 $1A9844 Item jingle ($0F→$3C→$3D→$3E→$3F)
; SFX3.3E $249E $1A984E Item jingle (paired $0F→$3C→$3D→$3E→$3F)
; SFX3.3F $2480 $1A9830 Item jingle (paired $0F→$3C→$3D→$3E→$3F)
; -----------------------------------------------------------------------------
; Unused SFX
; ARAM ROM Description
; -----------------------------------------------------------------------------
; $1A5B $1A8E0B Noisy fsssh; bleeds into SFX3.1C
; $1D1C $1A90CC Radar ping
; $1EE2 $1A9292 Slide whistle / Chirp
; $1F13 $1A92C3 Cucco clucking
; $252D $1A98DD Brighter hammer peg
; $2533 $1A98E3 Bat wings flapping
; $2657 $1A9A07 Broken static
; $267C $1A9A2C Static; Loops
; $26A2 $1A9A52 Tuba jingle followed by a roar
; $277E $1A9B2E UFO winding up
; $279D $1A9B4D Distant whistling
; $27C9 $1A9B79 Bwuuuoow
; $27F6 $1A9BA6 Cat call
; $2807 $1A9BB7 Higher pitched cat call
; $2818 $1A9BC8 Reverse cat call
; $2829 $1A9BD9 Dial-up
; $2831 $1A9BE1 Bumper peg

1154
Core/sprite_functions.asm Normal file

File diff suppressed because it is too large Load Diff

360
Core/sprite_macros.asm Normal file
View File

@@ -0,0 +1,360 @@
; Write Sprite Properties in the rom MACRO
macro Set_Sprite_Properties(SprPrep, SprMain)
{
pushpc ; Save writing Position for the sprite
org $0DB080+!SPRID ; Oam Harmless ($0E40)
db ((!Harmless<<7)|(!HVelocity<<6)|!NbrTiles)
org $0DB173+!SPRID ; Sprite HP ($0E50)
db !Health
org $0DB266+!SPRID ; Sprite Damage ($0CD2)
db !Damage
org $0DB359+!SPRID ; Sprite Data ($0E60 / $0F50)
db ((!DeathAnimation<<7)|(!ImperviousAll<<6)|(!SmallShadow<<5)|(!Shadow<<4)|(!Palette<<1))
org $0DB44C+!SPRID ; Sprite Hitbox ($0F60)
db ((!CollisionLayer<<7)|(!Statis<<6)|(!Persist<<5)|(!Hitbox))
org $0DB53F+!SPRID ; Sprite Fall ($0B6B)
db ((!DeflectArrow<<3)|(!Boss<<1)|!CanFall)
org $0DB632+!SPRID ; Sprite Prize ($0BE0)
db ((!Interaction<<7)|(!WaterSprite<<6)|(!Blockable<<5)|(!Sound<<4)|!Prize)
org $0DB725+!SPRID ; Sprite ($0CAA)
db ($40|(!Statue<<5)|(!DeflectProjectiles<<4)|(!ImpervSwordHammer<<2)|(!ImperviousArrow<<1))
org $069283+(!SPRID*2) ; Vanilla Sprite Main Pointer
dw NewMainSprFunction
org $06865B+(!SPRID*2) ; Vanilla Sprite Prep Pointer
dw NewSprPrepFunction
org NewSprRoutinesLong+(!SPRID*3) ; New Long Sprite Pointer
dl <SprMain>
org NewSprPrepRoutinesLong+(!SPRID*3) ; New Long Sprite Pointer
dl <SprPrep>
pullpc ; Get back the writing position for the sprite
}
endmacro
macro sta(...)
!a #= 0
while !a < sizeof(...)
STA <...>
!a #= !a+1
endwhile
endmacro
macro m16()
REP #$30
endmacro
macro m8()
SEP #$30
endmacro
macro a16()
REP #$20
endmacro
macro a8()
SEP #$20
endmacro
macro index16()
REP #$10
endmacro
macro index8()
SEP #$10
endmacro
macro GotoAction(action)
LDA.b #<action> : STA.w SprAction, X
endmacro
macro SetFrame(frame)
LDA.b #<frame> : STA.w SprFrame, X
endmacro
macro JumpTable(index, ...)
LDA.w <index>
JSL JumpTableLocal
!a #= 0
while !a < sizeof(...)
dw <...[!a]>
!a #= !a+1
endwhile
endmacro
macro SpriteJumpTable(...)
LDA.w SprAction, X
JSL JumpTableLocal
!a #= 0
while !a < sizeof(...)
dw <...[!a]>
!a #= !a+1
endwhile
endmacro
macro SetFlag(flag_addr, bit_pos)
LDA.b flag_addr : ORA.b #(1 << bit_pos) : STA.b flag_addr
endmacro
macro ClearFlag(flag_addr, bit_pos)
LDA.b flag_addr : AND.b #~(1 << bit_pos) : STA.b flag_addr
endmacro
macro ToggleFlag(flag_addr, bit_pos)
LDA.b flag_addr : EOR.b #(1 << bit_pos) : STA.b flag_addr
endmacro
macro CheckFlag(flag_addr, bit_pos, set_label, clear_label)
LDA.b flag_addr : AND.b #(1 << bit_pos) : BEQ clear_label
BRA set_label
endmacro
macro CheckFlagLong(flag_addr, bit_pos, set_label, clear_label)
LDA.l flag_addr : AND.b #(1 << bit_pos) : BEQ clear_label
BRA set_label
endmacro
; Increase the sprite frame every (frames_wait) frames
; reset to (frame_start) when reaching (frame_end)
; This is using SprTimerB
macro PlayAnimation(frame_start, frame_end, frame_wait)
{
LDA.w SprTimerB, X : BNE +
LDA.w SprFrame, X : INC : STA.w SprFrame, X
CMP.b #<frame_end>+1 : BCC ++
LDA.b #<frame_start> : STA.w SprFrame, X
++
LDA.b #<frame_wait> : STA.w SprTimerB, X
+
}
endmacro
macro PlayAnimBackwards(frame_start, frame_end, frame_wait)
LDA.w SprTimerB, X : BNE +
LDA.w SprFrame, X : DEC : STA.w SprFrame, X
CMP.b #<frame_end> : BCS ++
LDA.b #<frame_start> : STA.w SprFrame, X
++
LDA.b #<frame_wait> : STA.w SprTimerB, X
+
endmacro
macro StartOnFrame(frame)
LDA.w SprFrame, x : CMP.b #<frame> : BCS +
LDA.b #<frame> : STA.w SprFrame, x
+
endmacro
; Show message if the player is facing toward sprite and pressing A
; Return Carry Set if message is displayed
; can use BCC .label <> .label to see if message have been displayed
macro ShowSolicitedMessage(message_id)
LDY.b #(<message_id>)>>8
LDA.b #<message_id>
JSL Sprite_ShowSolicitedMessageIfPlayerFacing
endmacro
macro ShowMessageOnContact(message_id)
LDY.b #(<message_id>)>>8
LDA.b #<message_id>
JSL $05E1F0 ; Sprite_ShowMessageOnContact
endmacro
; Show message no matter what (should not be used without code condition)
macro ShowUnconditionalMessage(message_id)
LDY.b #(<message_id>)>>8
LDA.b #<message_id>
JSL Sprite_ShowMessageUnconditional
endmacro
; Make the sprite move towards the player at a speed of (speed)
macro MoveTowardPlayer(speed)
LDA.b #<speed>
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_MoveLong
endmacro
; Prevent the player from passing through sprite hitbox
macro PlayerCantPassThrough()
JSL Sprite_PlayerCantPassThrough
endmacro
; Do damage to player on contact if sprite is on same layer as player
macro DoDamageToPlayerSameLayerOnContact()
JSL Sprite_CheckDamageToPlayerSameLayer
endmacro
; Set harmless flag, 0 = harmful, 1 = harmless
macro SetHarmless(value)
LDA.w SprNbrOAM, X
AND #$7F
if <value> != 0
ORA.b #(<value>)<<7
endif
STA.w SprNbrOAM, X
endmacro
macro SetImpervious(value)
LDA.w SprDefl, X
EOR.b #(<value>)<<2
STA.w SprDefl, X
endmacro
; Set Room Flag (Chest 6)
; Do not use if you have more than 5 chests or a small key under a pot
; in that room unless you want it to be already opened/taken
macro SetRoomFlag(value)
if <value> != 0
LDA $0403 : ORA #$20 : STA $0403
else
LDA $0403 : AND #$DF : STA $0403
endif
endmacro
; Will prevent the player from moving or opening his menu
macro PreventPlayerMovement()
LDA #$01 : STA $02E4
endmacro
; Will allow the player to move or open his menu
macro AllowPlayerMovement()
STZ.w $02E4
endmacro
; This is a 16 bit will load A with current rupee count
; to use with instructions CMP and BCC/BCS
macro GetPlayerRupees()
LDA $7EF360
endmacro
; Set the velocity Y of the sprite at (speed) value
; this require the use of the function JSL Sprite_MoveLong
macro SetSpriteSpeedY(speed)
LDA.b #<speed> : STA.w SprYSpeed, x
endmacro
; Set the velocity X of the sprite at (speed) value
; this require the use of the function JSL Sprite_MoveLong
macro SetSpriteSpeedX(speed)
LDA.b #<speed> : STA.w SprXSpeed, x
endmacro
macro PlaySFX1(sfxid)
LDA.b #<sfxid> : STA $012E
endmacro
macro PlaySFX2(sfxid)
LDA.b #<sfxid> : STA $012F
endmacro
macro PlayMusic(musicid)
LDA.b #<musicid> : STA $012C
endmacro
macro SetTimerA(length)
LDA.b #<length> : STA.w SprTimerA, X
endmacro
macro SetTimerB(length)
LDA.b #<length> : STA.w SprTimerB, X
endmacro
macro SetTimerC(length)
LDA.b #<length> : STA.w SprTimerC, X
endmacro
macro SetTimerD(length)
LDA.b #<length> : STA.w SprTimerD, X
endmacro
macro SetTimerE(length)
LDA.b #<length> : STA.w SprTimerE, X
endmacro
macro SetTimerF(length)
LDA.b #<length> : STA.w SprTimerF, X
endmacro
macro ErrorBeep()
LDA.b #$3C : STA.w $012E ; Error beep
endmacro
macro NextAction()
INC $0D80, X
endmacro
macro GetTilePos(x, y)
LDX.w #((<y>*$80)+(<x>*$02))
endmacro
macro SetupDistanceFromSprite()
LDA.w POSX : STA $02
LDA.w POSY : STA $03
LDA.w SprX, X : STA $04
LDA.w SprY, X : STA $05
endmacro
macro ProbCheck(mask, label)
JSL GetRandomInt
AND.b #<mask>
BNE <label>
endmacro
macro ProbCheck2(mask, label)
JSL GetRandomInt
AND.b #<mask>
BEQ <label>
endmacro
macro DrawSprite()
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY
LDA.w .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ; amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
; Put the sprite out of the way
LDA.b #$F0 : STA ($90), Y : STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
}
endmacro

80
Core/sprite_new_table.asm Normal file
View File

@@ -0,0 +1,80 @@
pushpc
org $06FFF8 ; New Jumptable for sprites
NewMainSprFunction:
JSL SpriteActiveExp_MainLong
RTS
org $068EB9
NewSprPrepFunction:
JSL Sprite_PrepExp_Long
RTS
pullpc
SpriteActiveExp_MainLong:
{
PHB : PHK : PLB
JSL NewSprTable
PLB
RTL
}
NewSprTable:
{
LDA $0E20, X ; Load Sprite ID
REP #$30
AND.w #$00FF
STA $06
ASL A ; *2
CLC : ADC $06 ; *3
TAY
LDA NewSprRoutinesLong, Y ; Load sprite Address
STA $06
SEP #$20
LDA NewSprRoutinesLong+2, Y
STA $08
SEP #$30
JMP [$0006]
;do a JML and sprite will RTL back to previous code
}
Sprite_PrepExp_Long:
{
PHB : PHK : PLB
JSL NewSprPrepTable
PLB
RTL
}
NewSprPrepTable:
{
LDA $0E20, X ; Load Sprite ID
REP #$30
AND.w #$00FF
STA $06
ASL A ; *2
CLC : ADC $06 ; *3
TAY
LDA NewSprPrepRoutinesLong, Y ; Load sprite Address
STA $06
SEP #$20 ; Previously SEP #$30 -_- (that's fine for sprites below ~0x40 over that it will crash)
LDA NewSprPrepRoutinesLong+2, Y
STA $08
SEP #$30
JMP [$0006]
}
NewSprRoutinesLong:
{
fillbyte $00
fill $2FD
}
NewSprPrepRoutinesLong:
{
fillbyte $00
fill $2FD
}

545
Core/sram.asm Normal file
View File

@@ -0,0 +1,545 @@
; Game state
; 0x00 - Very start; progress cannot be saved in this state
; 0x01 - Uncle reached
; 0x02 - Farore intro over | Zelda rescued
; 0x03 - Agahnim defeated
GameState = $7EF3C5
; Red X on Hall of Secrets
; Red X on Kalyxo Pyramid
; .fmp h.i.
; f - fortress of secrets
; m - master sword
; p - pendant quest
; h - hall of secrets
; i - intro over, maku tree
OOSPROG = $7EF3D6
; Bitfield of less important progression
; .fbh .zsu
; u - Uncle
; s - Priest visited in sanc after Zelda is kidnapped again
; z - Zelda brought to sanc
; h - Uncle left Link's house (0: spawn | 1: gone)
; b - Book of Mudora obtained/mentioned; controls Aginah dialog
; f - Flipped by fortune tellers to decide fortune set to give
OOSPROG2 = $7EF3C6
; .... ...m
; m - maku tree has met link (0: no | 1: yes)
MakuTreeQuest = $7EF3D4
; Map icon
; 0x00 - Red X on Maku Tree/Maku Warp
; 0x01 - Toadstool Woods Crystal
; 0x02 - Kalyxo All Crystals
; 0x03 -
; 0x04 -
; 0x05 -
; 0x06 -
; 0x07 -
; 0x08 - Skull on GT | Climb Ganon's Tower
MapIcon = $7EF3C7
; 01 - Fishing Rod
; 02 - Portal Rod
CustomRods = $7EF351
; Free SRAM Block 38A-3C4
FishingRod = $7EF38A
; Collectibles
Bananas = $7EF38B
Pineapples = $7EF38D
RockMeat = $7EF38F
Seashells = $7EF391
Honeycomb = $7EF393
DekuSticks = $7EF395
TingleMaps = $7EF396
TingleId = $7EF397
; .dgi zktm
; m - Mushroom Grotto
; t - Tail Palace
; k - Kalyxo Castle
; z - Zora Temple
; i - Glacia Estate
; g - Goron Mines
; d - Dragon Ship
Scrolls = $7EF398
; Keep track of the previous scroll
; For re-reading old hints.
PrevScroll = $7EF39A
; .dts fwpb
; b - bean planted
; w - plant watered
; p - pollinated by bee
; f - first day
; s - second day
; t - third day
; d - done
MagicBeanProg = $7EF39B
JournalState = $7EF39C
; State machine for Link's House intro sequence (custom_tag.asm)
; 0x00 - Telepathic Plea phase
; 0x01 - Wake Up Player phase
; 0x02 - End (intro complete)
StoryState = $7EF39E
; 7EF403 - 7EF4FD Unused block
; .... .cpw
; c - courage
; p - power
; w - wisdom
Dreams = $7EF410
; =========================================================
; Items
; =========================================================
; 0x00 - Nothing
; 0x01 - Bow
; 0x02 - Bow and arrows
; 0x03 - Silver bow
; 0x04 - Silver bow and arrows
; Picking the arrow and nonarrow versions is done by the HUD draw routines
Bow = $7EF340
; 0x00 - Nothing
; 0x01 - Blue boomerang
; 0x02 - Red boomerang
Boomerang = $7EF341
; 0x00 - Nothing
; 0x01 - Hookshot
; 0x02 - Goldstar (L/R)
Hookshot = $7EF342
; Number of bombs
Bombs = $7EF343
; 0x00 - Nothing
; 0x01 - Mushroom
; 0x02 - Powder
MagicPowder = $7EF344
; 0x00 - Nothing
; 0x01 - Fire rod
FireRod = $7EF345
; 0x00 - Nothing
; 0x01 - Ice rod
IceRod = $7EF346
; 0x00 - Nothing
; 0x01 - Zora Mask
ZoraMask = $7EF347
; 0x00 - Nothing
; 0x01 - Bunny Hood
BunnyHood = $7EF348
; 0x00 - Nothing
; 0x01 - Deku Mask
DekuMask = $7EF349
; 0x00 - Nothing
; 0x01 - Lamp
Lamp = $7EF34A
; 0x00 - Nothing
; 0x01 - Magic hammer
Hammer = $7EF34B
; 0x00 - Nothing
; 0x01 - Shovel
; 0x02 - Inactive flute
; 0x03 - Active flute
Flute = $7EF34C
; 0x00 - Nothing
; 0x01 - Roc's Feather
RocsFeather = $7EF34D
; 0x00 - Nothing
; 0x01 - Book of Mudora
Book = $7EF34E
; 0x00 - Nothing
; Other values indicate the index of the currently selected bottle
BottleIndex = $7EF34F
; 0x00 - Nothing
; 0x01 - Cane of Somaria
Somaria = $7EF350
; 0x00 - Nothing
; 0x01 - Cane of Byrna
Byrna = $7EF351
; 0x00 - Nothing
; 0x01 - Stone Mask
StoneMask = $7EF352
; 0x00 - Nothing
; 0x01 - Letter (works like mirror)
; 0x02 - Mirror
; 0x03 - Deleted triforce item
Mirror = $7EF353
; 0x00 - Lift 1 (nothing)
; 0x01 - Lift 2 (power glove)
; 0x02 - Lift 3 (titan's mitt)
Gloves = $7EF354
; 0x00 - Nothing
; 0x01 - Pegasus boots
; bit 2 of $7E:F379 also needs to be set to actually dash
Boots = $7EF355
; 0x00 - Nothing
; 0x01 - Zora's flippers
Flippers = $7EF356
; 0x00 - Nothing
; 0x01 - Moon pearl
Pearl = $7EF357
; 0x00 - Nothing
; 0x01 - Wolf Mask
WolfMask = $7EF358
; 0x00 - Nothing
; 0x01 - Fighter sword
; 0x02 - Master sword
; 0x03 - Tempered sword
; 0x04 - Golden sword
; 0xFF - Set when sword is handed in to smithy
Sword = $7EF359
; 0x00 - Nothing
; 0x01 - Fighter shield
; 0x02 - Fire shield
; 0x03 - Mirror shield
Shield = $7EF35A
; 0x00 - Green mail
; 0x01 - Blue mail
; 0x02 - Red mail
Armor = $7EF35B
; 0x00 - Nothing
; 0x01 - Mushroom (unused)
; 0x02 - Empty bottle
; 0x03 - Red potion
; 0x04 - Green potion
; 0x05 - Blue potion
; 0x06 - Fairy
; 0x07 - Bee
; 0x08 - Good bee
; 0x09 - Magic Bean
; 0x0A - Milk Bottle
Bottle1 = $7EF35C
Bottle2 = $7EF35D
Bottle3 = $7EF35E
Bottle4 = $7EF35F
; Number of rupees you have
; RUPEEDISP will be incremented or decremented until it reaches this value
Rupees = $7EF360
RupeesGoal = $7EF361
; Rupee count displayed on the HUD
RUPEEDISP = $7EF362
; Bitfields for ownership of various dungeon items
; SET 2 SET 1
; xced aspm wihb tg..
; c - Hyrule Castle
; x - Sewers
; a - Agahnim's Tower
;
; e - Eastern Palace
; d - Desert Palace
; h - Tower of Hera
;
; p - Palace of Darkness
; s - Swamp Palace
; w - Skull Woods
; b - Thieves' Town
; i - Ice Palace
; m - Misery Mire
; t - Turtle Rock
; g - Ganon's Tower
COMPASS1 = $7EF364
COMPASS2 = $7EF365
BIGKEY1 = $7EF366
BIGKEY2 = $7EF367
DNGMAP1 = $7EF368
DNGMAP2 = $7EF369
; Number of rupees donated to fairies
WISHRUP = $7EF36A
; Number of heart pieces towards next container
; Intended to be a value from 0-3
HEARTPC = $7EF36B
; Maximum health; 1 heart container = 0x08 HP
MAXHP = $7EF36C
; Current health
; You die at 0x00
; You also die at ≥0xA8
CURHP = $7EF36D
; Magic power, capped at 128
MagicPower = $7EF36E
; Current number of keys for whatever dungeon is loaded
KEYS = $7EF36F
; Number of capacity upgrades received
BOMBCAP = $7EF370
ARROWCAP = $7EF371
; Refills health
; Expects multiples of 8
HeartRefill = $7EF372
; Refills magic
ZAPME = $7EF373
; ... ..gbr
; r - Wisdom (red)
; b - Power (blue)
; g - Courage (green)
Pendants = $7EF374
; Refills bombs
BOMBME = $7EF375
; Refills arrows
SHOOTME = $7EF376
; Arrow count
Arrows = $7EF377
; Unused
UNUSED_7EF378 = $7EF378
; Displays ability flags
; lrtu pbsh
; h - Pray (unused and mostly cut off by HUD borders)
; s - Swim
; b - Run
; u - unused but set by default
; p - Pull
; t - Talk
; r - Read
; l - Lift
; This only controls the display of "LIFT.1"
; If this bit is unset but LIFT is set then the proper lift text is displayed
Ability = $7EF379
; Dungeon ID Legend
; Mushroom Grotto ID 0x0C (Palace of Darkness)
; Tail Palace ID 0x0A (Swamp Palace)
; Kalyxo Castle ID 0x10 (Skull Woods)
; Zora Temple ID 0x16 (Thieves Town)
; Glacia Estate 0x12 (Ice Palace)
; Goron Mines 0x0E (Misery Mire)
; Dragon Ship 0x18 (Turtle Rock)
; .wbs tipm
; p - Palace of Darkness
; s - Swamp Palace
; w - Skull Woods
; b - Thieves' Town
; i - Ice Palace
; m - Misery Mire
; t - Turtle Rock
Crystals = $7EF37A
; 0x00 - Normal magic
; 0x01 - Half magic
; 0x02 - Quarter magic
; Quarter magic has no special HUD graphic, unlike half magic
; Also, not everything is necessarily quarter magic
MagicUsage = $7EF37B
; Keys earned per dungeon
; Sewers and Castle are kept in sync
KEYSSEWER = $7EF37C
KEYSHYRULE = $7EF37D
KEYSEAST = $7EF37E
KEYSDESERT = $7EF37F
KEYSAGA = $7EF380
KEYSSWAMP = $7EF381
KEYSPOD = $7EF382
KEYSMIRE = $7EF383
KEYSWOODS = $7EF384
KEYSICE = $7EF385
KEYSHERA = $7EF386
KEYSTHIEF = $7EF387
KEYSTROCK = $7EF388
KEYSGANON = $7EF389
; Unused block of SRAM
UNUSED_7EF38A = $7EF38A
; Game state
; 0x00 - Very start; progress cannot be saved in this state
; 0x01 - Uncle reached
; 0x02 - Zelda rescued
; 0x03 - Agahnim defeated
GAMESTATE = $7EF3C5
; Bitfield of less important progression
; .fbh .zsu
; u - Uncle visited in secret passage; controls spawn (0: spawn | 1: gone)
; s - Priest visited in sanc after Zelda is kidnapped again
; z - Zelda brought to sanc
; h - Uncle has left Link's house; controls spawn (0: spawn | 1: gone)
; b - Book of Mudora obtained/mentioned; controls Aginah dialog
; f - Flipped by fortune tellers to decide which fortune set to give
PROGLITE = $7EF3C6
; Map icon to guide noob players
; 0x00 - Red X on castle | Save zelda
; 0x01 - Red X on Kakariko | Talk to villagers about elders
; 0x02 - Red X on Eastern | Talk to Sahasrahla
; 0x03 - Pendants and MS | Obtain the master sword
; 0x04 - Master sword on LW | Grab the master sword
; 0x05 - Skull on castle | Kill Agahnim
; 0x06 - Crystal on POD | Get the first crystal
; 0x07 - Crystals | Get all 7 crystals
; 0x08 - Skull on GT | Climb Ganon's Tower
MAPICON = $7EF3C7
; 0x00 - Link's house
; 0x01 - Sanctuary
; 0x02 - Prison
; 0x03 - Uncle
; 0x04 - Throne
; 0x05 - Old man cave
; 0x06 - Old man home
SpawnPoint = $7EF3C8
; Another bitfield for progress
; t.dp s.bh
; t - smiths are currently tempering sword
; d - swordsmith rescued
; p - purple chest has been opened
; s - stumpy has been stumped
; b - bottle purchased from vendor
; h - bottle received from hobo
PROGLITE2 = $7EF3C9
; .d.. ....
; d - World (0: Light World | 1: Dark World)
SAVEWORLD = $7EF3CA
; Not used
UNUSED_7EF3CB = $7EF3CB
; Current follower ID
FOLLOWER = $7EF3CC
; Cache of follower properties
FOLLOWCYL = $7EF3CD
FOLLOWCYH = $7EF3CE
FOLLOWCXL = $7EF3CF
FOLLOWCXH = $7EF3D0
; Copies INDOORS
FOLLOWERINOUT = $7EF3D1
; Copies LAYER
FOLLOWERCLAYER = $7EF3D2
; Indicates the follower is currently following
; 0x00 - Following
; 0x80 - Not following
FOLLOWERING = $7EF3D3
; Unused
UNUSED_7EF3D4 = $7EF3D4
UNUSED_7EF3D5 = $7EF3D5
UNUSED_7EF3D6 = $7EF3D6
; Side Quest Progress Flags
; .dgo mwcn
; n - Met Mask Salesman (shown "need Ocarina" dialogue)
; c - Found cursed Cucco at ranch (shown first dialogue)
; w - Found withering Deku Scrub (shown first dialogue)
; m - Got Mushroom from Toadstool Woods
; o - Old Man Mountain quest active
; g - Goron quest active (collecting rock meat)
; d - (reserved)
SideQuestProg = $7EF3D7
; Side Quest Progress Flags 2
; .bts pfmr
; r - Ranch Girl transformed back (dialogue shown)
; m - Mask Salesman taught Song of Healing
; f - Fortune teller visited (any fortune)
; p - Potion shop visited with mushroom
; s - Deku Scrub soul freed (before mask given)
; t - Tingle met (any map purchased)
; b - Bean beanstalk grown (final stage)
SideQuestProg2 = $7EF3D8
; Player name
NAME1L = $7EF3D9
NAME1H = $7EF3DA
NAME2L = $7EF3DB
NAME2H = $7EF3DC
NAME3L = $7EF3DD
NAME3H = $7EF3DE
NAME4L = $7EF3DF
NAME4H = $7EF3E0
; Save file checksum; expected to be $55AA
SCHKSML = $7EF3E1
SCHKSMH = $7EF3E2
; Games played in each dungeon
GPSEWER = $7EF3E3
GPHYRULE = $7EF3E5
GPEAST = $7EF3E7
GPDESERT = $7EF3E9
GPAGA = $7EF3EB
GPSWAMP = $7EF3ED
GPPOD = $7EF3EF
GPMIRE = $7EF3F1
GPWOODS = $7EF3F3
GPICE = $7EF3F5
GPHERA = $7EF3F7
GPTHIEF = $7EF3F9
GPTROCK = $7EF3FB
GPGANON = $7EF3FD
; Games played for current segment
GPNOW = $7EF3FF
; Total games played
; No display on file select if 0xFFFF
GAMESPLAYED = $7EF401
; Big unused block
UNUSED_7EF403 = $7EF403
DEATHS_MAXED = $7EF405
; Inverse checksum for save file
SAVEICKSML = $7EF4FE
SAVEICKSMH = $7EF4FF

75
Core/structs.asm Normal file
View File

@@ -0,0 +1,75 @@
struct Sprite $7E0BA0
{
.BulletProof: skip 16
.AncillaId: skip 16
.Slot: skip 16
.OwDeath: skip 32
.Prize: skip 16
; 7E0BF0
; 7E0C9A
.OwScreen: skip 16
.Deflect: skip 16
.ForceDrop: skip 16
.OverlordRoom: skip 8
.BumpDamage: skip 16
.CurrDamage: skip 16
; 0CF2
; 0CFF
.yl: skip 16
.xl: skip 16
.yh: skip 16
.xh: skip 16
.vy: skip 16
.vx: skip 16
.sub_vy: skip 16
.sub_vx: skip 16
.action: skip 16
.frame: skip 16
.misc_a: skip 16
.misc_b: skip 16
.gfx: skip 16
.state: skip 16
.misc_c: skip 16
.TimerA: skip 16
.TimerB: skip 16
.TimerC: skip 16
.type: skip 16
.subtype: skip 16
.nbr_oam: skip 16
.hp: skip 16
.props: skip 16
.collide: skip 16
.delay: skip 16
.misc_d: skip 16
.recoil: skip 16
.misc_e: skip 16
.misc_f: skip 16
.misc_g: skip 16
.timer_d: skip 16
.death_timer: skip 16
.pause: skip 16
.timer_e: skip 16
.floor: skip 16
.recoil_y: skip 16
.recoil_x: skip 16
.oam_prop: skip 16
.collision_prop: skip 16
.z: skip 16
.vz: skip 16
.sub_vz: skip 16
}
endstruct
struct TimeState $7EE000
{
.Hours: skip 1
.Minutes: skip 1
.Speed: skip 1
.Padding: skip 13 ; Pad to $7EE010
.BlueVal: skip 2
.GreenVal: skip 2
.RedVal: skip 2
.TempColor: skip 2
.SubColor: skip 2
}
endstruct

759
Core/symbols.asm Normal file
View File

@@ -0,0 +1,759 @@
; =========================================================
; WRAM in Use
org $008000
base $7E0730 ; MAP16OVERFLOW free ram region
{
MenuScrollLevelV: skip 1
MenuScrollLevelH: skip 1
MenuScrollHDirection: skip 2
MenuItemValueSpoof: skip 2
ShortSpoof: skip 1
MusicNoteValue: skip 2
GoldstarOrHookshot: skip 1
Neck_Index: skip 1
Neck1_OffsetX: skip 1
Neck1_OffsetY: skip 1
Neck2_OffsetX: skip 1
Neck2_OffsetY: skip 1
Neck3_OffsetX: skip 1
Neck3_OffsetY: skip 1
Offspring1_Id: skip 1
Offspring2_Id: skip 1
Offspring3_Id: skip 1
Kydreeok_Id: skip 1
FishingOrPortalRod: skip 1
}
base off
; =========================================================
function RGBto555(R,G,B) = ((R/8)<<10)|((G/8)<<5)|(B/8) ; zarby
function menu_offset(y,x) = (y*64)+(x*2)
; Current Dream ID (0x00-0x03)
CurrentDream = $0426
; Current Song
CurrentSong = $030F
; 01 - Song of Healing
; 02 - Song of Time
; 03 - Song of Storms
SongFlag = $FE
; Overlay camera cache variable
CameraCache = $0632
; =========================================================
; The record format for the low table is 4 bytes:
; byte OBJ*4+0: xxxxxxxx
; byte OBJ*4+1: yyyyyyyy
; byte OBJ*4+2: cccccccc
; byte OBJ*4+3: vhoopppN
; The record format for the high table is 2 bits:
; bit 0/2/4/6 of byte OBJ/4: X
; bit 1/3/5/7 of byte OBJ/4: s
; Xxxxxxxxx = X position of the sprite. signed but see below.
; yyyyyyyy = Y position of the sprite.
; cccccccc = First tile of the sprite.
; N = Name table of the sprite. See below for VRAM address calculation
; ppp = Palette of the sprite. The first palette index is 128+ppp*16.
; oo = Sprite priority. See below for details.
; h/v = Horizontal/Vertical flip flags.
; s = Sprite size flag. See below for details.
OamPtr = $90
OamPtrH = $92
OamBackup = $0FEC
; =========================================================
; Sprite RAM
SprY = $0D00
SprX = $0D10
SprYH = $0D20
SprXH = $0D30
SprYSpeed = $0D40
SprXSpeed = $0D50
SprYRound = $0D60
SprXRound = $0D70
SprCachedX = $0FD8
SprCachedY = $0FDA
SprAction = $0D80 ; Indexes the action jump table
SprFrame = $0D90 ; Indexes the SprGfx for drawing
SprGfx = $0DC0 ; Determine the GFX used for the sprite
SprMiscA = $0DA0 ; Direction, position, or other misc usage
SprMiscB = $0DB0 ; Prober parent sprite ID, misc
SprMiscC = $0DE0 ; Cardinal direction the sprite is facing
SprMiscD = $0E90 ; Pikit stolen item, misc usage
SprMiscE = $0EB0 ; Head direction 0123 -> udlr
SprMiscF = $0EC0 ; Clones
SprMiscG = $0ED0 ; Probe whistle sfx
SprCustom = $1CC0 ;
; Used in sprite state 0x03 (falling in water)
; used as delay in most of the sprites
SprDelay = $0E80
SprFlash = $0B89 ; Enemy color flash buffer
SprTimerA = $0DF0 ; Action, decreased by 1 each frame
SprTimerB = $0E00 ; Animation, decreased by 1 each frame
SprTimerC = $0E10 ; decreased by 1 each frame
SprTimerD = $0EE0 ; decreased by 1 each frame
SprTimerE = $0F10 ; decreased by 1 each frame
SprTimerF = $0F80 ; Gravity, decreased by 2 each frame
SprSlot = $0FA0 ; Current sprite slot being executed
SprStunTimer = $0B58 ; counts down from 0xFF
SprPause = $0F00 ; Inactive if nonzero
SprFloor = $0F20 ; 0 (top layer), 1 (bottom layer)
SprType = $0E20 ; Sprite ID
SprSubtype = $0E30 ; Sprite subtype
; hmwo oooo
; o - define the number of OAM slots used by the sprite
; w - Causes enemies to go towards the walls
; m - Master sword ceremony sprite flag
; h - If set, harmless. Unset you take damage from contact.
SprNbrOAM = $0E40
SprHealth = $0E50
; 0x00 - Sprite is dead, totally inactive
; 0x01 - Sprite falling into a pit with generic animation.
; 0x02 - Sprite transforms into a puff of smoke, often producing an item
; 0x03 - Sprite falling into deep water (optionally making a fish jump up?)
; 0x04 - Death mode for bosses
; 0x05 - Sprite falling into a pit that has a special animation
; 0x06 - Death Mode for normal creatures.
; 0x08 - Sprite is being spawned at load time.
; An initialization routine will be run for one frame,
; and then move on to the active state (0x09) next frame.
; 0x09 - Sprite is in the normal, active mode.
; 0x0A - Sprite is being carried by the player.
; 0x0B - Sprite is frozen and / or stunned.
SprState = $0DD0
; nios pppt
; n - if set, don't draw extra death anim
; i - impervious to attacks and collision (0: normal | 1: clink)
; o - shadow size (0: normal | 1: small)
; s - shadow (0: no shadow | 1: shadow)
; p - palette used for OAM props
; t - name table used for OAM props
SprGfxProps = $0E60
; Direction of sprite collision with wall
SprCollision = $0E70
; Definitely closely tied to the process of a sprite taking damage.
; Seems to serve as a palette cycling index, or a state variable.
; When this value is positive
; 0x80 - Signal that the recoil process has finished
; and will terminate during this frame.
SprRecoil = $0EA0 ; Recoil Timer
; abbbbbbb:
; a - start death timer
; b - death timer
SprDeath = $0EF0
SprYRecoil = $0F30
SprXRecoil = $0F40
; DIWS UUUU
; D - boss death
; I - Impervious to all attacks
; W - Water slash
; S - Draw Shadow
; U - Unused
SprProps = $0F50
; ISPH HHHH
; I - ignore collisions
; S - Statis (not alive eg beamos)
; P - Persist code still run outside of camera
; H - Hitbox
SprHitbox = $0F60
SprHeight = $0F70 ; Distance from the shadow
SprHeightS = $0F90 ; Distance from the shadow subpixel
SprFreeze = $0FC1 ; Seems to freeze sprites
; Primarily deals with bump damage
; tzpd bbbb
; t - TODO
; z - High priority target for bees to give hints
; p - Powder interaction (0: normal | 1: ignore)
; d - Behavior when a boss spawns (0: die | 1: live)
; b - bump damage class
; Bump damage classes are read from a table at $06F42D
; Each table entry has 3 values, for green, blue, and red mails
; class g b r
; 0x00 2 1 1
; 0x01 4 4 4
; 0x02 0 0 0
; 0x03 8 4 2
; 0x04 8 8 8
; 0x05 16 8 4
; 0x06 32 16 8
; 0x07 32 24 16
; 0x08 24 16 8
; 0x09 64 48 24
SprBump = $0CD2
; Damage sprite is enduring
SprDmgTaken = $0CE2
; Sprite Deflection Properties
; abcdefgh
; a - If set, sprite is active
; b - Same as bit 'a' for Zora.
; c - Never queried, pushable interaction flag
; d - If hit from front, deflect Ice Rod, Somarian missile,
; boomerang, hookshot, and sword beam, and arrows stick in
; it harmlessly. If bit 1 is also set, frontal arrows will
; instead disappear harmlessly.
; e - If set, sprite collides with less tiles than usual
; f - If set, impervious to sword and hammer type attacks
; g - If set, impervious to arrows, but may have other additional meanings.
; h - Handles behavior with previous deaths flagged in $7FDF80 (0: default | 1: ignore)
SprDefl = $0CAA
; iwbs pppp
; i - disable tile interaction
; w - something water
; b - sprite is blocked by shield
; s - taking damage sfx to use TODO name
; p - prize pack
SprPrize = $0BE0
; tttt a.bp
; t - tile interaction hitbox
; a - deflect arrows TODO VERIFY
; b - boss death
; p - Sprite ignores falling into a pit when frozen?
SprTileDie = $0B6B
; For sprites that interact with speical objects (arrows in particular)
; the special object will identify its type to the sprite via this location.
SprSpecial = $0BB0
; If nonzero, ancillae do not interact with the sprite
; Bulletproof
SprBulletproof = $0BA0
SprRoom = $0C9A ;X W Contains the area or room id the sprite has been loaded in
SprDrop = $0CBA ;X W 00: Drop nothing, 01: drop normal key, 03: Drop green rupee, OtherValues: Drop big key
; Overlord
OverlordId = $0B00
OverlordX = $0B08
OverlordXH = $0B10
OverlordY = $0B18
OverlordYH = $0B20
OverlordTimerA = $0B28
OverlordTimerB = $0B30
OverlordTimerC = $0B38
; =========================================================
; Sprite Functions
SpriteData_OAMProp = $0DB359
; Clear all properties for sprites
SpritePrep_ResetProperties = $0DB871
; set the oam coordinate for the sprite draw
Sprite_PrepOamCoord = $06E416
; Draw the sprite depending of the position of the player
; (if he has to be over or under link)
Sprite_OAM_AllocateDeferToPlayer = $06F864
OAM_AllocateFromRegionA = $0DBA80 ; Above
OAM_AllocateFromRegionB = $0DBA84 ; Below
OAM_AllocateFromRegionC = $0DBA88 ; Above
OAM_AllocateFromRegionD = $0DBA8C ; Above
OAM_AllocateFromRegionE = $0DBA90 ; Above
OAM_AllocateFromRegionF = $0DBA94 ; Above
Sprite_DrawMultiple_quantity_preset = $05DF70
; check if the sprite is getting damage from player or items
Sprite_CheckDamageFromPlayer = $06F2AA
; check if the sprite is touching the player to damage
Sprite_CheckDamageToPlayer = $06F121
; damage the player everywhere on screen?
Sprite_AttemptDamageToPlayerPlusRecoil = $06F41F
; makes all the sprites on screen shaking
ApplyRumbleToSprites = $0680FA
Sprite_MoveLong = $1D808C
Sprite_ProjectSpeedTowardsPlayer = $06EA1A
Sprite_Decelerate_X = $05E657
Sprite_Decelerate_Y = $05E666
; =========================================================
; returns carry clear if there was no overlap
; args:
pos1_x_low = $00
pos1_y_low = $01
pos1_size = $02
pos1_height = $03
pos2_x_low = $04
pos2_y_low = $05
pos2_size = $06
pos2_height = $07
pos1_x_high = $08
pos1_y_high = $09
pos2_x_high = $0A
pos2_y_high = $0B
ans_low = $0F
ans_high = $0C
CheckIfHitBoxesOverlap = $0683E6
; $0FD8 = sprite's X coordinate
; $0FDA = sprite's Y coordinate
Sprite_Get16BitCoords_Local = $0684C1
Sprite_Get_16_bit_Coords = $0684BD
; load / draw a 16x16 sprite
Sprite_PrepAndDrawSingleLarge = $06DBF0
; load / draw a 8x8 sprite
Sprite_PrepAndDrawSingleSmall = $06DBF8
; draw shadow (requires additional oam allocation)
Sprite_DrawShadow = $06DC54
Sprite_DrawWaterRipple = $059FFA
Sprite_DrawRippleIfInWater = $1EFF8D
; check if the sprite is colliding with a solid tile set $0E70, X
; ----udlr , u = up, d = down, l = left, r = right
Sprite_CheckTileCollision = $06E496
Sprite_CheckTileCollision_long = $06E496
; $00[0x02] - Entity Y coordinate
; $02[0x03?] - Entity X coordinate
; $0FA5 - Tile ID result
Sprite_GetTileAttr = $06E87B
; check if the sprite is colliding with a solid sloped tile
Sprite_CheckSlopedTileCollision = $06E8FD
; set the velocity x,y towards the player (A = speed)
Sprite_ApplySpeedTowardsPlayer = $06EA12
; \return $0E is low byte of player_y_pos - sprite_y_pos
; \return $0F is low byte of player_x_pos - sprite_x_pos
Sprite_DirectionToFacePlayer = $06EAA0
; if Link is to the left of the sprite, Y = 1, otherwise Y = 0.
Sprite_IsToRightOfPlayer = $06EACD
; return Y=1 sprite is below player, otherwise Y = 0
Sprite_IsBelowPlayer = $06EAE4
; $06 = sprite's Y coordinate
; $07 = sprite's X coordinate
Sprite_IsBelowLocation = $06EB1D
; check damage done to player if they collide on same layer
Sprite_CheckDamageToPlayerSameLayer = $06F129
; check damage done to player if they collide even if they are not on same layer
Sprite_CheckDamageToPlayerIgnoreLayer = $06F131
; play a sound loaded in A
Sound_SetSfx1PanLong = $0DBB6E
Sound_SetSfx2PanLong = $0DBB7C
Sound_SetSfx3PanLong = $0DBB8A
; =========================================================
; spawn a new sprite on screen, A = sprite id
; when using this function you have to set the position yourself
; these values belong to the sprite who used that function not the new one
; $00 low x, $01 high x
; $02 low y, $03 high y
; $04 height, $05 low x (overlord)
; $06 high x (overlord), $07 low y (overlord)
; $08 high y (overlord)
Sprite_SpawnDynamically = $1DF65D
Sprite_SpawnDynamically_slot_limited = $1DF65F
Sprite_SetSpawnedCoords = $09AE64
Sprite_SetSpawnedCoordinates = $09AE64
; move the sprite if he stand on a conveyor belt
Sprite_ApplyConveyorAdjustment = $1D8010
; Setup sprite hitbox for comparison with scrap ram
Sprite_SetupHitBoxLong = $0683EA
; player can't pass through the sprite
Sprite_BehaveAsBarrier = $1EF4F3
Sprite_PlayerCantPassThrough = $1EF4F3
; player can't hookshot to that sprite
Sprite_CancelHookshot = $0FF540
Sprite_NullifyHookshotDrag = $0FF540
; show a message box without any condition
; A = low byte of message ID to use.
; Y = high byte of message ID to use.
Sprite_ShowMessageUnconditional = $05E219
; show a message if we press A and face the sprite
; A = low byte of message ID to use.
; Y = high byte of message ID to use.
Sprite_ShowSolicitedMessage = $05E1A7
Sprite_ShowSolicitedMessageIfPlayerFacing = $05E1A7
; show a message if we touch the sprite
; should be used with Sprite_PlayerCantPassThrough
; A = low byte of message ID to use.
; Y = high byte of message ID to use.
Sprite_ShowMessageOnContact = $05E1F0
Sprite_ShowMessageFromPlayerContact = $05E1F0
; Parameters: Stack, A
JumpTableLocal = $008781
UseImplicitRegIndexedLocalJumpTable = $008781
EnableForceBlank = $00893D
Snitch_SpawnGuard = $09C02F
Sprite_KillFriends = $09EF56
Sprite_KillSelf = $09F1F8
Dungeon_SpriteInducedTilemapUpdate = $01E7A9
; =========================================================
; $04 = X
; $05 = HighX
; $06 = Y
; $07 = HighY
; A = Speed
; \return $00 - Y Velocity
; \return $01 - X Velocity
Sprite_ProjectSpeedTowardsEntityLong = $06EA22
; =========================================================
; Guard and Prober functions
; SprMiscB contains the ID of the parent sprite to alert
Guard_ChaseLinkOnOneAxis = $05C542
Guard_ParrySwordAttacks = $06EB5E
Probe_CheckTileSolidity = $0DC26E
ProbeAndSparkCheckDirXSpeed = $05C359
ProbeAndSparkCheckDirYSpeed = $05C361
ProbeAndSparkXSpeed = $05C369
ProbeAndSparkYSpeed = $05C371
ColinearDirections = $05C381
OrthogonalDirections = $05C389
ColinearNextDirections = $05C391
OrthogonalNextDirections = $05C399
Sprite_SpawnProbeAlways_long = $05C66E
Sprite_TrackBodyToHead = $05DCA2
; =========================================================
; Misc long functions
GetRandomInt = $0DBA71
Sprite_SpawnFireball = $0DDA06
Sprite_SpawnSmallSplash = $1EA820
Sprite_SpawnSparkleGarnish = $058008
Sprite_SpawnPoofGarnish = $05AB9C
Sprite_CheckIfLifted = $06AA0C
Sprite_TransmuteToBomb = $06AD50
Sprite_RepelDash = $079291
Sprite_LoadGfxProperties = $00FC41
ThrownSprite_TileAndSpriteInteraction_long = $06DFF2
Overworld_DrawMap16_Persist = $1BC97C
; =========================================================
; Local functions which may be useful for sprites
; Sprite_AttemptZapDamage - 06EC02
; =========================================================
; Misc RAM
FrameCounter = $1A ; value that is increasing every frame
Indoor = $1B ; 0: outside, 1: indoor
UpdPalFlag = $15 ; Update all palettes $7EC500-$7EC700 if non-zero
RoomIndex = $A0 ; Return the current room ID
AreaIndex = $8A ; Return the current overworld area ID
MsgChoice = $1CE8 ; Choice made in a message box
; set the mosaic setting ($2106) XXXXDCBA
; [ABCD BG1/BG2/BG3/BG4][X size of the mosaic pixels 0-16]
Mosaic = $95
DungeonMainCheck = $021B
SpriteRanCheck = $8E
; Underworld:
; Flags sprite deaths in underworld based on slot.
; Indexed by 2 * room ID.
; Overworld:
; Holds ID+1 of sprite with each position being assigned a unique byte
; 0x00 indicates no sprite in this slot
UWDEATH = $7FDF80
RebuildHUD_long = $0DFA58
ForcePrizeDrop_long = $06FA54
TileDetect_BigArea_long = $07CF0A
Follower_Initialize = $099EFC
HandleFollowersAfterMirroring = $07AAA2
; =========================================================
; Controllers
; BYSTUDLR
; [B BButton][Y YButton]
; [SSelect Button][TStart Button]
; [UDLR dpad buttons Up, Down, Left, Right]
RawJoypad1L = $F0
; AXLRIIII
; [A AButton][X Xbutton][L LButton][R RButton][I = controller ID]
RawJoypad1H = $F2
; BYSTUDLR
; [B BButton][Y YButton]
; [SSelect Button][TStart Button]
; [UDLR dpad buttons Up, Down, Left, Right]
PressPad1L = $F4
; AXLRIIII
; [A AButton][X Xbutton]
; [L LButton][R RButton][I = controller ID]
PressPad1H = $F6
ButtonAFlag = $3B ; bit7: Button A is down (A-------)
; Timer for B button
; ssss tttt
; s - spin attack in action; set to 0x9
; t - sword swing timer
; 0x00 - No swing
; —0x08 - Sword swing
; 0x09 - Sword primed
; —0x0C - Poking wall
;
; Also used as a 16-bit countdown for various cutscenes:
; Ether tablet: 0x00C0
; Bombos tablet: 0x00E0
; Desert tablet: 0x0001
BFLAG = $3C
; =========================================================
; Ancilla
AnciOAMPrior = $0280 ; Ancilla oam priority if non zero use highest priority for draw
AnciColTimer = $028A ; Ancilla collision timer to prevent doing collision code too often set to 06 after a collision
AnciZSpeed = $0294 ; Ancilla Z Speed
AnciHeight = $029E ; Ancilla Height how far it is from its shadow
AnciHeightH = $02A8 ; Ancilla Height hight byte how far it is from its shadow
AnciMiscA = $0BF0 ; This can be used to do anything in ancilla
AnciMiscB = $0C54 ; This can be used to do anything in ancilla
AnciMiscC = $0C5E ; This can be used to do anything in ancilla (often used to track item received)
AnciMiscD = $0C72 ; This can be used to do anything in ancilla (often used to track direction)
; General use variable for ancillae. Only intended for front slots.
; LENGTH: 0x05
AnciMiscJ = $03CA
; General use variable for ancillae.
; LENGTH: 0x0A
ANC0MISCB = $0385
AnciTimerA = $0C68 ; This is a timer, value is decreased by 1 every frame
AnciY = $0BFA ; Position Y of the ancilla (Up to Down)
AnciX = $0C04 ; Position X of the ancilla (Left to Right)
AnciYH = $0C0E ; High (often determine the room) Position Y of the ancilla (Up to Down)
AnciXH = $0C18 ; High (often determine the room) Position X of the ancilla (Left to Right)
AnciXSpeed = $0C22 ; Y Speed of the ancilla can go negative to go up
AnciYSpeed = $0C2C ; X Speed of the ancilla can go negative to go left
AnciLayer = $0C7C ; return the floor where the ancilla is
AnciOamBuf = $0C86 ; Oam buffer?
AnciOAMNbr = $0C90 ; Number of OAM slots used
AnciYsub = $0C36 ; sub pixel for Y position for ancilla
AnciXsub = $0C40 ; sub pixel for X position for ancilla
; Ancilla IDs
; db $00 ; 0x00 - NOTHING
; db $08 ; 0x01 - SOMARIA BULLET
; db $0C ; 0x02 - FIRE ROD SHOT
; db $10 ; 0x03 - UNUSED
; db $10 ; 0x04 - BEAM HIT
; db $04 ; 0x05 - BOOMERANG
; db $10 ; 0x06 - WALL HIT
; db $18 ; 0x07 - BOMB
; db $08 ; 0x08 - DOOR DEBRIS
; db $08 ; 0x09 - ARROW
; db $08 ; 0x0A - ARROW IN THE WALL
; db $00 ; 0x0B - ICE ROD SHOT
; db $14 ; 0x0C - SWORD BEAM_BOUNCE
; db $00 ; 0x0D - SPIN ATTACK FULL CHARGE SPARK
; db $10 ; 0x0E - BLAST WALL EXPLOSION
; db $28 ; 0x0F - BLAST WALL EXPLOSION
; db $18 ; 0x10 - BLAST WALL EXPLOSION
; db $10 ; 0x11 - ICE ROD WALL HIT
; db $10 ; 0x12 - BLAST WALL EXPLOSION
; db $10 ; 0x13 - ICE ROD SPARKLE
; db $10 ; 0x14 - BAD POINTER
; db $0C ; 0x15 - SPLASH
; db $08 ; 0x16 - HIT STARS
; db $08 ; 0x17 - SHOVEL DIRT
; db $50 ; 0x18 - ETHER SPELL
; db $00 ; 0x19 - BOMBOS SPELL
; db $10 ; 0x1A - POWDER DUST
; db $08 ; 0x1B - SWORD WALL HIT
; db $40 ; 0x1C - QUAKE SPELL
; db $00 ; 0x1D - SCREEN SHAKE
; db $0C ; 0x1E - DASH DUST
; db $24 ; 0x1F - HOOKSHOT
; db $10 ; 0x20 - BLANKET
; db $0C ; 0x21 - SNORE
; db $08 ; 0x22 - ITEM GET
; db $10 ; 0x23 - LINK POOF
; db $10 ; 0x24 - GRAVESTONE
; db $04 ; 0x25 - BAD POINTER
; db $0C ; 0x26 - SWORD SWING SPARKLE
; db $1C ; 0x27 - DUCK
; db $00 ; 0x28 - WISH POND ITEM
; db $10 ; 0x29 - MILESTONE ITEM GET
; db $14 ; 0x2A - SPIN ATTACK SPARKLE A
; db $14 ; 0x2B - SPIN ATTACK SPARKLE B
; db $10 ; 0x2C - SOMARIA BLOCK
; db $08 ; 0x2D - SOMARIA BLOCK FIZZ
; db $20 ; 0x2E - SOMARIA BLOCK FISSION
; db $10 ; 0x2F - LAMP FLAME
; db $10 ; 0x30 - BYRNA WINDUP SPARK
; db $10 ; 0x31 - BYRNA SPARK
; db $04 ; 0x32 - BLAST WALL FIREBALL
; db $00 ; 0x33 - BLAST WALL EXPLOSION
; db $80 ; 0x34 - SKULL WOODS FIRE
; db $10 ; 0x35 - MASTER SWORD GET
; db $04 ; 0x36 - FLUTE
; db $30 ; 0x37 - WEATHERVANE EXPLOSION
; db $14 ; 0x38 - CUTSCENE DUCK
; db $10 ; 0x39 - SOMARIA PLATFORM POOF
; db $00 ; 0x3A - BIG BOMB EXPLOSION
; db $10 ; 0x3B - SWORD UP SPARKLE
; db $00 ; 0x3C - SPIN ATTACK CHARGE SPARKLE
; db $00 ; 0x3D - ITEM SPLASH
; db $08 ; 0x3E - RISING CRYSTAL
; db $00 ; 0x3F - BUSH POOF
; db $10 ; 0x40 - DWARF POOF
; db $08 ; 0x41 - WATERFALL SPLASH
; db $78 ; 0x42 - HAPPINESS POND RUPEES
; db $80 ; 0x43 - GANONS TOWER CUTSCENE
AnciType = $0C4A
AncillaInit_SetCoordsAndExit = $0980C3
Ancilla_PrepOAMCoord_long = $08F6D9
Ancilla_SetOAM_XY_long = $08F6FE
Ancilla_GetRadialProjection_long = $08FB23
Ancilla_CheckForAvailableSlot = $0FF577
Ancilla_CheckInitialTile_A = $099DD3
Ancilla_CheckSpriteCollision_long = $088DA2
Ancilla_CheckTileCollision_long = $08923B
Ancilla_CheckTileCollision_Class2_long = $089243
Ancilla_CalculateSFXPan = $0DBB5E
Ancilla_CheckDamageToSprite = $06ECB7
; Table of ancilla properties
AncillaObjectAllocation = $08806F
AncillaAdd_BombosSpell = $08AF66
AncillaAdd_FireRodShot = $0880B3
AncillaAdd_Snoring = $0980C8
AncillaAdd_Bomb = $09811F
AncillaAdd_Boomerang = $09820F
AncillaAdd_BoomerangAsClink = $098345
AncillaAdd_DugUpFlute = $098C73
AncillaAdd_ChargedSpinAttackSparkle = $098CB1
AncillaAdd_ExplodingWeatherVane = $098D11
AncillaAdd_CutsceneDuck = $098D90
AncillaAdd_SomariaPlatformPoof = $098DD2
AncillaAdd_SuperBombExplosion = $098DF9
ConfigureRevivalAncillae = $098E4E
AncillaAdd_CaneOfByrnaInitSpark = $098EE0
AncillaAdd_LampFlame = $098F1C
AncillaAdd_ShovelDirt = $098F5B
AncillaAdd_BlastWallFireball = $099031
AncillaAdd_Arrow = $0990A4
AncillaAdd_CapePoof = $09912C
AncillaAdd_BushPoof = $0991C3
AncillaAdd_EtherSpell = $0991FC
AncillaAdd_VictorySpin = $0992AC
AncillaAdd_MagicPowder = $0992F0
AncillaAdd_WallTapSpark = $099395
AncillaAdd_SwordSwingSparkle = $0993C2
AncillaAdd_QuakeSpell = $099589
AncillaAdd_IceRodShot = $099863
AncillaAdd_Splash = $0998FC
AncillaAdd_Hookshot = $099B10
AncillaAdd_Blanket = $098091
AddHappinessPondRupees = $098AE0
DeleteBoomAndByrnaSparks = $0FFD86
Sparkle_PrepOAMFromRadial = $08DA17
Fireball_SpawnTrailGarnish = $09B020
SpriteSFX_QueueSFX2WithPan = $0DBB7C
SpriteSFX_QueueSFX3WithPan = $0DBB8A

415
Core/tables.asm Normal file
View File

@@ -0,0 +1,415 @@
; Main Modules
Module00_Intro
Module01_FileSelect
Module02_CopyFile
Module03_KILLFile
Module04_NameFile
Module05_LoadFile
Module06_UnderworldLoad
Module07_Underworld
Module08_OverworldLoad
Module09_Overworld
Module0A_OverworldSpecialLoad
Module0B_OverworldSpecial
Module0C_Unused
Module0D_Unused
Module0E_Interface
Module0F_SpotlightClose
Module10_SpotlightOpen
Module11_UnderworldFallingEntrance
Module12_GameOver
Module13_BossVictory_Pendant
Module14_Attract
Module15_MirrorWarpFromAga
Module16_BossVictory_Crystal
Module17_SaveAndQuit
Module18_GanonEmerges
Module19_TriforceRoom
Module1A_Credits
Module1B_SpawnSelect
; Garnish IDs
Garnish01_FireSnakeTail
Garnish02_MothulaBeamTrail
Garnish03_FallingTile
Garnish04_LaserTrail
Garnish05_SimpleSparkle
Garnish06_ZoroTrail
Garnish07_BabasuFlash
Garnish08_KholdstareTrail
Garnish09_LightningTrail
Garnish0A_CannonSmoke
Garnish0B_WaterTrail
Garnish0C_TrinexxIceBreath
$0000
Garnish0E_TrinexxFireBreath
Garnish0F_BlindLaserTrail
Garnish10_GanonBatFlame
Garnish11_WitheringGanonBatFlame
Garnish12_Sparkle
Garnish13_PyramidDebris
Garnish14_KakKidDashDust
Garnish15_ArrghusSplash
Garnish16_ThrownItemDebris
Module09_Overworld:
Module09_00_PlayerControl ; 0x00
Module09_LoadAuxGFX ; 0x01
Module09_TriggerTilemapUpdate ; 0x02
Module09_LoadNewMapAndGFX ; 0x03
Module09_LoadNewSprites ; 0x04
Overworld_StartScrollTransition ; 0x05
Overworld_RunScrollTransition ; 0x06
Overworld_EaseOffScrollTransition ; 0x07
Overworld_FinalizeEntryOntoScreen ; 0x08
Module09_09_OpenBigDoorFromExiting ; 0x09
Module09_0A_WalkFromExiting_FacingDown ; 0x0A
Module09_0B_WalkFromExiting_FacingUp ; 0x0B
Module09_0C_OpenBigDoor ; 0x0C
Overworld_StartMosaicTransition ; 0x0D
Overworld_LoadSubscreenAndSilenceSFX1 ; 0x0E
Module09_LoadAuxGFX ; 0x0F
Module09_TriggerTilemapUpdate ; 0x10
Module09_LoadNewMapAndGFX ; 0x11
Module09_LoadNewSprites ; 0x12
Overworld_StartScrollTransition ; 0x13
Overworld_RunScrollTransition ; 0x14
Overworld_EaseOffScrollTransition ; 0x15
Module09_FadeBackInFromMosaic ; 0x16
Overworld_StartMosaicTransition ; 0x17
Module09_18 ; 0x18
Module09_19 ; 0x19
Module09_LoadAuxGFX ; 0x1A
Module09_TriggerTilemapUpdate ; 0x1B
Module09_1C ; 0x1C
Module09_1D ; 0x1D
Module09_1E ; 0x1E
Module09_1F ; 0x1F
Overworld_ReloadSubscreenOverlay ; 0x20
Module09_21 ; 0x21
Module09_22 ; 0x22
Module09_MirrorWarp ; 0x23
Overworld_StartMosaicTransition ; 0x24
Module09_25 ; 0x25
Module09_LoadAuxGFX ; 0x26
Module09_TriggerTilemapUpdate ; 0x27
Overworld_LoadAndBuildScreen ; 0x28
Module09_FadeBackInFromMosaic ; 0x29
Module09_2A_RecoverFromDrowning ; 0x2A
Module09_2B ; 0x2B
Module09_MirrorWarp ; 0x2C
Module09_2D_WaitForBird ; 0x2D
Module09_2E_Whirlpool ; 0x2E
Module09_2F
Module07_Underworld:
Module07_00_PlayerControl ; 0x00
Module07_01_IntraroomTransition ; 0x01
Module07_02_InterroomTransition ; 0x02
Module07_03_OverlayChange ; 0x03
Module07_04_UnlockDoor ; 0x04
Module07_05_ControlShutters ; 0x05
Module07_06_FatInterRoomStairs ; 0x06
Module07_07_FallingTransition ; 0x07
Module07_08_NorthIntraRoomStairs ; 0x08
Module07_09_OpenCrackedDoor ; 0x09
Module07_0A_ChangeBrightness ; 0x0A
Module07_0B_DrainSwampPool ; 0x0B
Module07_0C_FloodSwampWater ; 0x0C
Module07_0D_FloodDam ; 0x0D
Module07_0E_SpiralStairs ; 0x0E
Module07_0F_LandingWipe ; 0x0F
Module07_10_SouthIntraRoomStairs ; 0x10
Module07_11_StraightInterroomStairs ; 0x11
Module07_11_StraightInterroomStairs ; 0x12
Module07_11_StraightInterroomStairs ; 0x13
Module07_14_RecoverFromFall ; 0x14
Module07_15_WarpPad ; 0x15
Module07_16_UpdatePegs ; 0x16
Module07_17_PressurePlate ; 0x17
Module07_18_RescuedMaiden ; 0x18
Module07_19_MirrorFade ; 0x19
Module07_1A_RoomDraw_OpenTriforceDoor_bounce ; 0x1A
Link_ControlHandler:
LinkState_Default ; 0x00
LinkState_Pits ; 0x01
LinkState_Recoil ; 0x02
LinkState_SpinAttack ; 0x03
LinkState_Swimming ; 0x04
LinkState_OnIce ; 0x05
LinkState_Recoil ; 0x06
LinkState_Zapped ; 0x07
LinkState_UsingEther ; 0x08
LinkState_UsingBombos ; 0x09
LinkState_UsingQuake ; 0x0A - DekuHover
LinkState_HoppingSouthOW ; 0x0B
LinkState_HoppingHorizontallyOW ; 0x0C
LinkState_HoppingDiagonallyUpOW ; 0x0D
LinkState_HoppingDiagonallyDownOW ; 0x0E
LinkState_0F ; 0x0F
LinkState_0F ; 0x10
LinkState_Dashing ; 0x11
LinkState_ExitingDash ; 0x12
LinkState_Hookshotting ; 0x13
LinkState_CrossingWorlds ; 0x14
LinkState_ShowingOffItem ; 0x15
LinkState_Sleeping ; 0x16
LinkState_Bunny ; 0x17
LinkState_HoldingBigRock ; 0x18
LinkState_ReceivingEther ; 0x19
LinkState_ReceivingBombos ; 0x1A
LinkState_ReadingDesertTablet ; 0x1B
LinkState_TemporaryBunny ; 0x1C
LinkState_TreePull ; 0x1D
LinkState_SpinAttack ; 0x1E
Link_HandleYItem:
LinkItem_Bombs
LinkItem_Boomerang
LinkItem_Bow
LinkItem_Hammer
LinkItem_Rod
LinkItem_Rod
LinkItem_Net
LinkItem_ShovelAndFlute
LinkItem_Lamp
LinkItem_Powder
LinkItem_Bottle
LinkItem_Book
LinkItem_CaneOfByrna
LinkItem_Hookshot
LinkItem_Bombos
LinkItem_Ether
LinkItem_Quake
LinkItem_CaneOfSomaria
LinkItem_Cape
LinkItem_Mirror
; Liftable object palettes
; Sprites Aux 2 #8 for DW
; Sprites Aux 2 #6 for LW
; #7 and #9 are the yellow bush palettes
OverworldPaletteSet:
db $00, $FF, $07, $FF ; 0x00
db $00, $01, $07, $FF ; 0x01
db $00, $02, $07, $FF ; 0x02
db $00, $03, $07, $FF ; 0x03
db $00, $04, $07, $FF ; 0x04
db $00, $05, $07, $FF ; 0x05
db $00, $06, $07, $FF ; 0x06
db $07, $06, $05, $FF ; 0x07
db $00, $08, $07, $FF ; 0x08
db $00, $09, $07, $FF ; 0x09
db $00, $0A, $07, $FF ; 0x0A
db $00, $0B, $07, $FF ; 0x0B
db $00, $FF, $07, $FF ; 0x0C
db $00, $FF, $07, $FF ; 0x0D
db $03, $04, $07, $FF ; 0x0E
db $04, $04, $03, $FF ; 0x0F
db $10, $FF, $06, $FF ; 0x10
db $10, $01, $06, $FF ; 0x11
db $10, $11, $06, $FF ; 0x12
db $10, $03, $06, $FF ; 0x13
db $10, $04, $06, $FF ; 0x14
db $10, $05, $06, $FF ; 0x15
db $10, $06, $06, $FF ; 0x16
db $12, $13, $04, $FF ; 0x17
db $12, $05, $04, $FF ; 0x18
db $10, $09, $06, $FF ; 0x19
db $10, $0B, $06, $FF ; 0x1A
db $10, $0C, $06, $FF ; 0x1B
db $10, $0D, $06, $FF ; 0x1C
db $10, $0E, $06, $FF ; 0x1D
db $10, $0F, $06, $FF ; 0x1E
LDA.l UnderworldPaletteSets+0,X
STA.w $0AB6 ; PALBG
LDA.l UnderworldPaletteSets+1,X
STA.w $0AAC ; PALSPR0
LDA.l UnderworldPaletteSets+2,X
STA.w $0AAD ; PALSPR1
LDA.l UnderworldPaletteSets+3,X
STA.w $0AAE ; PALSPR2
; PALBG
; 0x00 - Kalyxo Castle
; 0x01 - Blue
; 0x02 - House
; 0x03 - Green
; 0x04 - Glacia Estate Ice
; 0x05 - Zora Temple
; 0x06 - Tail Palace Pink
; 0x07 - Goron Mines Cave Red
; 0x08 - Mushroom Grotto Gray
; 0x09
; 0x0A (10) - Ranch Pink
; 0x0B (11) - Another green
; 0x0C - Goron Mines Cave Red
; 0x0D
; 0x0E
; 0x0F
; 0x10 -
; 0x (19) -
UnderworldPaletteSets:
db $00, $00, $03, $01 ; 0x00
db $02, $00, $03, $01 ; 0x01
db $04, $00, $0A, $01 ; 0x02 House
db $06, $00, $01, $07 ; 0x03 Fortress of Secrets
db $0A, $02, $02, $07 ; 0x04 Zora Temple
db $04, $04, $03, $0A ; 0x05 House
db $0C, $05, $08, $14 ; 0x06 Tail Palace
db $0E, $00, $03, $0A ; 0x07 Goron Mines/Caves
db $02, $00, $0F, $14 ; 0x08 Castle Basement
db $0A, $02, $00, $07 ; 0x09
db $02, $00, $0F, $0C ; 0x0A
db $06, $00, $06, $07 ; 0x0B
db $00, $00, $0E, $12 ; 0x0C Kalyxo Castle
db $12, $05, $05, $0B ; 0x0D
db $12, $00, $02, $0C ; 0x0E
db $10, $05, $0A, $07 ; 0x0F Mushroom Grotto
db $10, $00, $10, $0C ; 0x10 Ranch?
db $16, $07, $02, $07 ; 0x11 Hall of Secrets
db $16, $00, $07, $0F ; 0x12
db $08, $00, $04, $0C ; 0x13 Glacia Estate
db $08, $00, $04, $09 ; 0x14
db $04, $00, $03, $01 ; 0x15 House
db $14, $00, $04, $04 ; 0x16
db $14, $00, $14, $0C ; 0x17
db $18, $05, $07, $0B ; 0x18 Lava Lands Cave/Turtle Rock
db $18, $06, $10, $0C ; 0x19
db $1A, $05, $08, $14 ; 0x1A Dragon Ship
db $1A, $02, $00, $07 ; 0x1B Dragon Ship
db $06, $00, $03, $0A ; 0x1C
db $1C, $00, $03, $01 ; 0x1D
db $1E, $00, $0B, $11 ; 0x1E Swordsmith
db $04, $00, $0B, $11 ; 0x1F
db $0E, $00, $00, $02 ; 0x20
db $20, $08, $13, $0D ; 0x21 Ganondorf Boss
db $0A, $00, $03, $0A ; 0x22 Zora Temple
db $14, $00, $04, $04 ; 0x23
db $1A, $02, $02, $07 ; 0x24 Dragon Ship
db $1A, $0A, $00, $00 ; 0x25 Dragon Ship
db $00, $00, $03, $02 ; 0x26
db $0E, $00, $03, $07 ; 0x27
db $1A, $05, $05, $0B ; 0x28 Dragon Ship
PrizePackRarities:
{
db $01 ; pack 1 : 50%
db $01 ; pack 2 : 50%
db $01 ; pack 3 : 50%
db $00 ; pack 4 : 100%
db $01 ; pack 5 : 50%
db $01 ; pack 6 : 50%
db $01 ; pack 7 : 50%
db $00 ; pack 8 : 100% - doesn't exist
}
ItemDropBounceProps:
{
db $24 ; GREEN RUPEE
db $24 ; BLUE RUPEE
db $24 ; RED RUPEE
db $20 ; BOMB REFILL 1
db $20 ; BOMB REFILL 4
db $20 ; BOMB REFILL 8
db $24 ; SMALL MAGIC DECANTER
db $24 ; LARGE MAGIC DECANTER
db $24 ; ARROW REFILL 5
db $24 ; ARROW REFILL 10
db $00 ; FAIRY
db $24 ; SMALL KEY
db $20 ; BIG KEY
db $20 ; STOLEN SHIELD
}
PrizePackPrizes:
{
.pack_1
db $D8 ; SPRITE D8 - heart
db $D8 ; SPRITE D8 - heart
db $D8 ; SPRITE D8 - heart
db $D8 ; SPRITE D8 - heart
db $D9 ; SPRITE D9 - green rupee
db $D8 ; SPRITE D8 - heart
db $D8 ; SPRITE D8 - heart
db $D9 ; SPRITE D9 - green rupee
.pack_2
db $DA ; SPRITE DA - blue rupee
db $D9 ; SPRITE D9 - green rupee
db $DA ; SPRITE DA - blue rupee
db $DB ; SPRITE DB - red rupee
db $DA ; SPRITE DA - blue rupee
db $D9 ; SPRITE D9 - green rupee
db $DA ; SPRITE DA - blue rupee
db $DA ; SPRITE DA - blue rupee
.pack_3
db $E0 ; SPRITE E0 - full magic
db $DF ; SPRITE DF - small magic
db $DF ; SPRITE DF - small magic
db $DA ; SPRITE DA - blue rupee
db $E0 ; SPRITE E0 - full magic
db $DF ; SPRITE DF - small magic
db $D8 ; SPRITE D8 - heart
db $DF ; SPRITE DF - small magic
.pack_4
db $DC ; SPRITE DC - 1 bomb
db $DC ; SPRITE DC - 1 bomb
db $DC ; SPRITE DC - 1 bomb
db $DD ; SPRITE DD - 4 bombs
db $DC ; SPRITE DC - 1 bomb
db $DC ; SPRITE DC - 1 bomb
db $DE ; SPRITE DE - 8 bombs
db $DC ; SPRITE DC - 1 bomb
.pack_5
db $E1 ; SPRITE E1 - 5 arrows
db $D8 ; SPRITE D8 - heart
db $E1 ; SPRITE E1 - 5 arrows
db $E2 ; SPRITE E2 - 10 arrows
db $E1 ; SPRITE E1 - 5 arrows
db $D8 ; SPRITE D8 - heart
db $E1 ; SPRITE E1 - 5 arrows
db $E2 ; SPRITE E2 - 10 arrows
.pack_6
db $DF ; SPRITE DF - small magic
db $D9 ; SPRITE D9 - green rupee
db $D8 ; SPRITE D8 - heart
db $E1 ; SPRITE E1 - 5 arrows
db $DF ; SPRITE DF - small magic
db $DC ; SPRITE DC - 1 bomb
db $D9 ; SPRITE D9 - green rupee
db $D8 ; SPRITE D8 - heart
.pack_7
db $D8 ; SPRITE D8 - heart
db $E3 ; SPRITE E3 - fairy
db $E0 ; SPRITE E0 - full magic
db $DB ; SPRITE DB - red rupee
db $DE ; SPRITE DE - 8 bombs
db $D8 ; SPRITE D8 - heart
db $DB ; SPRITE DB - red rupee
db $E2 ; SPRITE E2 - 10 arrows
}

131
Docs/Core/Link.md Normal file
View File

@@ -0,0 +1,131 @@
# Bank $07: Core Player (Link) Engine Analysis
**File**: `ALTTP/bank_07.asm`
**Address Range**: `$078000` - `$07FFFF`
This bank is dedicated entirely to the player character, Link. It contains his core state machine, which governs everything from movement and physics to item usage and interaction with the world. It is executed every frame that the player has control and is not in a cutscene.
---
### 1. Main Entry Point: `Link_Main`
* **Routine**: `Link_Main` (`#_078000`)
* **Purpose**: This is the top-level function for all player-related code, called once per frame from the main game loop when the game is in a playable state (e.g., Overworld or Underworld).
* **Functionality**:
1. It first checks if the player is in a state that prevents control (e.g., a cutscene, indicated by `$02E4` being non-zero).
2. If the player has control, it calls `Link_ControlHandler`, which is the heart of the player engine.
3. After the main handler runs, it calls `HandleSomariaAndGraves` to process interactions with those specific objects, which need to be checked every frame.
---
### 2. The Player State Machine: `Link_ControlHandler`
* **Routine**: `Link_ControlHandler` (`#_07807F`)
* **Purpose**: This function acts as a state machine dispatcher. It reads Link's current state from a single, critical WRAM variable and jumps to the appropriate logic handler for that state.
* **Critical WRAM Variable**: `$7E005D` (`LINKDO`) - This byte holds Link's current state ID. Modifying this value directly forces Link into a different state.
* **Execution Flow**:
1. **Damage Check**: Before any other action, the handler checks if Link has taken damage (`$7E0373`, `HURTME`). If so, it processes the damage, checks for the Magic Cape (`$7E0055`), reduces health, and can trigger a state change to `LinkState_Recoil` or the death sequence.
2. **State Dispatch**: It reads the value of `LINKDO`, multiplies it by two (since each entry is a 2-byte address), and uses it as an index into the `.vectors` jump table (`#_078041`). It then performs a `JMP` to the corresponding state handler routine.
---
### 3. Link State Vector Table
This table at `#_078041` defines all 31 possible states for Link. Understanding this is key to modifying player behavior.
| State ID | Label (`#_07....`) | Description |
|:---:|---|---|
| `0x00` | `LinkState_Default` | The normal on-foot state for walking, standing, and most basic interactions. |
| `0x01` | `LinkState_Pits` | Handles the logic for falling into a pit. |
| `0x02` | `LinkState_Recoil` | Handles being knocked back by an enemy or obstacle. |
| `0x03` | `LinkState_SpinAttack` | Manages the spin attack animation and hitbox. |
| `0x04` | `LinkState_Swimming` | The state for swimming in water. |
| `0x05` | `LinkState_OnIce` | Handles movement physics for icy surfaces. |
| `0x06` | `LinkState_Recoil` | A duplicate pointer to the recoil state, likely for a different impact type. |
| `0x07` | `LinkState_Zapped` | A special recoil state for electrical damage. |
| `0x08` | `LinkState_UsingEther` | Handles the animation and logic for using the Ether medallion. |
| `0x09` | `LinkState_UsingBombos` | Handles the animation and logic for using the Bombos medallion. |
| `0x0A` | `LinkState_UsingQuake` | Handles the animation and logic for using the Quake medallion. |
| `0x0B` | `LinkState_HoppingSouthOW` | Manages the multi-frame action of hopping off a ledge to the south. |
| `0x0C` | `LinkState_HoppingHorizontallyOW` | Manages hopping off a ledge to the east or west. |
| `0x0D` | `LinkState_HoppingDiagonallyUpOW` | Manages hopping off a ledge diagonally up-left or up-right. |
| `0x0E` | `LinkState_HoppingDiagonallyDownOW`| Manages hopping off a ledge diagonally down-left or down-right. |
| `0x0F` | `LinkState_0F` | A generic ledge-hopping state. |
| `0x10` | `LinkState_0F` | (Duplicate) A generic ledge-hopping state. |
| `0x11` | `LinkState_Dashing` | The state for running with the Pegasus Boots. |
| `0x12` | `LinkState_ExitingDash` | The brief turn-around animation after a dash collides with a wall. |
| `0x13` | `LinkState_Hookshotting` | Manages Link's state while the hookshot is extended. |
| `0x14`| `LinkState_CrossingWorlds` | Handles the Magic Mirror animation and world transition. |
| `0x15` | `LinkState_ShowingOffItem` | The "item get" pose when Link holds an item above his head. |
| `0x16` | `LinkState_Sleeping` | For the beginning of the game when Link is in bed. |
| `0x17` | `LinkState_Bunny` | The state for when Link is transformed into a bunny in the Dark World. |
| `0x18` | `LinkState_HoldingBigRock` | The state for lifting a heavy, dark-colored rock (requires Titan's Mitt). |
| `0x19` | `LinkState_ReceivingEther` | The cutscene for receiving the Ether medallion from the tablet. |
| `0x1A` | `LinkState_ReceivingBombos` | The cutscene for receiving the Bombos medallion from the tablet. |
| `0x1B` | `LinkState_ReadingDesertTablet` | The cutscene for reading the Desert Palace tablet. |
| `0x1C` | `LinkState_TemporaryBunny` | The brief bunny transformation sequence when entering the Dark World. |
| `0x1D` | `LinkState_TreePull` | The state for pulling on the tree in the haunted grove for the race game. |
| `0x1E` | `LinkState_SpinAttack` | (Duplicate) A second entry for the spin attack state. |
---
### 4. Analysis of Core States
#### `LinkState_Default` (`#_078109`)
This is the most complex state and serves as the foundation for player control. It is a large routine that dispatches to numerous sub-handlers.
* **Initial Checks**:
* `Link_HandleBunnyTransformation`: Checks if Link should transform into a bunny.
* Checks for recoil/damage (`$7E004D`) and branches to a simplified physics handler if necessary.
* **Action Dispatching**: If not recoiling, it checks for player input and calls the appropriate action handler.
* `Link_HandleToss`: Checks if Link is throwing a carried object.
* `Link_HandleAPress`: Handles context-sensitive actions for the A button (talk, read, lift, open, dash).
* `Link_HandleYItem`: Manages using the currently selected item (bow, boomerang, rods, etc.).
* `Link_HandleSwordCooldown`: Manages sword swings and charging a spin attack.
* **Physics and Collision**: If no other action is taken, it processes movement.
* `ResetAllAcceleration`: Clears speed values if Link is standing still.
* `Link_HandleDiagonalCollision` & `Link_HandleCardinalCollision`: Check for collisions with walls and objects.
* `JSL Link_HandleVelocity`: The main physics engine. Applies acceleration, deceleration, and the final movement vector to Link's coordinates.
* **Animation & Camera**:
* `JSL Link_HandleMovingAnimation_FullLongEntry`: Updates Link's sprite graphics based on his direction and action.
* `HandleIndoorCameraAndDoors`: Manages camera scrolling and door transitions indoors.
#### `LinkState_Recoil` (`#_0786B5`)
This state demonstrates how control is temporarily taken from the player.
* **Z-Axis Movement**: It uses `$7E0024` (Link's Z-position) and `$7E0029` (knockback Z-velocity) to handle Link being knocked into the air and falling back down.
* **Timer-Based**: The duration of the recoil is controlled by a countdown timer in `$7E0046` (`INPAIN`). Once the timer reaches zero, Link's state is typically returned to `LinkState_Default`.
* **Collision & Landing**: While in recoil, it still checks for collisions. It also has special checks for landing, such as `Link_SplashUponLanding` if he falls into water, which can change his state to `LinkState_Swimming`.
#### `LinkState_Bunny` (`#_0783A1`)
This state shows a persistent change in abilities.
* **Simplified Controls**: The bunny state has a much simpler control handler. It still allows for movement but disables all item and sword usage.
* **State Check**: It constantly checks for the condition that allows Link to transform back: the presence of the Moon Pearl (`$7EF357`). If the pearl is obtained or Link leaves the Dark World, it triggers the transformation back to the default state.
---
### 5. Key WRAM Variables for Link
This bank relies on a large number of WRAM addresses to function. Understanding these is critical to debugging or modifying player logic.
| Address | Label | Description |
|:---:|---|---|
| `$7E005D` | `LINKDO` | **Link's State**: The primary state ID, used as an index for the state machine. |
| `$7E0020/21`| `POSY` | Link's 16-bit Y-coordinate. |
| `$7E0022/23`| `POSX` | Link's 16-bit X-coordinate. |
| `$7E0024` | `POSZ` | Link's 8-bit Z-coordinate (height). |
| `$7E0026` | - | Link's facing direction. |
| `$7E0027/28`| - | Link's Y/X velocity. |
| `$7E002A/2B`| - | Link's Y/X sub-pixel position. |
| `$7E003A` | - | Action flags (bitfield for sword charging, etc.). |
| `$7E0046` | `INPAIN` | Recoil/invincibility timer after taking damage. |
| `$7E004D` | - | A flag indicating Link is in a recoil state. |
| `$7E0303` | - | The ID of the currently selected Y-button item. |
| `$7E0373` | `HURTME` | Damage value to be applied to Link on the next frame. |
| `$7E037B` | - | A flag that temporarily disables taking damage. |
| `$7E0372` | - | A flag indicating Link is currently dashing. |

181
Docs/Core/MemoryMap.md Normal file
View File

@@ -0,0 +1,181 @@
# Memory Map
This document provides a detailed map of the WRAM and SRAM memory regions, serv| `$7EF358` | `WolfMask` | Flag indicating if the player has obtained the Wolf Mask. |
### Repurposed Vanilla SRAM Blocks
The following blocks were marked "unused" in vanilla ALTTP but are now utilized for OOS custom data:
#### **Block $7EF38A-$7EF3C4** - Collectibles & Custom Progression
*This is a large block of vanilla unused SRAM now used for various collectibles, side-quests, and tracking systems.*
| Address | Label | Description | Verified |
|----------|---------------------|--------------------------------------------------------------------------|----------|
| `$7EF38A` | `FishingRod` | Flag indicating if the player has the Fishing Rod. | ✓ |
| `$7EF38B` | `Bananas` | Number of bananas collected for side-quest. | ✓ |
| `$7EF38D` | `Pineapples` | Number of pineapples collected. | ✓ |
| `$7EF38F` | `RockMeat` | Number of rock meat items collected. | ✓ |
| `$7EF391` | `Seashells` | Number of secret seashells collected. | ✓ |
| `$7EF393` | `Honeycomb` | Number of honeycombs collected. | ✓ |
| `$7EF395` | `DekuSticks` | Number of Deku sticks collected. | ✓ |
| `$7EF396` | `TingleMaps` | Tingle map collection tracking. | ✓ |
| `$7EF397` | `TingleId` | Tingle identification value. | ✓ |
| `$7EF398` | `Scrolls` | Bitfield tracking lore scroll collection (7 dungeons: `.dgi zktm`). | ✓ |
| `$7EF39A` | `PrevScroll` | Tracks the previous scroll for re-reading old hints. | ✓ |
| `$7EF39B` | `MagicBeanProg` | Multi-day growth cycle tracking for magic bean side-quest (`.dts fwpb`). | ✓ |
| `$7EF39C` | `JournalState` | Current state of the player's journal. | ✓ |
| `$7EF39D` | `SRAM_StormsActive` | Flag indicating if the Song of Storms effect is active. | ✓ |
| `$7EF39E` | `StoryState` | State machine for Link's House intro sequence (0-2). | ✓ |
#### **Block $7EF403-$7EF4FD** - Partially Repurposed
*Most of this block remains unused, but OOS utilizes a portion for the Dreams collectible system.*
| Address | Label | Description | Verified |
|----------|-----------|--------------------------------------------------------------------|----------|
| `$7EF410` | `Dreams` | Bitfield tracking collection of three Dreams (`.cpw`: Courage, Power, Wisdom). | ✓ |
> **💡 Usage Notes:**
> - **Scrolls** (`$7EF398`): One scroll per dungeon (7 total). Bitfield format: `.dgi zktm` where each letter represents a dungeon (m=Mushroom Grotto, t=Tail Palace, k=Kalyxo Castle, z=Zora Temple, i=Glacia Estate, g=Goron Mines, d=Dragon Ship).
> - **MagicBeanProg** (`$7EF39B`): Tracks multi-day growth cycle with bitfield `.dts fwpb` (b=bean planted, w=watered, p=pollinated, f=first day, s=second day, t=third day, d=done).
> - **Dreams** (`$7EF410`): Similar to vanilla Pendants, tracks three key collectibles. Bitfield: `.cpw` (c=Courage, p=Power, w=Wisdom).
### SRAM Address Contradictions (Source File Notes)
The following addresses appear with both active label definitions and `UNUSED_` markers in `Core/sram.asm`. **The label definitions take precedence** - these addresses are actively used:
- `$7EF3D4` - Both `MakuTreeQuest` and `UNUSED_7EF3D4` (✓ **In Use**)
- `$7EF3D6` - Both `OOSPROG` and `UNUSED_7EF3D6` (✓ **In Use**)
- `$7EF38A` - Both `FishingRod` and `UNUSED_7EF38A` (✓ **In Use**)
These contradictions appear to be legacy comments from the vanilla ALTTP disassembly that were not removed when OOS repurposed these addresses.
as a central reference for understanding the game's state.
## 1. WRAM (Work RAM) - `$7E0000`
This section details the layout of the game's volatile memory.
### Key Vanilla WRAM Variables
*This section contains a table listing critical vanilla WRAM addresses, their labels (from `Core/ram.asm` and `Core/symbols.asm`), and their purpose.*
| Address | Label | Description |
|----------|------------|---------------------------------------------------|
| `$7E0010` | `MODE` | The main game state/module index. |
| `$7E0011` | `SUBMODE` | The sub-state for the current game mode. |
| `$7E001A` | `FRAME` | A counter that increments each non-lagging frame. |
| `$7E001B` | `INDOORS` | A flag indicating if Link is indoors (0x01) or outdoors (0x00). |
| `$7E002F` | `DIR` | The direction Link is facing (0=U, 2=D, 4=L, 6=R). |
| `$7E005D` | `LINKDO` | Link's personal state machine ID (walking, swimming, etc.). |
| `$7E008A` | `OWSCR` | The current Overworld screen ID. |
| `$7E00A0` | `ROOM` | The current Underworld room ID. |
| `$7E02E0` | `BUNNY` | A flag indicating if Link is in his bunny form (0x01). |
| `$7E031F` | `IFRAMES` | Link's invincibility frame timer after taking damage. |
| `$7E0DD0` | `SprState` | An array storing the state for each of the 16 sprites. |
| `$7E0E20` | `SprType` | An array storing the ID for each of the 16 sprites. |
| `$7E0E50` | `SprHealth`| An array storing the health for each of the 16 sprites. |
### Custom WRAM Region - `$7E0730+`
*This section details the custom WRAM area defined in `Core/ram.asm` and `Core/symbols.asm`. It explains the purpose of each custom variable.*
| Address | Label | Description |
|----------|------------------------|--------------------------------------------------------------------------|
| `$7E0730` | `MenuScrollLevelV` | Vertical scroll position for the menu. |
| `$7E0731` | `MenuScrollLevelH` | Horizontal scroll position for the menu. |
| `$7E0732` | `MenuScrollHDirection` | The direction of horizontal scrolling in the menu. |
| `$7E0734` | `MenuItemValueSpoof` | Used to temporarily override the displayed value of a menu item. |
| `$7E0736` | `ShortSpoof` | A shorter version of the spoof value. |
| `$7E0737` | `MusicNoteValue` | The value of the current music note being played. |
| `$7E0739` | `GoldstarOrHookshot` | Differentiates between the vanilla Hookshot and the custom Goldstar item. |
| `$7E073A` | `Neck_Index` | Used for multi-part sprites, like a centipede body. |
| `$7E0745` | `FishingOrPortalRod` | Differentiates between the Fishing Rod and the Portal Rod. |
---
## 2. SRAM (Save RAM) - `$7EF000`
This section details the layout of the save file memory.
> **🔍 SRAM Verification Note**: All custom SRAM variables documented below have been cross-referenced with `Core/sram.asm`. Some addresses in the source file have contradictory `UNUSED_` markers alongside actual label definitions (e.g., `OOSPROG = $7EF3D6` vs `UNUSED_7EF3D6 = $7EF3D6`). **The actual usage takes precedence** - if a label is defined for an address, it is considered in-use regardless of `UNUSED_` markers. This appears to be a legacy comment artifact from the vanilla ALTTP disassembly.
### Key Vanilla SRAM Variables
*This section lists key vanilla save data locations, such as inventory, health, and progression flags, as defined in `Core/sram.asm`.*
| Address | Label | Description |
|----------|------------|-------------------------------------------|
| `$7EF340` | `Bow` | The player's current bow type (0x00-0x04). |
| `$7EF343` | `Bombs` | The number of bombs the player has. |
| `$7EF359` | `Sword` | The player's current sword type (0x00-0x04). |
| `$7EF35A` | `Shield` | The player's current shield type (0x00-0x03). |
| `$7EF360` | `Rupees` | The player's current rupee count. |
| `$7EF36C` | `MAXHP` | The player's maximum health (1 heart = 8 HP). |
| `$7EF36D` | `CURHP` | The player's current health. |
| `$7EF374` | `Pendants` | A bitfield for the collected pendants (Courage, Power, Wisdom). |
| `$7EF37A` | `Crystals` | A bitfield for the collected crystals from Dark World dungeons. |
| `$7EF3C5` | `GameState`| The main progression state of the game. |
### Custom SRAM Region
*This is a critical section. It provides a comprehensive breakdown of all custom variables added to the SRAM, explaining what each flag or value represents. This information is primarily found in `Core/sram.asm`.*
| Address | Label | Description |
|----------|-------------------|--------------------------------------------------------------------------|
| `$7EF3D6` | `OOSPROG` | A primary bitfield for major quest milestones unique to Oracle of Secrets. |
| `$7EF3C6` | `OOSPROG2` | A secondary bitfield for less critical progression flags. |
| `$7EF3D4` | `MakuTreeQuest` | A flag indicating if the Maku Tree has met Link. |
| `$7EF3C7` | `MapIcon` | Controls the position of the guiding 'X' on the world map. |
| `$7EF351` | `CustomRods` | A flag to differentiate between the Fishing Rod (1) and Portal Rod (2). |
| `$7EF38A` | `FishingRod` | Flag indicating if the player has the Fishing Rod. |
| `$7EF38B` | `Bananas` | The number of bananas collected for a side-quest. |
| `$7EF391` | `Seashells` | The number of secret seashells collected. |
| `$7EF398` | `Scrolls` | A bitfield tracking which of the lore scrolls have been found. |
| `$7EF39B` | `MagicBeanProg` | Tracks the multi-day growth cycle of the magic bean side-quest. |
| `$7EF39C` | `JournalState` | The current state of the player's journal. |
| `$7EF39D` | `SRAM_StormsActive`| A flag indicating if the Song of Storms effect is active. |
| `$7EF39E` | `StoryState` | State machine for Link's House intro sequence (0=Telepathy, 1=WakeUp, 2=End). |
| `$7EF410` | `Dreams` | A bitfield tracking the collection of the three "Dreams" (Courage, Power, Wisdom). |
| `$7EF347` | `ZoraMask` | Flag indicating if the player has obtained the Zora Mask. |
| `$7EF348` | `BunnyHood` | Flag indicating if the player has obtained the Bunny Hood. |
| `$7EF349` | `DekuMask` | Flag indicating if the player has obtained the Deku Mask. |
| `$7EF34D` | `RocsFeather` | Flag indicating if the player has obtained Roc's Feather. |
| `$7EF352` | `StoneMask` | Flag indicating if the player has obtained the Stone Mask. |
| `$7EF358` | `WolfMask` | Flag indicating if the player has obtained the Wolf Mask. |
## 3. Custom Code and Data Layout (ROM Banks)
This section details the allocation of custom code and data within the ROM banks, as defined by `org` directives in the project's assembly files. The order of `incsrc` directives in `Oracle_main.asm` is crucial for the final ROM layout.
| Bank (Hex) | Address Range (PC) | Purpose / Contents |
|------------|-----------------------|--------------------------------------------------------|
| $20 | `$208000` - `$20FFFF` | Expanded Music |
| $21-$27 | | ZScream Reserved |
| $28 | `$288000` - `$28FFFF` | ZSCustomOverworld data and code |
| $29-$2A | | ZScream Reserved |
| $2B | `$2B8000` - `$2BFFFF` | Items |
| $2C | `$2C8000` - `$2CFFFF` | Underworld/Dungeons |
| $2D | `$2D8000` - `$2DFFFF` | Menu |
| $2E | `$2E8000` - `$2EFFFF` | HUD |
| $2F | `$2F8000` - `$2FFFFF` | Expanded Message Bank |
| $30 | `$308000` - `$30FFFF` | Sprites |
| $31 | `$318000` - `$31FFFF` | Sprites |
| $32 | `$328000` - `$32FFFF` | Sprites |
| $33 | `$338000` - `$33FFFF` | Moosh Form Gfx and Palette |
| $34 | `$348000` - `$34FFFF` | Time System, Custom Overworld Overlays, Gfx |
| $35 | `$358000` - `$35FFFF` | Deku Link Gfx and Palette |
| $36 | `$368000` - `$36FFFF` | Zora Link Gfx and Palette |
| $37 | `$378000` - `$37FFFF` | Bunny Link Gfx and Palette |
| $38 | `$388000` - `$38FFFF` | Wolf Link Gfx and Palette |
| $39 | `$398000` - `$39FFFF` | Minish Link Gfx |
| $3A | `$3A8000` - `$3AFFFF` | Mask Routines, Custom Ancillae (Deku Bubble) |
| $3B | `$3B8000` - `$3BFFFF` | GBC Link Gfx |
| $3C | | Unused |
| $3D | | ZS Tile16 |
| $3E | | LW ZS Tile32 |
| $3F | | DW ZS Tile32 |
| $40 | `$408000` - `$40FFFF` | LW World Map |
| $41 | `$418000` - `$41FFFF` | DW World Map |
| Patches | Various | Targeted modifications within vanilla ROM addresses | `Core/patches.asm`, `Util/item_cheat.asm` |

104
Docs/Core/Ram.md Normal file
View File

@@ -0,0 +1,104 @@
# RAM Analysis: The Engine's State
This document provides a high-level analysis of how Work RAM (WRAM) and Save RAM (SRAM) are used to manage the game's state. For a raw list of addresses, see `Core/ram.asm` and `Core/sram.asm`.
## 1. The Core Game Loop: WRAM in Motion
The entire game is driven by a master state machine whose state is stored in a single WRAM variable:
- **`MODE` (`$7E0010`):** This is the game's primary state index. The main loop in `bank_00.asm` reads this value every frame and jumps to the corresponding module in the `Module_MainRouting` table.
- **`SUBMODE` (`$7E0011`):** Many modules have their own internal state machines. This variable holds the sub-state for the current `MODE`.
This `MODE`/`SUBMODE` pattern is the fundamental driver of the game's flow. For example:
- When Link opens the menu, the game sets `MODE` to `0x0E` (Interface), which gives control to the menu engine.
- When Link talks to a character, `Interface_PrepAndDisplayMessage` is called, which saves the current game state to `MODECACHE` (`$7E010C`) and then sets `MODE` to `0x0E` to display the text box. When the dialogue is finished, the previous state is restored from the cache.
- Transitioning between the overworld and underworld involves setting `MODE` to `0x08` (Overworld Load) or `0x06` (Underworld Load), respectively.
## 2. Defining the World: Location and Environment
The player's location and the properties of their environment are controlled by a handful of key WRAM variables.
- **`INDOORS` (`$7E001B`):** A simple but powerful flag (`0x01` for indoors, `0x00` for outdoors). This variable is checked by numerous systems to alter their behavior. For instance, the `ZSCustomOverworld` system reads this flag to determine whether to apply day/night palettes, and the audio engine uses it to select the appropriate music track.
- **`OWSCR` (`$7E008A`) and `ROOM` (`$7E00A0`):** These variables store the player's current location. `OWSCR` holds the Overworld screen ID, while `ROOM` holds the Underworld room ID.
The interaction between these variables is central to world traversal. When Link enters a cave on `OWSCR` 0x35, the following happens:
1. The game looks up the entrance data for that tile in `Overworld/entrances.asm`.
2. This data specifies the destination `ROOM` ID (e.g., 0x0104).
3. The `INDOORS` flag is set to `0x01`.
4. The main game `MODE` is set to `0x06` (Underworld Load).
5. The dungeon engine in `bank_01.asm` takes over. It reads the `ROOM` ID and uses it to look up the room's header in `ALTTP/rooms.asm`. This header contains pointers to all the data needed to draw the room, including its layout, objects, and sprites.
## 3. Room-Specific Behavior
Once a room is loaded, its specific behavior is governed by tags and flags.
- **`TAG1`/`TAG2` (`$7E00AE`/`$AF`):** These are "Room Effect" tags loaded from the room's header. They trigger special behaviors like kill rooms, shutter doors, or custom events defined in `Dungeons/custom_tag.asm`. For example, a kill room tag will cause the `Underworld_HandleRoomTags` routine to check if all sprites in the room (`$7E0E20+`) have been defeated.
- **`UWDEATH` (`$7FDF80`) and `OWDEATH` (`$7FEF80`):** These are large bitfields in SRAM that track the state of every overworld screen and underworld room. When a kill room is cleared or a key is taken from a chest, a bit is set in this array. This ensures that the state persists permanently in the save file, preventing enemies from respawning or chests from reappearing.
## 4. The Player and Entities
- **Link:** The player's state is managed by its own state machine in `bank_07.asm`, with the current state held in `LINKDO` (`$7E005D`). This is covered in detail in `Docs/Link.md`.
- **Sprites and Ancillae:** The WRAM regions from `$7E0D00` onwards are large arrays that hold the state of all active entities in the game (16 sprites, ~40 ancillae). These are defined as `structs` in `Core/structs.asm`. While there are dozens of variables for each sprite, the most important for general game logic are:
- `SprState` (`$7E0DD0,X`): The sprite's main state (e.g., `0x09` for active, `0x0B` for stunned).
- `SprType` (`$7E0E20,X`): The sprite's ID number.
- `SprX`/`SprY` (`$0D10,X`/`$0D00,X`): The sprite's coordinates.
The sprite engine in `bank_06.asm` iterates through these arrays each frame, executing the logic for each active sprite.
## 4.5. Custom WRAM Region (`$7E0730+`)
Oracle of Secrets adds a custom WRAM region starting at `$7E0730`, utilizing the MAP16OVERFLOW free RAM space. All custom variables documented here have been verified against `Core/ram.asm` and are actively used by the project's custom systems.
### Verified Custom WRAM Variables
| Address | Label | Description | Verified |
|------------|-------------------------|-----------------------------------------------------------|----------|
| `$7E0730` | `MenuScrollLevelV` | Vertical scroll position for the custom menu system | ✓ |
| `$7E0731` | `MenuScrollLevelH` | Horizontal scroll position for the custom menu system | ✓ |
| `$7E0732` | `MenuScrollHDirection` | Direction flag for horizontal menu scrolling (2 bytes) | ✓ |
| `$7E0734` | `MenuItemValueSpoof` | Temporary override for displayed menu item values (2 bytes)| ✓ |
| `$7E0736` | `ShortSpoof` | Shorter version of the spoof value (1 byte) | ✓ |
| `$7E0737` | `MusicNoteValue` | Current music note value for Ocarina system (2 bytes) | ✓ |
| `$7E0739` | `GoldstarOrHookshot` | Differentiates Hookshot (0) from Goldstar (1) mode | ✓ |
| `$7E073A` | `Neck_Index` | Index for multi-part sprite body tracking (e.g., bosses) | ✓ |
| `$7E073B` | `Neck1_OffsetX` | X-offset for first neck/body segment | ✓ |
| `$7E073C` | `Neck1_OffsetY` | Y-offset for first neck/body segment | ✓ |
| `$7E073D` | `Neck2_OffsetX` | X-offset for second neck/body segment | ✓ |
| `$7E073E` | `Neck2_OffsetY` | Y-offset for second neck/body segment | ✓ |
| `$7E073F` | `Neck3_OffsetX` | X-offset for third neck/body segment | ✓ |
| `$7E0740` | `Neck3_OffsetY` | Y-offset for third neck/body segment | ✓ |
| `$7E0741` | `Offspring1_Id` | Sprite ID of first child sprite (for boss mechanics) | ✓ |
| `$7E0742` | `Offspring2_Id` | Sprite ID of second child sprite (for boss mechanics) | ✓ |
| `$7E0743` | `Offspring3_Id` | Sprite ID of third child sprite (for boss mechanics) | ✓ |
| `$7E0744` | `Kydreeok_Id` | Sprite ID for Kydreeok boss entity | ✓ |
| `$7E0745` | `FishingOrPortalRod` | Differentiates Fishing Rod (1) from Portal Rod (2) | ✓ |
### Usage Notes
- **Menu System**: Variables `$7E0730-$7E0736` are exclusively used by the custom menu system (`Menu/menu.asm`) to manage smooth scrolling between the Items and Quest Status pages.
- **Item Differentiation**: `GoldstarOrHookshot` and `FishingOrPortalRod` are critical for shared inventory slots. These allow two distinct items to occupy a single menu slot, with the player able to switch between them using the L/R shoulder buttons.
- **Boss Mechanics**: The `Neck_*` and `Offspring_*` variables enable complex multi-part boss sprites (e.g., Kydreeok with multiple heads, Manhandla with independent parts). The parent sprite uses these to track and coordinate its child sprite components.
- **Memory Safety**: All variables in this region are placed within the MAP16OVERFLOW free RAM area, which is guaranteed to be unused by the vanilla game engine. This prevents conflicts with vanilla systems.
## 5. Long-Term Progression: SRAM and Custom Flags
SRAM (`$7EF000+`) stores the player's save file and is the key to managing long-term quest progression. Oracle of Secrets heavily expands the vanilla save format to support its new data-driven systems.
- **`OOSPROG` (`$7EF3D6`) and `OOSPROG2` (`$7EF3C6`):** These are the primary bitfields for tracking major and minor quest milestones. They are the heart of the game's custom progression.
- **Example Flow:**
1. The player talks to the `village_elder` NPC for the first time.
2. The NPC's code in `Sprites/NPCs/village_elder.asm` sets a specific bit in `OOSPROG` (e.g., `ORA.b #$10 : STA.l OOSPROG`).
3. Later, the world map code in `Overworld/world_map.asm` checks this bit (`LDA.l OOSPROG : AND.b #$10`). If it's set, a new icon is displayed on the map.
- **Other Custom SRAM:** The project adds many other custom variables to SRAM to track new systems, such as:
- **New Inventory:** `ZoraMask` (`$7EF347`), `RocsFeather` (`$7EF34D`), etc.
- **Side-Quests:** `MagicBeanProg` (`$7EF39B`) tracks the growth of a magic bean over time.
- **New Collectibles:** A block starting at `$7EF38B` tracks items like `Bananas` and `Seashells`.
This data-driven approach, centered on modifying and checking flags in SRAM, allows for complex, stateful quest design that persists across play sessions.

540
Docs/Core/StyleGuide.md Normal file
View File

@@ -0,0 +1,540 @@
# Oracle of Secrets: 65816 ASM Style Guide
**Version**: 1.0
**Purpose**: Reduce AI errors and ensure consistent code quality across the codebase.
---
## Quick Reference Card
### Label Naming
| Type | Pattern | Example |
|------|---------|---------|
| Sprite function | `Sprite_{Name}_{Type}` | `Sprite_Booki_Main`, `Sprite_Darknut_Draw` |
| Menu function | `Menu_{Purpose}` | `Menu_InitGraphics`, `Menu_DrawBackground` |
| Link/Player | `Link_{Action}` | `Link_ConsumeMagicBagItem`, `Link_HandleYItem` |
| Oracle namespace | `Oracle_{Function}` | `Oracle_CheckIfNight`, `Oracle_MainEntry` |
| Local labels | `.lowercase_with_underscores` | `.not_being_pushed`, `.nextTile` |
| Constants (macro) | `!UPPERCASE` | `!SPRID`, `!Health`, `!Damage` |
| Memory addresses | `CamelCase` | `SprAction`, `LinkState`, `OOSPROG` |
### Processor State Checklist
- [ ] Always use size suffixes (`.b`, `.w`, `.l`) for ambiguous operations
- [ ] Use `PHP`/`PLP` for functions called from unknown context
- [ ] `REP #$30` = 16-bit A and X/Y, `SEP #$30` = 8-bit
- [ ] `REP #$20` / `SEP #$20` = A only
- [ ] `REP #$10` / `SEP #$10` = X/Y only
### Call Convention Checklist
- [ ] `JSL`/`RTL` for cross-bank calls (3-byte return address)
- [ ] `JSR`/`RTS` for same-bank calls (2-byte return address)
- [ ] **NEVER MIX** - mismatch causes crashes
- [ ] External hooks use `JSL`, internal helpers use `JSR`
---
## 1. File Structure
### 1.1 File Header (Required for new files)
```asm
; =========================================================
; File: sprites/enemies/my_enemy.asm
; Purpose: [Brief description of what this file implements]
; Author: [Your name or handle]
; =========================================================
```
### 1.2 Section Organization
```asm
; =========================================================
; Sprite Properties
; =========================================================
!SPRID = $XX
!NbrTiles = 02
; ... (30 properties in standard order)
; =========================================================
; Entry Points
; =========================================================
Sprite_MyEnemy_Long:
{ ... }
Sprite_MyEnemy_Prep:
{ ... }
; =========================================================
; Main Logic
; =========================================================
Sprite_MyEnemy_Main:
{ ... }
; =========================================================
; Drawing
; =========================================================
Sprite_MyEnemy_Draw:
{ ... }
```
---
## 2. Naming Conventions
### 2.1 Labels
**PascalCase with underscores for hierarchy:**
```asm
; Good
Sprite_Booki_Main
Menu_InitGraphics
Link_ConsumeMagicBagItem
Oracle_CheckIfNight
; Bad
spriteBookiMain ; No underscores
sprite_booki_main ; All lowercase
SPRITE_BOOKI_MAIN ; All uppercase
```
### 2.2 Local Labels
**Lowercase with dot prefix:**
```asm
Sprite_Move:
{
LDA.w SprAction, X : BNE .already_moving
; Start movement
INC.w SprAction, X
.already_moving
RTS
}
```
### 2.3 Constants and Macros
```asm
; Macro parameters: !UPPERCASE
!SPRID = $D5
!Health = 08
!Damage = 02
; Debug flags: !UPPERCASE with LOG prefix
!DEBUG = 1
!LOG_MUSIC = 1
!LOG_SPRITES = 0
; Memory addresses: CamelCase (matching vanilla convention)
SprAction = $0D80
LinkState = $5D
OOSPROG = $7EF3D6
```
### 2.4 Sprite Property Standard Order
All sprites MUST define properties in this order:
```asm
!SPRID = Sprite_MyEnemyID
!NbrTiles = 02
!Harmless = 00
!Health = 08
!Damage = 02
!DeathAnimation = 00
!ImperviousArrow = 00
!ImperviousSword = 00
!Boss = 00
!Shadow = 01
!Palette = 00
!Hitbox = $00
!Persist = 00
!Statis = 00
!CollisionLayer = 00
!CanFall = 01
!DeflectProjectiles = 00
!WaterSprite = 00
!Blockable = 00
!Prize = 00
!Sound = $00
!Interaction = $00
!Subtype2 = 00
%Set_Sprite_Properties(Sprite_MyEnemy_Prep, Sprite_MyEnemy_Long)
```
---
## 3. Scoping and Indentation
### 3.1 Bracket Scoping
**ALL functions use `{ }` brackets** (NOT `subroutine`/`endsubroutine`):
```asm
Sprite_Booki_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw StalkPlayer
dw HideFromPlayer
dw ApproachPlayer
StalkPlayer:
{
%PlayAnimation(0,1,16)
JSR Sprite_Booki_Move
RTS
}
HideFromPlayer:
{
; Nested content indented 2 spaces
LDA.b #$00
STA.w SprAction, X
RTS
}
}
```
### 3.2 Indentation Rules
- **2-space indentation** for all nested content
- Local labels at same indentation as containing block
- Conditional code indented under branch:
```asm
JSL Sprite_CheckActive : BCC .inactive
; Active sprite code (indented)
JSR DoActiveStuff
.inactive
PLB
RTL
```
---
## 4. Processor State Management
### 4.1 Size Suffixes (REQUIRED)
Always use explicit size suffixes when processor state matters:
```asm
; Good - explicit sizes
LDA.w #$1234 ; 16-bit load
LDA.b #$12 ; 8-bit load
STA.l $7E0000 ; Long address
; Bad - ambiguous
LDA #$12 ; Is this 8-bit or 16-bit?
```
### 4.2 State Preservation
```asm
; Functions called from unknown context
SomePublicFunction:
{
PHP ; Save caller's state
SEP #$30 ; Set known state (8-bit A, X/Y)
; ... function body ...
PLP ; Restore caller's state
RTL
}
; Internal helpers can assume state from caller
.helper:
; Assume 8-bit A from caller
LDA.b #$00
RTS
```
### 4.3 Processor Mode Macros
Use these macros for clarity:
```asm
%m8() ; SEP #$20 - 8-bit accumulator
%m16() ; REP #$20 - 16-bit accumulator
%a8() ; SEP #$20 - 8-bit A (alias)
%a16() ; REP #$20 - 16-bit A (alias)
%index8() ; SEP #$10 - 8-bit X/Y
%index16() ; REP #$10 - 16-bit X/Y
```
---
## 5. Hook and Patch Patterns
### 5.1 Small Patches (pushpc/pullpc)
```asm
pushpc
org $1EF27D
ShopItem_Banana:
{
JSR $F4CE ; SpriteDraw_ShopItem
; Custom code here
RTS
}
assert pc() <= $1EF2AB ; Ensure we fit
pullpc
```
### 5.2 Hook Pattern
```asm
; In patches.asm or near related code
pushpc
org $02XXXX ; Vanilla address
JSL MyCustomHook ; 4-byte JSL
NOP ; Pad if needed
pullpc
; The hook implementation
MyCustomHook:
{
; Preserve any clobbered code
JSL OriginalRoutine
; Add custom logic
LDA.w CustomFlag : BEQ .skip
JSL DoCustomThing
.skip
RTL
}
```
### 5.3 Hook Documentation
```asm
; =========================================================
; Hook: $02XXXX - Link's Y-Button Handler
; Purpose: Add custom item handling for Magic Bag
; Vanilla Code Replaced: JSL $07F44C
; Side Effects: Clobbers A
; =========================================================
```
---
## 6. Comments and Documentation
### 6.1 Section Dividers
Use exactly 57 equal signs:
```asm
; =========================================================
; Section Name
; =========================================================
```
### 6.2 Bitfield Documentation
```asm
; Bitfield: hmwo oooo
; o - OAM slot count (bits 0-4)
; w - Wall-seeking behavior
; m - Master sword ceremony flag
; h - Harmless (no contact damage)
SprNbrOAM = $0E40
```
### 6.3 TODO Comments
```asm
; TODO: Add chase animation when player is detected
; TODO(scawful): Refactor this to use lookup table
```
### 6.4 Magic Number Documentation
```asm
LDA.b #$08 ; 8-frame animation delay
CMP.w #$0100 ; Check if past screen boundary (256px)
```
---
## 7. Memory and Data Structures
### 7.1 Struct Definitions
```asm
struct TimeState $7EE000
{
.Hours: skip 1
.Minutes: skip 1
.Speed: skip 1
.Padding: skip 13
.BlueVal: skip 2
.GreenVal: skip 2
.RedVal: skip 2
}
endstruct
```
### 7.2 Inline Data Tables
```asm
Sprite_Draw:
{
; ... draw code ...
RTS
; Data tables use dot notation
.start_index
db $00, $04, $08, $0C
.nbr_of_tiles
db 3, 3, 3, 3
.x_offsets
dw 4, -4, 4, -4
}
```
---
## 8. Error Prevention Checklist
### Before Submitting Code
- [ ] All labels use correct PascalCase_With_Underscores
- [ ] All local labels use .dot_notation
- [ ] Size suffixes on all ambiguous loads/stores
- [ ] JSL/RTL and JSR/RTS pairs matched correctly
- [ ] Hooks have `assert` statements to prevent overflow
- [ ] Magic numbers have inline comments explaining purpose
- [ ] Sprite properties in standard order
- [ ] Section dividers between major code blocks
### Common Crash Causes
1. **JSL/JSR mismatch** - Using RTL with JSR or RTS with JSL
2. **Bank crossing** - Forgetting to set DBR with PHK:PLB
3. **Processor state** - Assuming 8-bit when 16-bit or vice versa
4. **Hook overflow** - Patch exceeds available space
5. **Missing pullpc** - Stack imbalance from pushpc
---
## 9. Oracle of Secrets Specific Patterns
### 9.1 Sprite Entry Point Pattern
```asm
Sprite_MyEnemy_Long:
{
PHB : PHK : PLB ; Set data bank to current bank
JSR Sprite_MyEnemy_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .inactive
JSR Sprite_MyEnemy_Main
.inactive
PLB
RTL
}
```
### 9.2 State Machine Pattern
```asm
Sprite_MyEnemy_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw State_Idle
dw State_Chase
dw State_Attack
dw State_Retreat
State_Idle:
{
%PlayAnimation(0,1,16)
; Check for player proximity
JSL Sprite_CheckDamageToLink
BCC .stay_idle
INC.w SprAction, X ; Transition to Chase
.stay_idle
RTS
}
; ... more states ...
}
```
### 9.3 SRAM Flag Checking
```asm
; Check Oracle progression flag
LDA.l OOSPROG : AND.b #$01 : BEQ .not_complete
; Player has completed this milestone
.not_complete
; Bitfield reference for OOSPROG ($7EF3D6):
; .fmp h.i.
; i = Intro complete
; h = Hall of Secrets visited
; p = Pendant progress
; m = Master Sword acquired
; f = Fortress of Secrets
```
---
## 10. AI Agent Instructions
### 10.1 Before Writing Code
1. **Read existing patterns** - Search for similar implementations
2. **Check memory map** - Verify address usage won't conflict
3. **Identify hook points** - Use Hyrule Historian to find vanilla code
4. **Verify bank space** - Check MemoryMap.md for free space
### 10.2 When Modifying Code
1. **Always read the file first** - Never assume structure
2. **Match existing style** - Follow patterns in the same file
3. **Use explicit sizes** - Never rely on assumed processor state
4. **Add assert statements** - Prevent silent overflow errors
### 10.3 After Writing Code
1. **Run build** - Use `mcp__book-of-mudora__run_build()`
2. **Run lint** - Use `mcp__book-of-mudora__lint_asm()`
3. **Verify in emulator** - Test before marking complete
---
## Appendix: Common Macro Reference
### Animation and Drawing
- `%PlayAnimation(start, end, speed)` - Animate sprite frames
- `%DrawSprite(...)` - Draw sprite OAM
- `%SetFrame(n)` - Set current animation frame
### Sprite Control
- `%GotoAction(n)` - Change sprite state
- `%SetTimer*(n)` - Set various timers
- `%SetSpriteSpeed*(n)` - Set movement speed
- `%SetHarmless()` / `%SetImpervious()` - Damage flags
### Player
- `%PreventPlayerMovement()` / `%AllowPlayerMovement()`
- `%GetPlayerRupees()` - Return rupee count
- `%ShowUnconditionalMessage(id)` - Display dialogue
- `%ShowSolicitedMessage(id)` - Display on interaction
### Audio
- `%PlaySFX1(id)` / `%PlaySFX2(id)` - Sound effects
- `%PlayMusic(id)` - Change music
### Debugging
- `%print_debug(msg)` - Build-time debug output
- `%log_section(name, flag)` - Conditional section logging

View File

@@ -0,0 +1,472 @@
# Oracle of Secrets: System Architecture
**Purpose**: Document how major systems interact to help AI agents understand the codebase structure.
---
## 1. High-Level Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ Oracle_main.asm │
│ (Master include file - controls ROM layout and build order) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Core/ │ │ Sprites/ │ │ Overworld/ │
│ - link.asm │ │ - all_sprites│ │ - ZSCustomOW │
│ - sram.asm │ │ - Bosses/ │ │ - time_system│
│ - symbols.asm│ │ - NPCs/ │ │ - overlays │
│ - patches.asm│ │ - Enemies/ │ │ - lost_woods │
│ - message.asm│ │ - Objects/ │ └───────────────┘
└───────────────┘ └───────────────┘
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Items/ │ │ Menu/ │
│ - all_items │ │ - menu.asm │
│ - ocarina │ │ - menu_select│
│ - magic_bag │ │ - menu_journal│
└───────────────┘ └───────────────┘
```
---
## 2. Namespace Organization
### 2.1 Oracle Namespace
All custom Oracle of Secrets code lives inside the `Oracle` namespace:
```asm
namespace Oracle
{
; Core systems
incsrc "Core/link.asm"
incsrc "Core/sram.asm"
incsrc "Core/symbols.asm"
; Content
incsrc "Music/all_music.asm"
incsrc "Sprites/all_sprites.asm"
incsrc "Items/all_items.asm"
; Patches go last
incsrc "Core/patches.asm"
}
namespace off
; ZScream code is OUTSIDE the namespace
incsrc "Overworld/ZSCustomOverworld.asm"
```
### 2.2 Why This Matters
- Labels inside `namespace Oracle` become `Oracle.LabelName`
- ZScream uses its own conventions and must be outside
- Patches at end to ensure all labels are defined
---
## 3. Memory Map Overview
### 3.1 Bank Organization
| Bank Range | Purpose | Notes |
|------------|---------|-------|
| $00-$1F | Vanilla ALTTP + small patches | Limited free space |
| $20-$29 | ZScream Overworld Data | ~1.5MB reserved |
| $30 | Sprite prep/initialization | Oracle sprites start here |
| $31 | Main sprite logic | Enemy/NPC behavior |
| $32 | Boss logic | Complex sprite code |
| $33-$3F | Free space | Available for expansion |
### 3.2 RAM Regions
| Region | Purpose |
|--------|---------|
| $7E0000-$7E1FFF | Scratch RAM (volatile) |
| $7E2000-$7EFFFF | Game state RAM |
| $7EE000-$7EE0FF | TimeState struct |
| $7EF000-$7EFFFF | SRAM (saved data) |
| $7EF3C5-$7EF3D6 | Oracle progression flags |
| $7EF410 | Dreams bitfield |
### 3.3 Key SRAM Variables
```asm
; GameState ($7EF3C5) - Overall progression
; 0x00 = Very start
; 0x01 = Uncle reached
; 0x02 = Zelda rescued / Farore intro
; 0x03 = Agahnim defeated
; OOSPROG ($7EF3D6) - Oracle progression bitfield
; .fmp h.i.
; i = Intro complete, Maku Tree met
; h = Hall of Secrets visited
; p = Pendant quest progress
; m = Master Sword acquired
; f = Fortress of Secrets
; OOSPROG2 ($7EF3C6) - Secondary progression
; .fbh .zsu
; u = Uncle visited
; s = Priest visited in sanctuary
; z = Zelda brought to sanctuary
; h = Uncle left house
; b = Book of Mudora obtained
; f = Fortune teller flag
; Dreams ($7EF410) - Dream sequence tracking
; .dts fwpb
; (Individual dream completion flags)
```
---
## 4. System Interactions
### 4.1 ZScream Custom Overworld (ZSOW) Integration
ZSOW manages:
- Overworld map transitions
- Palette events
- Overlay data
- Custom collision
**Hook Points**:
```
OverworldHandleTransitions ($028000 area)
└── Oracle_CheckIfNight (time-based sprite loading)
└── LostWoods_PuzzleHandler (navigation puzzle)
└── SongOfStorms overlay effects
```
**Known Conflicts**:
- Lost Woods puzzle directly modifies transition logic
- Day/Night sprites must check `Oracle_CheckIfNight`
- Song of Storms overlays need coordination with ZSOW
### 4.2 Time System
**File**: `Overworld/time_system.asm`
**Structure**:
```asm
struct TimeState $7EE000
{
.Hours, .Minutes, .Speed
.BlueVal, .GreenVal, .RedVal
.TempColor, .SubColor
}
```
**Flow**:
```
RunClock (called each frame)
├── TimeSystem_CheckCanRun
│ └── Check game mode, indoors status
├── TimeSystem_IncrementTime
│ └── Update Hours/Minutes based on Speed
└── TimeSystem_UpdatePalettes
└── Apply color tinting based on time
```
**Integration Points**:
- `Oracle_CheckIfNight` - Called by ZSOW for sprite loading
- Palette system - Affects overworld colors
- NPC behavior - Some NPCs react to time
### 4.3 Sprite System
**Entry Points** (standard pattern):
```
Sprite_*_Long (JSL entry from sprite table)
├── PHB : PHK : PLB (set data bank)
├── Sprite_*_Draw (JSR - render)
├── Sprite_CheckActive (JSL - is active?)
│ └── Sprite_*_Main (JSR - if active)
├── PLB
└── RTL
```
**State Machine**:
```
SprAction (per-sprite state variable)
└── JumpTableLocal dispatches to state handlers
├── State_Idle
├── State_Chase
├── State_Attack
└── State_Retreat
```
**Key Variables** (indexed by X):
| Address | Name | Purpose |
|---------|------|---------|
| $0D00 | SprY | Y position (low byte) |
| $0D10 | SprX | X position (low byte) |
| $0D80 | SprAction | Current state |
| $0DA0 | SprHealth | Hit points remaining |
| $0E40 | SprNbrOAM | OAM slot count |
### 4.4 Menu System
**File**: `Menu/menu.asm`
**State Machine**:
```
MenuMode ($0200) - Current menu state
├── $00 = Not in menu
├── $01 = Opening animation
├── $02 = Item select
├── $0C = Magic Bag submenu
├── $0D = Ring Box submenu
└── $0E = Song select submenu
```
**Flow**:
```
Menu_Entry (from pause input)
├── Menu_InitGraphics
├── Menu_Upload* (VRAM transfers)
└── Menu_MainLoop
├── Handle input
├── Update selection
└── Menu_Draw*
```
### 4.5 Dialogue System
**Files**: `Core/message.asm`, `Core/messages.org`
**Message Format** (in messages.org):
```
** 20 - Maku Tree Part1
[W:02][S:03]Ah, [L]!
[2]Thank the Goddesses you are
[3]alright. I feared the worst.
[V]A dark shadow has befallen us.[K]
```
**Control Codes**:
| Code | Meaning |
|------|---------|
| `[2]`, `[3]` | Line 2, Line 3 |
| `[K]` | Wait for button press |
| `[V]` | Continue on same line |
| `[W:XX]` | Wait time |
| `[S:XX]` | Text speed |
| `[SFX:XX]` | Play sound effect |
| `[CH2I]` | 2-choice prompt |
| `[CH3]` | 3-choice prompt |
| `[L]` | Player name |
**Display Macros**:
```asm
%ShowUnconditionalMessage($20) ; Force display
%ShowSolicitedMessage($20) ; On interaction only
```
---
## 5. Hook Architecture
### 5.1 Hook Types
**Type 1: Inline Patch** (replace vanilla code)
```asm
pushpc
org $02XXXX ; Vanilla address
JSL MyHook ; Replace original instruction
NOP : NOP ; Pad to match original size
pullpc
```
**Type 2: Table Override** (jump table entry)
```asm
pushpc
org $07F000+($ID*2) ; Jump table for sprite $ID
dw Sprite_Custom_Prep
pullpc
```
**Type 3: Extended Logic** (call original + extend)
```asm
MyHook:
{
JSL OriginalRoutine ; Preserve original behavior
; Add custom logic
LDA.w CustomFlag
BEQ .skip
JSL CustomHandler
.skip
RTL
}
```
### 5.2 Hook Documentation Pattern
Every hook should document:
```asm
; =========================================================
; Hook: $XXBANK:ADDR
; Purpose: [What this hook adds/changes]
; Vanilla Code: [What original code did]
; Clobbered: [Registers modified]
; Dependencies: [Other systems affected]
; =========================================================
```
---
## 6. Build System
### 6.1 Build Order (Critical)
```
1. Core/symbols.asm - Memory declarations
2. Core/sram.asm - SRAM layout
3. Core/link.asm - Player modifications
4. Music/all_music.asm - SPC700 data
5. Sprites/all_sprites.asm - All sprite code
6. Items/all_items.asm - Item handlers
7. Menu/menu.asm - Menu system
8. Dungeons/ - Dungeon-specific code
9. Core/patches.asm - Vanilla patches (LAST)
10. Overworld/ZSCustomOverworld.asm - ZSOW (OUTSIDE namespace)
```
### 6.2 Build Commands
```bash
# Fast build
./run.sh
# MCP tools
mcp__book-of-mudora__run_build() # Build ROM
mcp__book-of-mudora__lint_asm() # Check style
mcp__book-of-mudora__analyze_patches() # Review patches
```
---
## 7. Debugging Workflow
### 7.1 Common Debug Points
| Symptom | Check First |
|---------|-------------|
| Crash on room enter | Sprite prep routine, invalid JSL target |
| Wrong graphics | SprGfx assignment, DMA timing |
| Frozen game | Infinite loop in Main, missing RTS/RTL |
| Black screen | Palette loading, HDMA setup |
| Corrupt saves | SRAM address conflict, missing bank setup |
### 7.2 Debug Tools
**Yaze MCP** (in-development):
```python
mcp__yaze_mcp__read_memory("7E0010", 2) # Read RAM
mcp__yaze_mcp__add_breakpoint("02XXXX") # Set breakpoint
mcp__yaze_mcp__get_game_state() # Dump current state
```
**Hyrule Historian**:
```python
mcp__hyrule-historian__lookup_address("02XXXX")
mcp__hyrule-historian__search_oracle_code("Sprite_Booki")
mcp__hyrule-historian__get_ram_info("SprAction")
```
### 7.3 Logging
```asm
; Build-time logging
%log_section("Sprites", !LOG_SPRITES)
; Enable in build:
!LOG_SPRITES = 1 ; Set in config
; Output appears in build log
```
---
## 8. Common Integration Patterns
### 8.1 Adding a New Sprite
1. Create file: `Sprites/Enemies/my_sprite.asm`
2. Define properties using standard order
3. Implement `_Long`, `_Prep`, `_Main`, `_Draw`
4. Add include to `Sprites/all_sprites.asm`
5. Add to sprite table with `org` directive
6. Build and test
### 8.2 Adding a Quest Flag
1. Find free bit in OOSPROG/OOSPROG2
2. Document in `Core/sram.asm`
3. Update this file's SRAM section
4. Use in code:
```asm
LDA.l OOSPROG : ORA.b #$XX : STA.l OOSPROG
```
### 8.3 Adding a New Hook
1. Find vanilla address with Hyrule Historian
2. Document what original code does
3. Create hook with `pushpc`/`pullpc`
4. Add `assert` to verify space
5. Test vanilla behavior still works
---
## 9. System Dependency Graph
```
┌─────────────┐
│ TimeSystem │
└──────┬──────┘
│ Oracle_CheckIfNight
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Lost Woods │────▶│ ZSOW │◀────│ Overlays │
│ Puzzle │ │ Transitions │ │ System │
└─────────────┘ └──────┬──────┘ └─────────────┘
┌────────────┴────────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Sprites │ │ Events │
│ (Loading) │ │ (Triggers) │
└──────┬──────┘ └──────┬──────┘
│ │
└───────────┬─────────────┘
┌─────────────┐
│ Player │
│ (Link) │
└─────────────┘
```
---
## 10. AI Agent Checklist
When working on Oracle of Secrets:
1. [ ] Check `oracle.org` for related tasks
2. [ ] Read existing code in affected files
3. [ ] Verify memory map for conflicts
4. [ ] Use Hyrule Historian for vanilla lookups
5. [ ] Follow StyleGuide.md conventions
6. [ ] Run build after changes
7. [ ] Document any new hooks
8. [ ] Update this file if adding new systems

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,610 @@
# Castle Ambush & Guard Capture System - Implementation Plan
**Status:** 🚧 Planning Phase
**Created:** October 3, 2025
**Target:** Future Update
**Related Files:** `Core/capture.asm`, `Sprites/Enemies/custom_guard.asm`, `Sprites/overlord_ref.asm`
---
## Overview
The **Castle Ambush System** will create a dynamic encounter where Link is detected by guards in the castle, captured, and warped to a dungeon. This combines:
1. **Probe Detection System** - Guards detect Link entering restricted areas
2. **Guard Capture Mechanics** - Guards surround and capture Link
3. **Warp System** - Link is transported to a dungeon entrance
4. **Overlord Management** - Multi-screen guard coordination
---
## Current State Analysis
### Existing Components
#### ✅ Core/capture.asm
**Status:** Implemented but untested
```asm
Oracle_CaptureAndWarp:
{
STA.w $010E ; Set the target entrance ID
LDA.b #$05 ; Game Mode 05: (hole/whirlpool transition)
STA.b $10 ; Set the game mode
STZ.b $2F ; Clear Link's action state
STZ.b $5D ; Clear Link's state
LDA.b #$02 : STA.b $71 ; Set transition flag
RTL
}
```
**Purpose:** Warps Link to a specific dungeon entrance (like WallMaster)
**Issues to Address:**
- [ ] Test entrance ID values (need to determine correct dungeon entrance)
- [ ] Verify game mode $05 works for this use case
- [ ] Add screen fade/transition effect
- [ ] Play capture sound effect
- [ ] Store pre-capture location for potential escape sequence
#### 🚧 Sprites/Enemies/custom_guard.asm
**Status:** Prototype with duplicate code
**Contains:**
1. `Oracle_CaptureAndWarp` (DUPLICATE - already in Core/capture.asm)
2. `Hooked_Guard_Main` - Modified guard behavior
**Issues:**
- [ ] Remove duplicate `Oracle_CaptureAndWarp` function
- [ ] Complete `Hooked_Guard_Main` implementation
- [ ] Test guard capture trigger conditions
- [ ] Integrate with vanilla guard sprites (ID $41, $42, $43)
#### 📚 Sprites/overlord_ref.asm
**Status:** Reference material (now in experimental/)
**Purpose:** Documents overlord path patterns for crumbling tiles
**Relevance:** Can be adapted for guard patrol paths
---
## System Architecture
### Phase 1: Detection (Probe System)
```
┌─────────────────────────────────────────────────┐
│ Link enters castle restricted area │
│ SRAM flag: $7EF??? = Castle infiltration active │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Guard spawns probe sprites every 32 frames │
│ Probe checks: │
│ - Link within 16px radius │
│ - Same floor layer ($0F20) │
│ - Not invisible/bunny │
└──────────────────┬──────────────────────────────┘
┌────────┴────────┐
│ Probe Hit? │
└────────┬────────┘
┌────────────┼────────────┐
│ YES │ NO
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Trigger │ │ Continue │
│ Alert State │ │ Patrol │
└──────┬───────┘ └──────────────┘
┌──────────────────────────────────────┐
│ Play alert sound ($1D) │
│ Set SprTimerD = $B0 (176 frames) │
│ Spawn reinforcement guards │
└──────────────────────────────────────┘
```
### Phase 2: Pursuit & Capture
```
┌─────────────────────────────────────────────────┐
│ Alert state active (SprTimerD > 0) │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Guards converge on Link's position │
│ - Use Guard_ChaseLinkOnOneAxis │
│ - Spawn additional guards from off-screen │
│ - Maximum 4 guards active │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Check capture conditions (every frame) │
│ - Link is surrounded (guards on 3+ sides) │
│ - Link is not moving (speed = 0) │
│ - Link has taken damage from guard │
└──────────────────┬──────────────────────────────┘
┌────────┴────────┐
│ Captured? │
└────────┬────────┘
┌────────────┼────────────┐
│ YES │ NO
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Initiate │ │ Continue │
│ Capture │ │ Chase │
└──────┬───────┘ └──────────────┘
┌──────────────────────────────────────┐
│ Phase 3: Warp Sequence │
└──────────────────────────────────────┘
```
### Phase 3: Warp Sequence
```
┌─────────────────────────────────────────────────┐
│ Freeze Link (disable input) │
│ Play capture animation │
│ - Link's sprite changes to "captured" pose │
│ - Guards move to surround positions │
│ - Screen shake effect (3 frames) │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Fade out screen ($0012 = $01) │
│ Wait 32 frames │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Call Oracle_CaptureAndWarp │
│ - A register = Dungeon entrance ID │
│ - Sets game mode to $05 (transition) │
│ - Clears Link state │
└──────────────────┬──────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Link spawns in dungeon cell │
│ - Set SRAM flag: $7EF??? = Captured │
│ - Play jingle ($06) │
│ - Trigger escape sequence │
└──────────────────────────────────────────────────┘
```
---
## File Consolidation Plan
### Step 1: Organize Core Utilities
**Keep in `Core/capture.asm`:**
```asm
; Core warp functionality
Oracle_CaptureAndWarp:
{
; (existing implementation)
}
; NEW: Enhanced version with effects
Oracle_CaptureAndWarp_Enhanced:
{
PHP
; Store entrance ID
STA.w $010E
; Store capture flag in SRAM
LDA.b #$01
STA.l $7EF3D8 ; Custom flag: Has been captured
; Play capture sound
LDA.b #$1D ; Alert/Capture sound
STA.w $012E
; Fade out screen
LDA.b #$01
STA.w $0012 ; Request fade
; Set up timer for transition
LDA.b #$40 ; Wait 64 frames
STA.b $00
.wait_fade
LDA.b $00 : BNE .wait_fade
; Execute warp
LDA.w $010E ; Get entrance ID back
STA.w $010E
LDA.b #$05 ; Game Mode 05
STA.b $10
STZ.b $2F
STZ.b $5D
LDA.b #$02
STA.b $71
PLP
RTL
}
```
### Step 2: Create Unified Guard Sprite
**New file: `Sprites/Enemies/castle_guard.asm`**
This will replace `Sprites/Enemies/custom_guard.asm` with a complete implementation:
```asm
; =========================================================
; Castle Guard - Ambush & Capture Variant
; =========================================================
!SPRID = Sprite_CastleGuard ; Use new sprite ID or override vanilla
!NbrTiles = 02
!Health = 08
!Damage = 04
; ... other properties ...
%Set_Sprite_Properties(Sprite_CastleGuard_Prep, Sprite_CastleGuard_Long)
; States
!STATE_PATROL = 0
!STATE_ALERT = 1
!STATE_CHASE = 2
!STATE_CAPTURE = 3
Sprite_CastleGuard_Long:
{
PHB : PHK : PLB
JSR Sprite_CastleGuard_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .inactive
JSR Sprite_CastleGuard_Main
.inactive
PLB
RTL
}
Sprite_CastleGuard_Prep:
{
PHB : PHK : PLB
; Check if castle ambush is active
LDA.l $7EF3D7 : BEQ .no_ambush ; Custom flag: Castle ambush active
; Enable enhanced AI
LDA.b #$01 : STA.w $0E80, X ; Custom flag for this guard
.no_ambush
; Standard health based on sword level
LDA.l $7EF359 : TAY
LDA.w .health, Y : STA.w SprHealth, X
; Enable parrying
LDA.b #$80 : STA.w SprDefl, X
PLB
RTL
.health
db $04, $06, $08, $0A
}
Sprite_CastleGuard_Main:
{
; State machine
LDA.w SprAction, X
JSL JumpTableLocal
dw CastleGuard_Patrol
dw CastleGuard_Alert
dw CastleGuard_Chase
dw CastleGuard_Capture
}
CastleGuard_Patrol:
{
; Check if castle ambush should activate
LDA.l $7EF3D7 : BEQ .normal_patrol
; Check distance to Link
JSL GetDistance8bit_Long : CMP.b #$80 : BCS .no_probe
; Spawn probe for detection
LDA.w SprTimerA, X : BNE .no_probe
LDA.b #$20 : STA.w SprTimerA, X ; Spawn every 32 frames
JSL Sprite_SpawnProbeAlways_long
.no_probe
; Check if probe triggered alert
LDA.w SprTimerD, X : BEQ .normal_patrol
; Probe detected Link!
LDA.b #!STATE_ALERT : STA.w SprAction, X
; Play alert sound
LDA.b #$1D : STA.w $012E
; Spawn reinforcements
JSR CastleGuard_SpawnReinforcements
RTS
.normal_patrol
; Standard patrol behavior
JSR Guard_StandardPatrol
RTS
}
CastleGuard_Alert:
{
; Transition to chase after alert plays
LDA.w SprTimerD, X : CMP.b #$A0 : BCS .stay_alert
LDA.b #!STATE_CHASE : STA.w SprAction, X
.stay_alert
; Face Link
JSL Sprite_DirectionToFacePlayer : TYA : STA.w SprMiscC, X
; Draw with alert animation
LDA.b #$08 : STA.w SprGfx, X
RTS
}
CastleGuard_Chase:
{
; Move toward Link
LDA.b #$0C : JSL Sprite_ApplySpeedTowardsPlayer
JSL Guard_ChaseLinkOnOneAxis
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
; Check if Link is surrounded
JSR CastleGuard_CheckSurrounded : BCC .not_surrounded
; Capture Link!
LDA.b #!STATE_CAPTURE : STA.w SprAction, X
LDA.b #$60 : STA.w SprTimerC, X ; Capture animation duration
; Freeze Link
LDA.b #$17 : STA.b $5D ; Link state: captured
STZ.b $67 ; Stop Link's movement
RTS
.not_surrounded
; Continue chase
JSL Guard_ParrySwordAttacks
JSL Sprite_CheckDamageFromPlayer
RTS
}
CastleGuard_Capture:
{
; Animate capture sequence
LDA.w SprTimerC, X : BNE .animating
; Capture complete - warp Link
LDA.b #$42 ; Entrance ID for dungeon cell
JSL Oracle_CaptureAndWarp_Enhanced
RTS
.animating
; Guards surround Link
; ... capture animation logic ...
RTS
}
CastleGuard_CheckSurrounded:
{
; Count guards within range in each direction
; Return carry set if Link is surrounded
; (3+ guards within 32px, covering different quadrants)
; ... implementation ...
CLC ; Not surrounded
RTS
}
CastleGuard_SpawnReinforcements:
{
; Spawn additional castle guards off-screen
LDY.b #$00
LDX.b #$0F
.spawn_loop
LDA.w $0DD0, X : BEQ .found_slot
DEX : BPL .spawn_loop
RTS ; No free slots
.found_slot
; Spawn guard sprite
LDA.b #Sprite_CastleGuard : STA.w $0E20, X
LDA.b #$09 : STA.w $0DD0, X ; Active state
; Position off-screen based on Link's position
; ... positioning logic ...
; Set to chase state immediately
LDA.b #!STATE_CHASE : STA.w SprAction, X
INY
CPY.b #$03 : BCC .spawn_loop ; Spawn up to 3 reinforcements
RTS
}
; ... drawing routine ...
```
### Step 3: Integrate with Existing Systems
**Modify `Sprites/all_sprites.asm`:**
```asm
org $318000
%log_start("castle_guard", !LOG_SPRITES)
incsrc "Sprites/Enemies/castle_guard.asm"
%log_end("castle_guard", !LOG_SPRITES)
```
**Add SRAM Flags to `Core/sram.asm`:**
```asm
; Castle Ambush System
$7EF3D7 = CastleAmbushActive ; 01 = ambush scenario active
$7EF3D8 = HasBeenCaptured ; 01 = player has been captured before
$7EF3D9 = CaptureCount ; Number of times captured
```
**Add Constants to `Core/symbols.asm`:**
```asm
; Castle Ambush
CastleAmbushActive = $7EF3D7
HasBeenCaptured = $7EF3D8
CaptureCount = $7EF3D9
```
---
## Testing Plan
### Test Case 1: Detection
- [ ] Enter castle area with ambush flag set
- [ ] Walk near guard
- [ ] Verify probe spawns every 32 frames
- [ ] Walk into probe's path
- [ ] Verify alert sound plays
- [ ] Verify guard enters alert state
### Test Case 2: Chase
- [ ] Continue from Test Case 1
- [ ] Verify guard chases Link
- [ ] Verify reinforcements spawn
- [ ] Verify multiple guards coordinate
- [ ] Verify guards use parrying
### Test Case 3: Capture
- [ ] Let guards surround Link
- [ ] Verify capture check works
- [ ] Verify Link is frozen
- [ ] Verify capture animation plays
- [ ] Verify screen fades out
### Test Case 4: Warp
- [ ] Continue from Test Case 3
- [ ] Verify Link warps to dungeon
- [ ] Verify SRAM flag is set
- [ ] Verify Link spawns in correct room
- [ ] Verify capture count increments
### Test Case 5: Escape
- [ ] Escape from dungeon cell
- [ ] Return to castle
- [ ] Verify guards remember previous capture
- [ ] Verify harder difficulty on subsequent captures
---
## Implementation Phases
### Phase A: Core Functionality (Week 1)
- [ ] Clean up `Core/capture.asm`
- [ ] Add `Oracle_CaptureAndWarp_Enhanced`
- [ ] Test basic warp functionality
- [ ] Determine correct entrance ID for dungeon cell
### Phase B: Guard AI (Week 2)
- [ ] Create `Sprites/Enemies/castle_guard.asm`
- [ ] Implement probe detection
- [ ] Implement state machine
- [ ] Test patrol → alert → chase transitions
### Phase C: Capture Mechanics (Week 3)
- [ ] Implement surround check
- [ ] Implement capture animation
- [ ] Test capture trigger conditions
- [ ] Add sound effects
### Phase D: Integration (Week 4)
- [ ] Add SRAM flags
- [ ] Integrate with quest system
- [ ] Create dungeon escape sequence
- [ ] Test full cycle
### Phase E: Polish (Week 5)
- [ ] Add dialogue/cutscenes
- [ ] Add visual effects
- [ ] Balance difficulty
- [ ] Add achievements/tracking
---
## Entrance IDs Reference
Need to determine correct entrance for dungeon cell:
```asm
; Common dungeon entrances
$00 = Hyrule Castle (main entrance)
$04 = Hyrule Castle (throne room)
$0E = Hyrule Castle (dark passage)
$20 = Eastern Palace
$42 = Dark Palace
$?? = Custom dungeon cell (TBD)
```
**Action Required:** Find or create appropriate dungeon cell entrance
---
## Files to Create/Modify
### Create:
- [ ] `Sprites/Enemies/castle_guard.asm` - Main guard implementation
- [ ] `Docs/Features/CastleAmbush.md` - System documentation
- [ ] `Docs/Sprites/Enemies/CastleGuard.md` - Sprite documentation
### Modify:
- [ ] `Core/capture.asm` - Add enhanced version
- [ ] `Core/sram.asm` - Add SRAM flags
- [ ] `Core/symbols.asm` - Add constants
- [ ] `Sprites/all_sprites.asm` - Include castle_guard.asm
### Delete/Consolidate:
- [ ] `Sprites/Enemies/custom_guard.asm` - Consolidate into castle_guard.asm
- [ ] Remove duplicate `Oracle_CaptureAndWarp` from custom_guard.asm
---
## Questions to Resolve
1. **Entrance ID:** Which dungeon entrance should be used for the cell?
2. **Quest Integration:** When should castle ambush activate?
- After certain quest milestone?
- When Link enters specific castle area?
- Triggered by dialogue/cutscene?
3. **Difficulty Scaling:** Should capture difficulty increase after first capture?
4. **Escape Sequence:** How should the escape play out?
- Find key item?
- Stealth section?
- Fight way out?
5. **Sprite Slot:** New sprite ID or override vanilla guard ($41/$42/$43)?
---
## See Also
- `Docs/Sprites/ProbeSprites.md` - Probe detection system
- `Docs/Sprites/Enemies/Darknut.md` - Similar guard-type enemy
- `Docs/Guides/SpriteCreationGuide.md` - Sprite creation reference
- `Core/capture.asm` - Core warp functionality
- `Sprites/experimental/probe.asm` - Probe system reference

View File

@@ -0,0 +1,84 @@
# Custom Items System
This document details the functionality of new and modified items in Oracle of Secrets, based on analysis of the `Items/` directory.
## 1. Overview
The item roster has been significantly expanded with new mechanics, and many vanilla items have been reworked to provide new functionality. The system is managed through a combination of hooks into the main player state machine and custom routines for each item.
## 2. Vanilla Item Modifications
Several items from the original game have been altered.
### Hookshot / Goldstar
- **Files:** `goldstar.asm`
- **Functionality:** The Hookshot can be upgraded to the **Goldstar**, a powerful morning star weapon. The two items share an inventory slot.
- **Switching:** When the Goldstar is obtained, the player can switch between the Hookshot and Goldstar by pressing the L/R shoulder buttons while it is selected in the menu. The current mode is tracked by the `GoldstarOrHookshot` WRAM variable.
- **Goldstar Mechanics:** When active, the item functions as a short-range, powerful melee weapon with its own collision and damage properties, distinct from the Hookshot's grappling mechanic.
### Ice Rod
- **File:** `ice_rod.asm`
- **Functionality:** The Ice Rod's projectile now freezes water tiles it hits, creating temporary 16x16 ice platforms. This allows the player to cross water gaps.
- **Implementation:** The `LinkItem_IceRod` routine hooks into the ancilla tile collision logic. When the projectile hits a water tile, it dynamically modifies the tilemap properties in RAM and DMAs new ice graphics to VRAM.
### Bug-Catching Net -> Roc's Feather
- **File:** `jump_feather.asm`
- **Functionality:** The vanilla Bug-Catching Net has been completely replaced by **Roc's Feather**. This item allows Link to perform a short hop.
- **Implementation:** `LinkItem_JumpFeather` initiates the jump by setting Link's state to a recoil/ledge hop state and applying a burst of vertical velocity.
### Bottles
- **File:** `bottle_net.asm`
- **Functionality:** The Bug-Catching Net is no longer required to catch bees, fairies, etc. The Bottle item now has a dual function:
1. If the bottle is **empty**, using it initiates the `LinkItem_CatchBottle` routine, which performs a net-catching swing.
2. If the bottle is **full**, using it calls `LinkItem_Bottles`, which consumes the contents (e.g., drinks a potion, releases a fairy).
### Book of Mudora -> Book of Secrets
- **File:** `book_of_secrets.asm`
- **Functionality:** The Book of Mudora is now the **Book of Secrets**. While its vanilla function of translating Hylian text remains, it has a new secret-revealing capability.
- **Implementation:** The `Dungeon_RevealSecrets` routine checks if the L button is held while inside a building. If it is, it disables the `BG2` layer, which can be used to hide secret passages or objects behind walls that are part of that background layer.
## 3. New Active Items
### Ocarina
- **File:** `ocarina.asm`
- **Functionality:** A multi-song instrument. When selected, the player can cycle through learned songs using the L/R shoulder buttons. Pressing 'Y' plays the selected song, triggering its unique effect.
- **Songs & Effects:**
- **Song of Healing:** Heals certain NPCs or triggers quest events.
- **Song of Storms:** Toggles a rain overlay on the overworld, which can affect the environment (e.g., watering the Magic Bean).
- **Song of Soaring:** Warps the player to pre-defined locations (the vanilla flute's bird travel).
- **Song of Time:** Toggles the in-game time between day and night.
### Shared Slot: Portal Rod & Fishing Rod
- **Files:** `portal_rod.asm`, `fishing_rod.asm`
- **Functionality:** These two distinct items share a single inventory slot. If the player has the upgrade (`$7EF351 >= 2`), they can swap between the two by pressing L/R in the menu.
- **Portal Rod:** Fires a projectile that creates a portal sprite (blue or orange). The `Ancilla_HandlePortalCollision` logic detects when another projectile (like an arrow) hits a portal and teleports it to the other portal's location.
- **Fishing Rod:** Initiates a fishing minigame. `LinkItem_FishingRod` spawns a "floater" sprite, and the player can reel it in to catch fish or other items from a prize table.
## 4. New Passive Items
### Magic Rings
- **File:** `magic_rings.asm`
- **Functionality:** Passive items that grant buffs when equipped in one of the three ring slots in the Quest Status menu. The effects are applied by hooking into various game logic routines.
- **Implemented Rings:**
- **Power Ring:** Increases sword damage.
- **Armor Ring:** Reduces damage taken by half.
- **Heart Ring:** Slowly regenerates health over time.
- **Light Ring:** Allows the sword to shoot beams even when Link is not at full health (down to -2 hearts from max).
- **Blast Ring:** Increases the damage of bombs.
- **Steadfast Ring:** Prevents or reduces knockback from enemy hits.
## 5. Consumable Items (Magic Bag)
- **File:** `all_items.asm`
- **Functionality:** The Magic Bag is a sub-menu that holds new consumable items. The `Link_ConsumeMagicBagItem` routine is a jump table that executes the effect for the selected item.
- **Consumables:**
- **Banana:** Implemented. Restores a small amount of health (`#$10`).
- **Pineapple, Rock Meat, Seashells, Honeycombs, Deku Sticks:** Placeholder entries exist in the jump table, but their effects are not yet implemented (the routines just contain `RTS`).

View File

@@ -0,0 +1,145 @@
# Mask System
This document provides a detailed analysis of the Mask System in Oracle of Secrets, based on the code in the `Masks/` directory. The system allows Link to transform into various forms, each with unique graphics, palettes, and abilities.
## 1. System Architecture
The Mask System is built around a central WRAM variable and a set of core routines that handle transformations, graphics, and palettes.
- **`!CurrentMask` (`$02B2`):** A WRAM variable that stores the ID of the currently active mask. A value of `0x00` represents Link's normal human form.
- **`!LinkGraphics` (`$BC`):** A WRAM variable that holds the bank number for Link's current graphics sheet. The Mask System changes this value to load the appropriate sprite graphics for each form.
### Mask IDs
| ID | Mask / Form |
|------|---------------|
| `00` | Human (Default) |
| `01` | Deku Mask |
| `02` | Zora Mask |
| `03` | Wolf Mask |
| `04` | Bunny Hood |
| `05` | Minish Form |
| `06` | GBC Form |
| `07` | Moosh Form |
## 2. Core Routines & Hooks (`Masks/mask_routines.asm`)
A set of shared routines and hooks form the backbone of the system.
- **`Link_TransformMask`:** This is the primary function for changing forms. It is typically called when the player uses a mask item.
- **Trigger:** It requires a new R-button press (`CheckNewRButtonPress`) to prevent rapid toggling.
- **Logic:** It takes a mask ID in the A register. If the requested mask is already active, it reverts Link to his human form. Otherwise, it sets `!CurrentMask`, updates the graphics bank in `$BC` from a lookup table, and calls `Palette_ArmorAndGloves` to apply the new look.
- **Effect:** It spawns a "poof" of smoke (`AddTransformationCloud`) and plays a sound effect.
- **`Palette_ArmorAndGloves` (Hook):** This routine hooks the vanilla palette loading function (`$1BEDF9`). It checks `!CurrentMask` and jumps to the appropriate `Update...Palette` routine for the active form, ensuring the correct colors are loaded. If no mask is active, it proceeds with the vanilla logic for loading Link's tunic color.
- **`LinkItem_CheckForSwordSwing_Masks` (Hook):** This routine hooks the vanilla sword swing check (`$079CD9`). It prevents certain forms (Deku, Wolf, Minish, Moosh) from using the sword, while allowing others (Zora, GBC Link) to use it freely.
- **Reset Routines:**
- `ResetToLinkGraphics`: Reverts Link to his default graphics and `!CurrentMask = 0`.
- `ForceResetMask_GameOver` / `ForceResetMask_SaveAndQuit`: Hooks into the game over and save/quit routines to ensure Link's form is reset before the game saves or restarts.
## 3. Transformation Masks
These masks grant Link new forms with significant new abilities.
### Deku Mask
- **File:** `Masks/deku_mask.asm`
- **Transformation:** Replaces the Quake Medallion. Pressing 'Y' with the item selected transforms Link.
- **Abilities:**
- **Spin Attack:** Pressing 'Y' performs a spinning attack.
- **Deku Bubble:** If not on a Deku Flower, the spin attack also shoots a bubble projectile (`Ancilla0E_MagicBubble`).
- **Hover:** If standing on a Deku Flower (tile property check sets WRAM `$71`), the spin attack launches Link into the air, allowing him to hover for a short time.
- **Bomb Drop:** While hovering, pressing 'Y' drops a bomb.
- **Cancel Hover:** Pressing 'B' or letting the timer expire cancels the hover.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x01`
- `DekuFloating` (`$70`): Flag set when Link is hovering.
- `DekuHover` (`$71`): Flag set when Link is standing on a Deku Flower, enabling the hover ability.
- **Code Interactions:**
- Hooks `LinkItem_Quake` (`$07A64B`).
- Repurposes Link's "Using Quake Medallion" state (`$5D = 0x0A`) for the hover ability.
- Hooks `LinkOAM_DrawShield` (`$0DA780`) to prevent the shield from being drawn.
### Zora Mask
- **File:** `Masks/zora_mask.asm`
- **Transformation:** Replaces the Bombos Medallion. Pressing 'Y' with the item selected transforms Link.
- **Abilities:**
- **Diving:** Allows Link to dive in deep water by pressing 'Y'. Pressing 'Y' again resurfaces.
- **Overworld Diving:** When diving in the overworld, Link becomes invincible, moves faster, and is hidden beneath a ripple effect.
- **Dungeon Diving:** When diving in a dungeon, Link moves to the lower layer (`$EE=0`), allowing him to swim under floors and obstacles.
- **Sword:** The Zora form can use the sword.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x02`
- `!ZoraDiving` (`$0AAB`): Flag set when Link is currently underwater.
- **Code Interactions:**
- Hooks `LinkItem_Bombos` (`$07A569`).
- Hooks the end of `LinkState_Swimming` (`$079781`) to handle the dive input.
- Hooks the end of `LinkState_Default` (`$0782D2`) to handle resurfacing in dungeons.
- Hooks `Link_HopInOrOutOfWater_Vertical` (`$07C307`) to reset the dive state when using water stairs.
### Wolf Mask
- **File:** `Masks/wolf_mask.asm`
- **Transformation:** Shares an item slot with the Flute. When selected, it replaces the Shovel. Pressing 'Y' transforms Link.
- **Abilities:**
- **Dig:** When transformed, pressing 'Y' executes the vanilla `LinkItem_Shovel` routine, allowing Wolf Link to dig for items without needing the shovel.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x03`
- **Code Interactions:**
- Hooks the `LinkItem_Shovel` vector (`$07A313`) to a new `LinkItem_ShovelAndFlute` routine that dispatches between the Flute and Wolf Mask logic based on the selected item (`$0202`).
### Minish Form
- **File:** `Masks/minish_form.asm`
- **Transformation:** Context-sensitive. When standing on a special portal tile (`ID 64`), pressing 'R' transforms Link into Minish form. Pressing 'R' on the portal again reverts him.
- **Abilities:**
- **Access Minish Areas:** Allows Link to pass through special small openings (`Tile ID 65`).
- **Restricted Actions:** Cannot lift objects.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x05`
- **Code Interactions:**
- Hooks the overworld (`$07DAF2`) and underworld (`$07D8A0`) tile collision tables to add handlers for the portal and passage tiles.
- Hooks the lift check (`$079C32`) to disable lifting while in Minish form.
### Moosh Form
- **File:** `Masks/moosh.asm`
- **Transformation:** The trigger for transforming into Moosh is not defined within the mask's own file, but is handled by `Link_TransformMoosh`.
- **Abilities:**
- **Hover Dash:** Attempting to use the Pegasus Boots (dash) while in Moosh form will instead trigger a short hover, similar to the Deku Mask's ability.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x07`
- **Code Interactions:**
- Hooks the dash initiation logic (`$079093`) to intercept the dash and call `PrepareQuakeSpell`, which sets Link's state to `0x0A` (hover).
- Shares the hover/recoil animation logic with the Deku Mask.
## 4. Passive & Cosmetic Forms
### Bunny Hood
- **File:** `Masks/bunny_hood.asm`
- **Transformation:** Replaces the Ether Medallion. Pressing 'Y' activates the Bunny Hood state. This is a state change, not a visual transformation.
- **Abilities:**
- **Increased Speed:** While the Bunny Hood is the active mask (`!CurrentMask = 0x04`), Link's movement speed is increased across various actions (walking, carrying, etc.). The specific speed values are defined in `BunnySpeedTable`.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x04`
- **Code Interactions:**
- Hooks `LinkItem_Ether` (`$07A494`) to trigger the state change.
- Hooks the velocity calculation in the player engine (`$07E330`) to load custom speed values from a table.
### GBC Form
- **File:** `Masks/gbc_form.asm`
- **Transformation:** An automatic, cosmetic transformation that occurs whenever Link is in the Dark World.
- **Abilities:**
- Changes Link's graphics to a Game Boy Color-inspired sprite.
- Applies a unique, limited-color palette. The palette correctly reflects Link's current tunic (Green, Blue, or Red).
- This form can still use the sword.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x06`
- `$0FFF`: The vanilla Dark World flag.
- **Code Interactions:**
- Hooks numerous overworld, underworld, and transition routines to consistently apply the effect when in the Dark World and remove it when in the Light World.

View File

@@ -0,0 +1,77 @@
# Custom Menu & HUD System
This document provides a detailed analysis of the custom menu and Heads-Up Display (HUD) systems in Oracle of Secrets, based on the code in the `Menu/` directory.
## 1. Overview
The project features a completely custom menu and HUD, replacing the vanilla systems. The menu is a robust, multi-screen system, while the HUD provides a clean, modern interface for in-game stats.
- **Menu System**: A two-page design that separates selectable items from quest status and equipment. It is accessible by pressing the Start button.
- **HUD System**: A persistent on-screen display for health, magic, rupees, and the currently equipped item.
## 2. Menu System Architecture
The entire menu operates as a large state machine, with the main entry point being `Menu_Entry` in `Menu/menu.asm`. The flow is controlled by the value in WRAM `$0200`.
### 2.1. Main State Machine
The `Menu_Entry` routine uses a jump table (`.vectors`) to execute different subroutines based on the state in `$0200`. This modular approach allows for a clean separation of tasks like initialization, drawing, input handling, and screen transitions.
**Key States in `$0200`:**
| State ID | Label | Purpose |
|----------|----------------------------|-------------------------------------------------------------------------|
| `0x00` | `Menu_InitGraphics` | Initializes the menu, clears player state, and prepares for drawing. |
| `0x01` | `Menu_UploadRight` | Draws the entire right-hand screen (Quest Status). |
| `0x02` | `Menu_UploadLeft` | Draws the entire left-hand screen (Item Selection). |
| `0x04` | `Menu_ItemScreen` | The main interactive state for the Item screen. Handles cursor movement. |
| `0x05` | `Menu_ScrollTo` | Handles the smooth scrolling animation when moving from Items to Quest. |
| `0x06` | `Menu_StatsScreen` | The main interactive state for the Quest Status screen. |
| `0x0A` | `Menu_Exit` | Exits the menu, restores the game state, and updates the equipped item. |
| `0x0C` | `Menu_MagicBag` | A sub-menu for viewing collectible items. |
| `0x0D` | `Menu_SongMenu` | A sub-menu for selecting Ocarina songs. |
| `0x0E` | `Menu_Journal` | A sub-menu for reading the player's journal. |
| `0x09` | `Menu_RingBox` | A sub-menu for managing magic rings. |
### 2.2. Item Selection Screen (Left Page)
This is the primary interactive screen where the player selects their Y-button item.
- **Drawing (`DrawYItems`):** This routine is responsible for rendering all 24 item slots. It reads the SRAM address for each slot from `Menu_AddressIndex` (`menu_select_item.asm`), checks if the player owns the item, and then calls `DrawMenuItem`.
- **`DrawMenuItem`:** This generic function is the core of the drawing system. It takes an item's SRAM value (e.g., Sword level 0-4) and uses it to look up the correct 16x16 tile data from a large graphics table in `Menu/menu_gfx_table.asm`. This makes the menu highly data-driven.
- **Selection (`menu_select_item.asm`):** Cursor movement is handled by `Menu_FindNextItem`, `Menu_FindPrevItem`, etc. These routines intelligently skip over empty slots, ensuring the cursor always lands on a valid item. The currently selected slot index is stored in `$0202`.
### 2.3. Quest Status Screen (Right Page)
This screen is a static display of the player's overall progress.
- **Drawing:** It is rendered by a series of functions in `menu_draw.asm`, including:
- `Menu_DrawQuestItems`: Draws equipped sword, shield, tunic, etc.
- `Menu_DrawPendantIcons` & `Menu_DrawTriforceIcons`: Reads SRAM flags to draw collected pendants and crystals.
- `Menu_DrawCharacterName`: Reads the player's name from SRAM and renders it.
- `DrawLocationName`: Reads the current overworld area (`$008A`) or underworld room (`$00A0`) and looks up the corresponding name from the tables in `menu_map_names.asm`.
## 3. HUD System Architecture
The HUD is a separate system that hooks the vanilla game's NMI rendering routines. Its main entry point is `HUD_Update` in `Menu/menu_hud.asm`.
- **Functionality:** The `HUD_Update` routine runs every frame during gameplay. It reads player stats directly from SRAM and WRAM and draws them to the VRAM buffer for the top of the screen.
- **Key Drawing Logic:**
- **Hearts:** `HUD_UpdateHearts` is a loop that draws empty hearts based on `MAXHP` (`$7EF36C`) and then overlays full/partial hearts based on `CURHP` (`$7EF36D`).
- **Magic Meter:** It reads `MagicPower` (`$7EF36E`) and uses the `MagicTilemap` lookup table to find the correct tiles to display the green bar.
- **Counters:** It uses a `HexToDecimal` routine to convert the values for Rupees, Bombs, and Arrows into drawable digits.
- **Equipped Item:** `HUD_UpdateItemBox` reads the currently equipped item index (`$0202`), finds its graphics data in the `HudItems` table, and draws the icon in the top-left box.
## 4. Data-Driven Design & Areas for Improvement
The entire menu and HUD are heavily data-driven, which is a major strength.
- **Graphics:** All item icons for both the menu and HUD are defined in data tables in `menu_gfx_table.asm` and `menu_hud.asm`, not hardcoded.
- **Item Layout:** The position and SRAM address of every item in the menu are defined in the `Menu_ItemCursorPositions` and `Menu_AddressIndex` tables, allowing the layout to be easily changed.
- **Text:** Item names, location names, and other text are all stored in data tables in `menu_text.asm` and `menu_map_names.asm`.
This analysis confirms the suggestions in the placeholder `Menu.md` file:
1. **Refactor Redundant Code:** The input handling logic for the Magic Bag, Song Menu, and Ring Box is nearly identical and is a prime candidate for being refactored into a single, reusable subroutine.
2. **Use `table` for Jump Tables:** The main `Menu_Entry` jump table is created with manual `dw` directives and would be cleaner and safer if generated with asar's `table` directive.
3. **Replace Hardcoded Values:** Hardcoded state values (e.g., `LDA.b #$0C : STA.w $0200`) should be replaced with named constants (`!MENU_STATE_MAGIC_BAG = $0C`) for readability and maintainability.

View File

@@ -0,0 +1,137 @@
# Music Creation Guide
This document details the process for creating and integrating custom music into Oracle of Secrets. The project uses the native Super Nintendo Packet Chip (N-SPC) music format, abstracted through a powerful set of `asar` macros.
## 1. N-SPC Music Format Primer
Music in the N-SPC engine is structured around eight independent channels. Each channel is a stream of bytes that are read sequentially. The stream consists of two types of data:
- **Commands:** Special bytes (from `$E0` to `$FF`) that control aspects of the sound, such as setting the instrument, changing volume, or calling a subroutine.
- **Notes:** A note consists of a duration byte followed by one or more tone bytes. The duration byte (e.g., `$48` for a quarter note) determines how long the following tone(s) will play.
## 2. The Macro System (`Core/music_macros.asm`)
To make composing more intuitive, the project uses a comprehensive library of macros that wrap the raw N-SPC commands into readable names. All music files must include `Core/music_macros.asm`.
### Key Concepts
- **Note Durations:** Constants are defined for standard note lengths (e.g., `!4th`, `!8th`, `!16th`).
- **Note Tones:** Constants are defined for all notes across several octaves (e.g., `C4`, `G4s` for G#4, `A5`).
- **Special Notes:** `Tie` (`$C8`) continues the previous note for the new duration, and `Rest` (`$C9`) signifies silence.
### Core Macros
- **`%SetInstrument(id)`:** Sets the instrument for the current channel (e.g., `%SetInstrument($09)` for Strings). Helper macros like `%Strings()`, `%Piano()`, etc., exist for common instruments.
- **`%SetTempo(value)`:** Sets the overall playback speed of the song.
- **`%SetMasterVolume(value)` / `%SetChannelVolume(value)`:** Sets the volume for the entire song or just the current channel.
- **`%CallSubroutine(address, repeats)`:** The most important macro for structuring songs. It jumps to a labeled subroutine, plays it `repeats+1` times, and then returns. **This is the primary method for looping musical phrases.**
- **`%VibratoOn(delay, rate, depth)`:** Adds a vibrato effect.
- **`%TremoloOn(delay, rate, depth)`:** Adds a tremolo (volume fluctuation) effect.
- **`%SetPan(value)`:** Sets the stereo position (left/right) of the channel.
- **`%EchoVBits(switch, left, right)`:** Enables and configures echo for the channel.
## 3. Song File Structure
Every song `.asm` file follows a standard structure.
#### 1. Header
The file begins with a header that defines metadata for the song engine.
```asm
MyNewSong:
!ARAMAddr = $D86A ; Base address in ARAM for this song
dw !ARAMAddr+$0A ; Pointer to the Intro section
dw !ARAMAddr+$1A ; Pointer to the Main (looping) section
dw $00FF ; Default fade-in
dw !ARAMAddr+$02 ; Start of the looping section data
dw $0000
```
#### 2. Channel Pointers
Next is a table of pointers to each of the eight channel data blocks. The `!ARAMC` constant is used to make these pointers relative to the song's ARAM address.
```asm
.Channels
!ARAMC = !ARAMAddr-MyNewSong
dw .Channel0+!ARAMC
dw .Channel1+!ARAMC
; ...up to 8 channels, use dw $0000 for unused channels
```
#### 3. Channel Data
Each channel is a block of code containing commands and notes.
```asm
.Channel0
%SetMasterVolume($DA)
%SetTempo(62)
%SetInstrument($02) ; Tympani
%SetDurationN(!4th, $7F)
%CallSubroutine(.sub1+!ARAMC, 23) ; Call subroutine .sub1 24 times
db End ; $00, signifies end of channel data
```
#### 4. Subroutines
The bulk of a song is made of small, labeled subroutines containing musical phrases. These are placed after the channel data.
```asm
.sub1
db !4th, B1, B1, !8th, Tie, C2, !4th, F3s
db End ; Subroutines must also end with $00
```
## 4. How to Add a New Song
1. **Create the File:** Create a new `.asm` file in the `Music/` directory.
2. **Copy Template:** Copy the contents of an existing song (e.g., `stone_tower_temple_v2.asm`) into your new file to use as a template.
3. **Set Header:** Change the main label (e.g., `MyNewSong:`) and set the `!ARAMAddr`. This address must be unique and not conflict with other songs.
4. **Compose:** Write your music in the channel and subroutine blocks using the note constants and macros.
5. **Integrate the Song:**
- Open `Music/all_music.asm` and add an `incsrc` for your new file.
- To replace a vanilla song, find its label in the ROM map and use `org` to place your new song at that address. For example, to replace the Lost Woods theme:
```asm
org $1AADDE ; Original address of Lost Woods theme
incsrc "Music/MyNewSong.asm"
```
- To add a new song to the expanded Dark World bank, open `Music/expanded.asm` and add a new entry to the `SongBank_OverworldExpanded_Main` table.
## 5. Proposals for Improved Organization
The current system is functional but can be made more readable and maintainable.
1. **Standardize Subroutine Naming:** The current convention of `.sub1`, `.sub101`, etc., is ambiguous. A clearer naming scheme would greatly improve readability.
- **Proposal:** Name subroutines based on their musical function, like `.MelodyVerseA`, `.BasslineIntro`, `.PercussionFill1`. This makes the main channel blocks easier to read as a high-level song structure.
2. **Create a Common Patterns Library:** Many songs use similar rhythmic or melodic patterns (e.g., a standard 4/4 drum beat, an arpeggiated chord).
- **Proposal:** Create a `Music/common_patterns.asm` file. This file could contain a library of generic, reusable subroutines for things like drum patterns, basslines, or common arpeggios. Songs could then `incsrc` this library and call these patterns, reducing code duplication and speeding up composition.
3. **Develop Advanced Composition Macros:** The existing helper macros are basic. More advanced macros could abstract away the manual process of defining and calling subroutines.
- **Proposal:**
- `%DefineMeasure(Name, Notes...)`: A macro that takes a name and a list of notes and automatically creates a correctly formatted subroutine block.
- `%PlayMeasure(Name, Repeats)`: A macro that automatically calculates the relative address (`+!ARAMC`) and calls `%CallSubroutine`.
- **Example Workflow with Proposed Macros:**
```asm
; --- Subroutine Definitions ---
%DefineMeasure(VerseMelody, !8th, C4, D4, E4, F4, G4, A4, B4, C5)
%DefineMeasure(VerseBass, !4th, C2, G2, A2, F2)
; --- Channel Data ---
.Channel0
; ... setup ...
%PlayMeasure(VerseMelody, 4) ; Plays the melody 4 times
db End
.Channel1
; ... setup ...
%PlayMeasure(VerseBass, 4) ; Plays the bassline 4 times
db End
```
This approach would make the main channel data blocks read like a high-level song arrangement, significantly improving clarity.
4. **Improve In-File Documentation:**
- **Proposal:** Encourage the use of comments to label major song sections directly within the channel data (e.g., `; --- VERSE 1 ---`, `; --- CHORUS ---`). This provides crucial signposting when navigating complex song files.

848
Docs/GEMINI.md Normal file
View File

@@ -0,0 +1,848 @@
# Gemini Development Guidelines for Oracle of Secrets
This document outlines the established coding conventions, architectural patterns, and best practices observed in the Oracle of Secrets project. Adhering to these guidelines will ensure consistency and maintainability.
## 1. SNES 65816 Processor Basics
### 1.1. Architecture Overview
The 65816 is an 8/16-bit microprocessor used in the Super Nintendo Entertainment System (SNES). It operates in two modes: emulation mode (6502-compatible, 8-bit) and native mode (65816, 16-bit). The SNES typically runs in native mode.
### 1.2. Key Registers
- **A (Accumulator):** The primary register for data manipulation. Its size (8-bit or 16-bit) is controlled by the M flag in the Processor Status Register.
- **X, Y (Index Registers):** Used for addressing memory. Their size (8-bit or 16-bit) is controlled by the X flag in the Processor Status Register.
- **S (Stack Pointer):** Points to the current top of the stack.
- **D (Direct Page Register):** Used for direct page addressing, allowing faster access to the first 256 bytes of each bank.
- **DB (Data Bank Register):** Specifies the current 64KB data bank for memory accesses.
- **PB (Program Bank Register):** Specifies the current 64KB program bank for instruction fetches.
- **P (Processor Status Register):** A crucial 8-bit register containing various flags:
- **N (Negative):** Set if the result of an operation is negative.
- **V (Overflow):** Set if an arithmetic overflow occurs.
- **M (Memory/Accumulator Select):** Controls the size of the A register (0=16-bit, 1=8-bit).
- **X (Index Register Select):** Controls the size of the X and Y registers (0=16-bit, 1=8-bit).
- **D (Decimal Mode):** Enables BCD arithmetic (rarely used in SNES development).
- **I (IRQ Disable):** Disables interrupt requests.
- **Z (Zero):** Set if the result of an operation is zero.
- **C (Carry):** Used for arithmetic operations and bit shifts.
### 1.3. Processor Status Register (P) Manipulation
- **`SEP #$20` (or `SEP #$30`):** Sets the M flag (and X flag if $30 is used) to 1, switching A (and X/Y) to 8-bit mode.
- **`REP #$20` (or `REP #$30`):** Resets the M flag (and X flag if $30 is used) to 0, switching A (and X/Y) to 16-bit mode.
- **Importance:** Mismatched M/X flags between calling and called routines are a common cause of crashes (BRKs) or unexpected behavior. Always ensure the P register is in the expected state for a given routine, or explicitly set it.
**Practical Example:**
```asm
; INCORRECT: Size mismatch causes corruption
REP #$20 ; A = 16-bit
LDA.w #$1234 ; A = $1234
SEP #$20 ; A = 8-bit now
LDA.w #$1234 ; ERROR: Assembler generates LDA #$34, $12 becomes opcode!
; CORRECT: Match processor state to operation
REP #$20 ; A = 16-bit
LDA.w #$1234 ; A = $1234
SEP #$20 ; A = 8-bit
LDA.b #$12 ; Load only 8-bit value
```
**Best Practice:**
```asm
MyFunction:
PHP ; Save caller's processor state
SEP #$30 ; Set to known 8-bit state
; ... your code here ...
PLP ; Restore caller's processor state
RTL
```
See `Docs/General/Troubleshooting.md` Section 3 for comprehensive processor state troubleshooting.
### 1.4. Memory Mapping
- The SNES has a 24-bit address space, allowing access to up to 16MB of ROM/RAM.
- **Banks:** Memory is organized into 256 banks of 64KB each.
- **Direct Page (Bank 00):** The first 256 bytes of bank 00 (`$0000-$00FF`) are special and can be accessed quickly using direct page addressing (when D=0).
- **WRAM (Work RAM):** Located in banks $7E-$7F. This is where most game variables and temporary data are stored.
- **SRAM (Save RAM):** Typically located in banks $70-$7D, used for saving game progress.
## 2. Asar Best Practices
### 2.1. `pushpc`/`pullpc` and `org`
- **Guideline:** While `pushpc`/`pullpc` is good for isolating small, targeted patches, extreme care must be taken. Patches that use `org` to place new code into freespace (e.g., `org $2B8000`) have a dependency on their location within the file. Moving these `org` blocks can break the ROM by changing the memory layout.
- **Rationale:** The order of `incsrc` and `org` directives determines the final ROM layout. Moving a freespace `org` block to a central `patches.asm` file changes this order and will likely cause errors. Simple, single-line patches that modify existing vanilla code can often be moved, but larger blocks of new code should remain in their contextually relevant files.
### 2.2. Scoping and Style
- **Guideline:** The established code style uses labels followed by `{}` brackets to define scope for new blocks of logic. This convention must be followed. The `subroutine`/`endsubroutine` keywords are explicitly *not* to be used in this project.
- **Rationale:** The `subroutine`/`endsubroutine` keywords are not used in this project. Maintaining a consistent style is crucial for readability.
### 2.3. Data Organization
- **Guideline:** For complex, related data (like sprite state or system configurations), use `struct`. For jump tables or data arrays, use `table`.
- **Rationale:** These directives make data structures explicit and readable. They replace confusing pointer arithmetic and manual offset calculations with clear, named accessors, which is less error-prone.
### 2.4. Define Constants for Magic Numbers
- **Guideline:** Avoid hardcoding numerical values. Use `!` or `define()` to create named constants for RAM/SRAM addresses, item IDs, sprite states, tile IDs, etc.
- **Rationale:** This makes the code self-documenting and significantly easier to maintain and debug.
### 2.5. Opcode Size Suffixes (.b, .w, .l)
`asar` can often infer operand sizes, but relying on this can lead to bugs when the processor state (M and X flags) is not what you expect. To write robust, readable, and safe code, you should use explicit size suffixes.
- **`.b` (byte):** Forces an 8-bit operation. Use this when you are certain you are working with a single byte.
- Example: `LDA.b $7E0010` will correctly load a single byte into the accumulator, regardless of the M flag's state.
- **`.w` (word):** Forces a 16-bit operation. Use this when working with two bytes (a word).
- Example: `LDA.w $7E0022` will load a 16-bit value. This is essential for correctness if the M flag is 1 (8-bit mode).
- **`.l` (long):** Forces a 24-bit operation, typically for addresses in `JML` or `JSL`.
- Example: `JSL.l SomeRoutineInAnotherBank`
**Golden Rule:** A mismatch between the M/X flags and the intended operation size is a primary cause of crashes. When in doubt, wrap your code in `REP`/`SEP` to explicitly set the processor state, and use size suffixes to make your intent clear to both the assembler and future developers.
## 3. Project-Specific Conventions
### 3.1. File & Directory Structure
- The project is well-organized by functionality (`Core`, `Items`, `Sprites`, `Overworld`, etc.). New code should be placed in the appropriate directory.
- Central include files (e.g., `all_items.asm`, `all_sprites.asm`) are used to aggregate modules. This is a good pattern to continue.
### 3.2. Patch Management
- **Guideline:** Hooks and patches should be placed logically near the code they relate to, not centralized in `Core/patches.asm`. This improves code organization, maintainability, and context preservation.
- **Rationale:** When a hook modifies vanilla behavior to add custom functionality, placing the hook in the same file as the custom implementation keeps related code together. This makes it easier to understand the complete feature, debug issues, and maintain the codebase.
- **Exception:** Only truly generic, cross-cutting patches that don't belong to any specific feature should be considered for `Core/patches.asm`.
### 3.3. Debugging
- The `!DEBUG` flag and `%print_debug()` macro in `Util/macros.asm` should be used for all build-time logging. This allows for easy enabling/disabling of diagnostic messages.
### 3.4. Referencing Vanilla Code (`usdasm`)
- When hooking or modifying vanilla code, it is essential to understand the original context. The `usdasm` disassembly is the primary reference for this.
- To find the original code for a patch at a given address (e.g., `$07A3DB`), you can search for the SNES address in the `usdasm` files (e.g., `#_07A3DB:`).
- **Vanilla labels are not included by default.** The `usdasm` project is a reference, not part of the build. If you need to call a vanilla routine, you must find its implementation in the disassembly and explicitly copy or recreate it within the `Oracle of Secrets` source, giving it a new label (e.g., inside the `Oracle` namespace).
- **Disassembly files are for reference only.** Never modify any files within the `usdasm` directory. All changes must be made within the `Oracle of Secrets` project files.
### 3.5. Namespacing
- **Guideline:** The majority of the *Oracle of Secrets* codebase is organized within an `Oracle` namespace, as defined in `Oracle_main.asm`. However, some modules, notably `ZSCustomOverworld.asm`, are included *outside* of this namespace.
- **Interaction:** To call a function that is inside the `Oracle` namespace from a file that is outside of it (like `ZSCustomOverworld.asm`), you must prefix the function's label with `Oracle_`. For example, to call the `CheckIfNight16Bit` function (defined inside the namespace), you must use `JSL Oracle_CheckIfNight16Bit`.
- **Rationale:** The build process correctly resolves these `Oracle_` prefixed labels to their namespaced counterparts (e.g., `Oracle.CheckIfNight16Bit`). Do not add the `Oracle_` prefix to the original function definition; it is only used by the calling code outside the namespace.
**Practical Example - Oracle to ZScream:**
```asm
// In ZScream file (no namespace):
LoadOverworldSprites_Interupt:
{
; ZScream code here
RTL
}
// Export to Oracle namespace:
namespace Oracle
{
Oracle_LoadOverworldSprites_Interupt = LoadOverworldSprites_Interupt
}
// Now Oracle code can call it:
namespace Oracle
{
MyFunction:
JSL Oracle_LoadOverworldSprites_Interupt ; Use prefix!
RTL
}
```
**Practical Example - ZScream to Oracle (Bridge Pattern):**
```asm
// Oracle implementation:
namespace Oracle
{
CheckIfNight:
LDA.l $7EE000 ; Check time system
; ... logic ...
RTL
}
// Bridge function (no namespace):
ZSO_CheckIfNight:
{
JSL Oracle_CheckIfNight ; Can call INTO Oracle
RTL
}
// Export bridge:
namespace Oracle
{
Oracle_ZSO_CheckIfNight = ZSO_CheckIfNight
}
// ZScream hook can use it:
org $09C4C7
LoadOverworldSprites_Hook:
JSL Oracle_ZSO_CheckIfNight ; Bridge function
```
For comprehensive namespace troubleshooting and advanced patterns, see:
- `Docs/World/Overworld/ZSCustomOverworldAdvanced.md` Section 5 (Cross-Namespace Integration)
- `Docs/General/Troubleshooting.md` Section 5 (Cross-Namespace Calling)
- `Docs/General/DevelopmentGuidelines.md` Section 2.4 (Namespace Architecture)
### 3.6. Safe Hooking and Code Injection
When modifying vanilla game logic, it is critical to never edit the disassembly files in `ALTTP/` or `usdasm/` directly. Instead, use the following safe hooking method to inject custom code.
- **1. Identify a Target and Free Space:**
- Locate the exact address in the vanilla code you want to modify (the "hook point").
- Identify a free bank or region in the ROM to place your new, expanded code.
- **2. Choose the Appropriate File for Your Hook:**
- **Feature-Specific Hooks:** Place hooks in the same file as the custom implementation they enable. For example, if you're adding a new item feature in `Items/magic_ring.asm`, place the vanilla hook in that same file.
- **Module-Specific Hooks:** For hooks that modify core game systems (sprite engine, player engine, etc.), place them in the relevant module file within the `Core/` directory.
- **Generic Patches:** Only place truly generic, cross-cutting modifications in `Core/patches.asm` (e.g., fixes to vanilla bugs, performance optimizations).
- **Rationale:** Co-locating hooks with their implementations improves code organization, makes features self-contained, and provides better context for future maintenance.
- **3. Write the Hook:**
- Use `pushpc` and `pullpc` to isolate your patch.
- Use `org` to navigate to the target address in the vanilla code.
- At the target address, overwrite the original instruction(s) with a `JSL` (or `JMP`) to your new custom routine in free space.
- **Crucially, ensure your `JSL`/`JMP` instruction and any necessary `NOP`s perfectly replace the original instruction(s) byte-for-byte.** A `JSL` is 4 bytes. If you overwrite an instruction that is only 2 bytes, you must add `NOP` instructions to fill the remaining 2 bytes to avoid corrupting the subsequent instruction.
- **4. Implement the Custom Routine:**
- In a `freedata` block (or using `org` with a free space address), write your new routine in the same file as the hook.
- **Preserve Overwritten Code:** The first thing your new routine must do is execute the exact vanilla instruction(s) that you overwrote with your `JSL`. This is essential to maintain the original game's behavior.
- After preserving the original logic, add your new custom code.
- End your routine with an `RTL` (to return from a `JSL`) or `RTS` (to return from a `JSR`).
- **Example (Feature-Specific Hook):**
```asm
; In Items/magic_ring.asm
; 1. Place the new, expanded logic in a free bank.
org $348000
MagicRing_CustomEffect:
{
; 2. First, execute the original instruction(s) that were overwritten.
LDA.b #$01 ; Example: Original instruction was LDA #$01 (2 bytes)
STA.w $0DD0,X ; Example: Original instruction was STA $0DD0,X (3 bytes)
; 3. Now, add your new custom logic for the magic ring.
LDA.l MagicRing ; Check if player has magic ring
BEQ .no_ring
LDA.b #$FF ; Apply ring's special effect
STA.w $1234,X
.no_ring
; 4. Return to the vanilla code.
RTL
}
; 5. Hook placement: In the same file, near the feature implementation
pushpc
org $05C227 ; Target address in vanilla sprite damage routine
JSL MagicRing_CustomEffect ; JSL is 4 bytes.
NOP ; Fill the 5th byte since we overwrote two instructions (2+3=5 bytes)
pullpc
```
- **Example (Core System Hook):**
```asm
; In Core/sprite_engine_hooks.asm (or similar)
org $348100
CustomSprite_DeathHandler:
{
; Preserve original death logic
LDA.w SprHealth, X
BNE .not_dead
; Original vanilla death code here
JSL Sprite_SpawnDeathAnimation
.not_dead
; Add custom death effects for Oracle sprites
LDA.w SprType, X
CMP.b #CustomSpriteID : BNE .skip_custom
JSR CustomSprite_SpecialDeath
.skip_custom
RTL
}
; Hook in same file
pushpc
org $068450
JSL CustomSprite_DeathHandler
pullpc
```
## 4. Build Process and ROM Management
- **Clean ROM**: The clean, unmodified "The Legend of Zelda: A Link to the Past" ROM should be placed at `Roms/oos169.sfc`. This path is included in `.gitignore`, so the ROM file will not be committed to the repository.
- **Build Script**: A `build.sh` script is provided to automate the build process. For detailed usage, see `Docs/General/AsarUsage.md`.
- **Workflow**: The build script creates a fresh copy of the clean ROM and applies the `Oracle_main.asm` patch to it using `asar`.
- **Important**: Never apply patches directly to `Roms/oos169.sfc`. Always use the build script to create a new, patched ROM. This ensures the clean ROM remains untouched for future builds.
## 5. Debugging Tips for BRKs and Crashes
When encountering unexpected crashes (often indicated by a `BRK` instruction in emulators), especially after modifying code, consider the following:
**For comprehensive debugging guidance with step-by-step procedures, see `Docs/General/Troubleshooting.md`.**
### 5.1. Most Common Causes
- **Processor Status Register (P) Mismatch:** This is a very common cause. If a routine expects 8-bit accumulator/index registers (M=1, X=1) but is called when they are 16-bit (M=0, X=0), or vice-versa, memory accesses and arithmetic operations will be incorrect, leading to crashes.
**Example:**
```asm
; BAD: Size mismatch
REP #$20 ; A = 16-bit
JSL Function ; Function expects 8-bit!
; Inside Function:
SEP #$20 ; Sets 8-bit mode
LDA.b #$FF
STA.w $1234 ; Only stores $FF, not $00FF!
RTL ; ← Doesn't restore caller's 16-bit mode
; GOOD: Preserve state
Function:
PHP ; Save caller's state
SEP #$20 ; Set to 8-bit
LDA.b #$FF
STA.w $1234
PLP ; Restore caller's state
RTL
```
- **Stack Corruption:** JSL/JSR push the return address onto the stack. If a called routine pushes too much data onto the stack without popping it, or if the stack pointer (`S`) is corrupted, the return address can be overwritten, leading to a crash when `RTL`/`RTS` is executed.
- **`JSR`/`RTS` vs `JSL`/`RTL` Mismatch:** This is a critical and common error.
- `JSR` (Jump to Subroutine) pushes a 2-byte return address. It **must** be paired with `RTS` (Return from Subroutine), which pulls 2 bytes.
- `JSL` (Jump to Subroutine Long) pushes a 3-byte return address (including the bank). It **must** be paired with `RTL` (Return from Subroutine Long), which pulls 3 bytes.
**Example:**
```asm
; BAD: Mismatched call/return
MainFunction:
JSL SubFunction ; Pushes 3 bytes ($02 $C4 $09)
SubFunction:
; ... code ...
RTS ; ← ERROR: Only pops 2 bytes! Stack corrupted!
; GOOD: Matched call/return
MainFunction:
JSL SubFunction ; Pushes 3 bytes
SubFunction:
; ... code ...
RTL ; ← Correct: Pops 3 bytes
```
### 5.2. Debugging Tools
- **Mesen-S (Recommended):** The most powerful SNES debugger:
- Set breakpoints with conditions: `A == #$42`
- Memory watchpoints: `[W]$7E0730` (break on write)
- Stack viewer to trace call history
- Event viewer for NMI/IRQ timing
- Break on BRK automatically
**Quick Mesen-S Workflow:**
1. Enable "Break on BRK" in Debugger settings
2. When crash occurs, check Stack viewer
3. Read return addresses to trace call history
4. Set breakpoint before suspected crash location
5. Step through code examining registers
- **Breadcrumb Tracking:**
```asm
; Add markers to narrow down crash location
LDA.b #$01 : STA.l $7F5000 ; Breadcrumb 1
JSL SuspiciousFunction
LDA.b #$02 : STA.l $7F5000 ; Breadcrumb 2
JSL AnotherFunction
LDA.b #$03 : STA.l $7F5000 ; Breadcrumb 3
; After crash, check $7F5000 in memory viewer
; If value is $02, crash occurred in AnotherFunction
```
### 5.3. Common Error Patterns
**Pattern 1: Jumping to $000000 (BRK)**
- Cause: Corrupted jump address or return address
- Debug: Check stack contents, verify JSL/JSR is called before RTL/RTS
**Pattern 2: Infinite Loop / Freeze**
- Cause: Forgot to increment module/submodule, infinite recursion
- Debug: Check that `$10` (module) or `$11` (submodule) is incremented
**Pattern 3: Wrong Graphics / Corrupted Screen**
- Cause: DMA during active display, wrong VRAM address
- Debug: Ensure graphics updates only during NMI or Force Blank
### 5.4. Cross-Reference Documentation
For specific debugging scenarios:
- **BRK Crashes:** `Docs/General/Troubleshooting.md` Section 2
- **Stack Corruption:** `Docs/General/Troubleshooting.md` Section 3
- **Processor State Issues:** `Docs/General/Troubleshooting.md` Section 4
- **Namespace Problems:** `Docs/General/Troubleshooting.md` Section 5
- **Memory Conflicts:** `Docs/General/Troubleshooting.md` Section 6
- **Graphics Issues:** `Docs/General/Troubleshooting.md` Section 7
- **ZScream-Specific:** `Docs/General/Troubleshooting.md` Section 8
### 5.5. Recent Debugging Insights
During recent development and bug-fixing tasks, several critical patterns and debugging insights have emerged:
- **Processor Status Mismatch (M/X flags) and BRK (`$00` opcode):**
- A common cause of crashes is calling a routine expecting a different processor mode (e.g., 16-bit Accumulator) than the current CPU state (e.g., 8-bit Accumulator).
- Specifically, if an `AND.w #$00FF` instruction is encountered while the A-register is in 8-bit mode (`SEP #$20` active), the assembler may generate `29 FF 00`. The CPU will execute `29 FF` (AND immediate byte), and then interpret the trailing `00` as a `BRK` instruction, leading to a crash.
- **Resolution:** Always explicitly set the processor state (`REP #$30` for 16-bit, `SEP #$30` for 8-bit) at the entry of routines that depend on a specific mode, and consider `PHP`/`PLP` for state preservation if the routine needs to temporarily change modes or be called from various contexts.
- **Input Polling Registers for Continuous Actions:**
- For features requiring continuous input (e.g., holding a button to navigate in a menu or turn pages), use the joypad register that tracks **all pressed buttons** (`$F2` / `JOY1B_ALL`).
- Avoid using registers that only signal **new button presses** (`$F6` / `JOY1B_NEW`), as these will only trigger an action for a single frame, making continuous interaction impossible.
- **Resolution:** Pair `$F2` checks with a delay timer (`$0207` in our context) to prevent rapid-fire actions.
- **VRAM Update Flags (`$0116`, `$15`, `$17`) for Menu Graphics:**
- The variable `$0116` acts as a crucial trigger for the vanilla NMI handler (`NMI_DoUpdates`) to perform VRAM updates. **Bit 0 of `$0116` must be set (`$01`, or part of `$21`, `$23`, `$25`, etc.)** for standard tilemap and OAM buffer uploads to occur. Values like `$22` (where bit 0 is clear) may be ignored by the vanilla NMI handler for general VRAM updates.
- The `$15` flag (often referred to as the Palette/Refresh flag) should often be set alongside `$17` (NMI module selection) to ensure consistent and complete VRAM refreshes, especially for full-screen updates.
- **Resolution:** When a menu state needs to update its tilemap or OAM visually, ensure `$0116` has bit 0 set, and consider setting `$15` for comprehensive refreshes.
- **Data Table Mismatches (Logical vs. Visual Indexing):**
- In UI-heavy features (like inventory or submenus), a misalignment between a table defining the *logical order* of items (e.g., `Menu_AddressIndex`) and a table defining their *visual positions* (e.g., `Menu_ItemCursorPositions`) can lead to subtle bugs.
- **Symptom:** A cursor might appear in the wrong place, or attempting to clear a cursor from one item might inadvertently clear another, resulting in visual artifacts.
- **Resolution:** Rigorously align item indices across all related data tables, ensuring a 1:1 mapping between logical item order and visual screen coordinates.
- **Custom NMI Handlers and Vanilla System Integration:**
- Be aware that extensive custom systems (like ZScream's overworld graphics streaming) may replace or heavily modify vanilla NMI routines. These custom handlers might be designed to process their *own* DMA requests and could potentially ignore standard vanilla flags (`$0116`, `$15`) or input registers.
- **Symptom:** Standard game elements (like menus) may fail to update graphics or respond to input if the custom NMI handler does not explicitly integrate or defer to the vanilla update logic.
- **Resolution:** If a custom NMI handler is in place, it must either pass control to the vanilla NMI handler when appropriate (e.g., when the game is in a menu state), or manually replicate the necessary vanilla update logic (e.g., checking `$0116` and initiating DMA for menu buffers).
## 6. Verification Policy
- **Bugs and Features:** Never mark a bug fix or feature implementation as `DONE` until it has been thoroughly tested and verified in an emulator. This ensures stability and prevents regressions.
## 7. Memory and Symbol Analysis
This section details the layout and purpose of critical memory regions (WRAM and SRAM) and the symbol definition files that give them context.
**For comprehensive memory documentation, see:**
- `Docs/Core/MemoryMap.md` - Complete WRAM/SRAM map with verified custom variables
- `Docs/Core/Ram.md` - High-level overview of memory usage
- `Docs/General/Troubleshooting.md` Section 6 - Memory conflict resolution
### 7.1. WRAM (Work RAM) Analysis
Work RAM (WRAM) holds the active, volatile state of the entire game. The following are some of the most critical variables for understanding real-time game logic.
* **Direct Page & Scrap (`$7E0000` - `$7E000F`):** A highly volatile scratchpad for temporary, single-frame calculations.
* **Main Game State (`$7E0010` - `$7E001F`):**
* `MODE` (`$7E0010`): The primary game state variable (Overworld, Underworld, Menu, etc.). This dictates which main module is executed each frame.
* `INDOORS` (`$7E001B`): A flag (`0x01` for indoors, `0x00` for outdoors) controlling environmental factors.
* **Link's State (`$7E0020`+):** A large block containing the player's immediate state.
* `POSX`/`POSY`/`POSZ`: Link's 16-bit absolute coordinates.
* `LINKDO` (`$7E005D`): Link's personal state machine variable (walking, swimming, lifting, etc.), used by the player engine in Bank $07.
* `IFRAMES` (`$7E031F`): Invincibility frame timer after taking damage.
* **Area & Room State (`$7E008A` - `$7E00AF`):**
* `OWSCR` (`$7E008A`): The current Overworld screen ID.
* `ROOM` (`$7E00A0`): The current Underworld room ID.
* **Sprite and Ancilla Data (`$7E0D00+`):** `Core/symbols.asm` maps the data structures for all sprites and ancillae (projectiles, effects). Key variables include `SprState` (state machine), `SprType` (ID), `SprHealth`, and coordinates. This is fundamental to all NPC and enemy logic.
* **Oracle of Secrets Custom WRAM (`$7E0730+`):** A custom region for new features. Notable variables include `GoldstarOrHookshot` and `FishingOrPortalRod`, used to manage the state of new custom items.
### 7.2. SRAM (Save RAM) Analysis
SRAM stores the player's save file, including long-term progression and inventory. `Core/sram.asm` reveals significant customization for Oracle of Secrets.
#### Vanilla ALTTP Save Data:
* **Inventory:** `Bow` (`$7EF340`), `Bombs` (`$7EF343`), `Sword` (`$7EF359`), `Shield` (`$7EF35A`).
* **Player Status:** `Rupees` (`$7EF360`), `MAXHP` (`$7EF36C`), `CURHP` (`$7EF36D`).
* **Progression:** `Pendants` (`$7EF374`), `Crystals` (`$7EF37A`), `GAMESTATE` (`$7EF3C5`).
#### Oracle of Secrets (OOS) Custom SRAM Data:
This highlights the major new features of the hack.
* **New Items & Masks:** `ZoraMask` (`$7EF347`), `BunnyHood` (`$7EF348`), `DekuMask` (`$7EF349`), `RocsFeather` (`$7EF34D`), etc. These introduce major new player abilities.
* **New Progression System:**
* `OOSPROG` (`$7EF3D6`): A primary bitfield for major quest milestones unique to OOS.
* `Dreams` (`$7EF410`): A new collectible concept.
* **New Collectibles & Side-Quests:** A block from `$7EF38B` holds new items like `Bananas`, `Seashells`, and `Honeycomb`. `MagicBeanProg` (`$7EF39B`) tracks a new multi-day side-quest.
### 7.3. Symbols and Functions (`Core/symbols.asm`)
This file acts as a central header, defining constants and labels for memory addresses and functions to make the assembly code readable and maintainable.
* **Function Pointers:** It provides labels for critical functions across different ROM banks (e.g., `Sprite_CheckDamageToPlayer`, `EnableForceBlank`), allowing for modular code.
* **Memory Maps:** It contains the definitive memory maps for WRAM structures, most notably for sprites and ancillae.
* **Readability:** Its primary purpose is to replace "magic numbers" (raw addresses) with human-readable labels, which is essential for a project of this scale.
## 8. Documentation Reference
This section provides a comprehensive overview of all available documentation files, organized by category. These documents serve as key references for understanding the project's architecture, gameplay systems, and development practices.
### 8.1. Core System Documentation
* **`Docs/Core/MemoryMap.md`:** Complete WRAM and SRAM memory map with verified custom variables. Documents all custom memory regions from `$7E0730+` (WRAM) and OOS-specific SRAM including `$7EF3D6` (OOSPROG), `$7EF38A+` (collectibles block), and `$7EF410` (Dreams). Essential reference for any code that accesses RAM.
* **`Docs/Core/Ram.md`:** High-level overview of WRAM and SRAM usage patterns with descriptions of custom variable purposes.
* **`Docs/Core/Link.md`:** Documentation of Link's state machine, player mechanics, and control handlers.
* **`Docs/Core/SystemInteractions.md`:** Documentation of core game systems and their interactions.
### 8.2. Development Guidelines
* **`Docs/General/DevelopmentGuidelines.md`:** Comprehensive development guidelines covering architecture patterns, memory management, assembly best practices, coding standards, and debugging strategies. Expands on concepts in this GEMINI.md file with detailed examples and rationale. **Required reading for all contributors.**
* **`Docs/General/Troubleshooting.md`:** Comprehensive troubleshooting guide with step-by-step debugging procedures. Covers:
- BRK crashes and stack traces
- Stack corruption patterns (JSL/JSR vs RTL/RTS mismatches)
- Processor status register issues (M/X flag problems)
- Cross-namespace calling problems
- Memory conflicts and bank collisions
- Graphics/DMA timing issues
- ZScream-specific problems
- Debugging with Mesen-S and BSNES-Plus
* **`Docs/General/AsarUsage.md`:** Best practices for using the Asar assembler and the build script system. Covers `org` vs `pushpc`/`pullpc`, ROM management, and build workflow.
### 8.3. Creation Guides
* **`Docs/Guides/SpriteCreationGuide.md`:** Comprehensive 878-line tutorial for creating custom sprites from scratch. Covers:
- File setup and bank organization
- Sprite properties (23 configurable flags with memory addresses)
- Initialization with 60+ WRAM variables documented
- Main logic with 30+ macros and 20+ core functions
- OAM drawing system with tile format specifications
- Testing procedures and debugging strategies
- Common issues and solutions
- 10 advanced patterns:
1. State Machines (Booki example)
2. Multi-part Sprites (Kydreeok boss)
3. Guard/Defense Mechanics (Darknut)
4. Shared Logic (Goriya variations)
5. Complex Boss Mechanics
6. NPC Interactions (Followers)
7. Interactive Objects (Minecart)
8. Environmental Awareness
9. Advanced AI Patterns
10. Cross-System Integration
- Real examples from Booki, Darknut, Kydreeok, Goriya, Followers, and Minecart sprites
* **`Docs/Guides/QuestFlow.md`:** Detailed guide to main story and side-quest progression, including trigger conditions, progression flags, and quest dependencies.
### 8.4. World System Documentation
* **`Docs/World/Overworld/ZSCustomOverworld.md`:** Basic guide to the ZScream custom overworld system and its data tables.
* **`Docs/World/Overworld/ZSCustomOverworldAdvanced.md`:** Advanced technical documentation for ZScream integration. **Critical for modifying overworld behavior.** Covers:
- Internal hook architecture (38+ vanilla routine replacements)
- Hook execution order during screen transitions
- Memory management and state tracking (Bank $28 data pool)
- Graphics loading pipeline with frame-by-frame analysis
- Sprite loading system deep dive
- Cross-namespace integration patterns (Oracle ↔ ZScream)
- Performance considerations and optimization strategies
- Adding custom features to the overworld system
- Debugging ZScream-specific issues
* **`Docs/World/Overworld/TimeSystem.md`:** Documentation of the day/night cycle system implementation.
* **`Docs/World/Dungeons/Dungeons.md`:** Breakdown of dungeon systems, layouts, enemy placements, and puzzle mechanics.
### 8.5. Feature System Documentation
* **`Docs/Features/Menu/Menu.md`:** Analysis of the custom menu and HUD systems, including two-page menu layout and item drawing routines.
* **`Docs/Features/Items/Items.md`:** Guide to custom and modified items, including implementation details for Goldstar, Portal Rod, Ocarina, and others.
* **`Docs/Features/Music/Music.md`:** Guide to custom music tracks, sound effects, and adding new audio.
* **`Docs/Features/Masks/Masks.md`:** Comprehensive overview of the Mask System, including transformation mechanics and each mask's abilities.
### 8.6. Sprite Documentation
Each sprite category has both an overview document and individual files for specific sprites:
* **`Docs/Sprites/NPCs.md`:** Overview of NPC sprite system with links to individual NPC documentation in `Docs/Sprites/NPCs/` (BeanVendor, DekuScrub, EonOwl, Farore, Followers, Impa, Korok, Maple, MaskSalesman, Tingle, Vasu, ZoraPrincess, etc.)
* **`Docs/Sprites/Bosses.md`:** Overview of boss sprite system with links to individual boss documentation in `Docs/Sprites/Bosses/` (DarkLink, Kydreeok, Manhandla, etc.)
* **`Docs/Sprites/Enemies/`:** Individual documentation for enemy sprites (AntiKirby, Booki, BusinessScrub, Darknut, Goriya, Keese, Leever, Octorok, PolsVoice, Wolfos, etc.)
* **`Docs/Sprites/Objects.md`:** Overview of interactive object sprites with documentation in `Docs/Sprites/Objects/` (Collectible, DekuLeaf, IceBlock, Minecart, Pedestal, PortalSprite, etc.)
* **`Docs/Sprites/Overlords.md`:** Analysis of the Overlord sprite system used for environmental effects and multi-screen management.
## 9. Disassembly Analysis and Search Guide
This section provides a high-level analysis of key banks in the Link to the Past disassembly. Use this guide to quickly locate relevant code and understand the overall structure of the game.
### 9.1. Bank $00: Game Core & Main Loop
**File:** `ALTTP/bank_00.asm`
**Address Range:** `$008000` - `$00FFFF`
**Summary:** The heart of the game engine. Contains the main game loop, interrupt handlers, and the primary game state machine.
#### Key Structures & Routines:
* **`Reset:` (#_008000)**: Game entry point on boot.
* **`MainGameLoop:` (#_008034)**: Central loop, calls `Module_MainRouting`.
* **`Module_MainRouting:` (#_0080B5)**: Primary state machine dispatcher. Reads `MODE` (`$7E0010`) and uses `pool Module_MainRouting` to jump to the correct game module.
* **`Interrupt_NMI:` (#_0080C9)**: Runs every frame. Handles input (`NMI_ReadJoypads`), graphics DMA (`NMI_DoUpdates`), and sprite preparation (`NMI_PrepareSprites`).
#### Search Heuristics:
* **Game Module Logic (Overworld, Underworld, Menus):** Search `bank_00.asm` for the `pool Module_MainRouting` jump table. The labels (e.g., `Module09_Overworld`) are the entry points for each game state, determined by WRAM `$7E0010` (`MODE`).
* **Per-Frame Logic:** Search `bank_00.asm` for `Interrupt_NMI:`. Key routines called from here are `NMI_ReadJoypads` (input) and `NMI_DoUpdates` (graphics DMA).
* **Initialization Logic:** Start at the `Reset:` label in `bank_00.asm` and trace `JSR`/`JSL` calls to routines like `InitializeMemoryAndSRAM`.
### 9.2. Bank $01: Dungeon Engine
**File:** `ALTTP/bank_01.asm`
**Address Range:** `$018000` - `$01FFFF`
**Summary:** Responsible for loading, drawing, and managing all aspects of interior rooms (dungeons, houses, caves).
#### Key Structures & Routines:
* **`Underworld_LoadRoom:` (#_01873A)**: Main entry point for loading a dungeon room.
* **`DrawObjects` Tables:** A set of tables at the top of the bank defining object graphics and drawing routines.
* **`RoomDraw_DrawAllObjects:` (#_0188E4)**: Iterates through a room's object list.
* **`RoomDraw_RoomObject:` (#_01893C)**: Main dispatcher for drawing a single object based on its ID.
#### Search Heuristics:
* **Room Construction Logic:** In `bank_01.asm`, start at `Underworld_LoadRoom` and trace the call sequence: `Underworld_LoadHeader` -> `RoomDraw_DrawFloors` -> `RoomDraw_DrawAllObjects`.
* **Specific Dungeon Object Code:** To find an object's drawing code, search the `.type1_subtype_..._routine` tables at the start of `bank_01.asm` for the object's ID. The corresponding label is the drawing routine. To find its tile data, search the `.type1_subtype_..._data_offset` tables.
### 9.3. Bank $02: Overworld & Transitions
**File:** `ALTTP/bank_02.asm`
**Address Range:** `$028000` - `$02FFFF`
**Summary:** Manages loading the overworld, transitioning between areas, and handling special game sequences.
#### Key Structures & Routines:
* **`Module06_UnderworldLoad:` (#_02821E)**: Primary module for transitioning into and loading an underworld room.
* **`Module08_OverworldLoad:` (#_0283BF)**: Primary module for loading the overworld.
* **`Module07_Underworld:` (#_0287A2)**: Main logic loop for when the player is in the underworld. Dispatches to submodules based on WRAM `$11`.
#### Search Heuristics:
* **Overworld Loading:** Start at `Module08_OverworldLoad` in `bank_02.asm`. Logic checks WRAM `$8A` (overworld area number) to determine behavior.
* **Underworld Gameplay:** Start at `Module07_Underworld` in `bank_02.asm`. Examine the `.submodules` jump table to see the different states, determined by WRAM `$11`.
* **Transition Logic:** Search for code that sets the game `MODE` (`$10`) to `$08` (Overworld Load) or `$06` (Underworld Load) to find the start of a transition.
### 9.4. Bank $03: Tile32 Overworld Layout Data
### 9.5. Bank $04: Tile32 Overworld Layout Data, Dungeon Room Headers
### 9.6. Bank $07: Core Player (Link) Engine
**File:** `ALTTP/bank_07.asm`
**Address Range:** `$078000` - `$07FFFF`
**Summary:** Contains Link's core state machine, governing movement, physics, item usage, and interactions.
#### Key Structures & Routines:
* **`Link_Main:` (#_078000)**: Top-level entry point for all player logic.
* **`Link_ControlHandler:` (#_07807F)**: The heart of the player engine. A state machine dispatcher that reads `LINKDO` (`$7E005D`) and jumps via the `pool Link_ControlHandler` table.
* **`LinkState_Default` (#_078109):** The most common state, handling walking and dispatching to action sub-handlers like `Link_HandleYItem`.
#### Search Heuristics:
* **Player Action Logic (walking, swimming):** In `bank_07.asm`, search for `pool Link_ControlHandler`. The state ID is from WRAM `$7E005D` (`LINKDO`). Find the label for the desired state (e.g., `LinkState_Default`) to locate its main routine.
* **Player Physics/Collision:** Within a player state routine, search for calls to `JSL Link_HandleVelocity` (physics) and `JSR Link_HandleCardinalCollision` (collision).
* **Y-Button Item Logic:** In `LinkState_Default`, search for the call to `JSR Link_HandleYItem`.
* **Player Damage Logic:** Search for writes to WRAM `$7E0373` (`HURTME`).
### 9.7. Bank $05: Specialized Sprite & Object Engine
**File:** `ALTTP/bank_05.asm`
**Address Range:** `$058000` - `$05FFFF`
**Summary:** Code for unique, complex, and scripted sprites that do not fit the standard enemy AI model (e.g., cutscene sprites, minigame hosts, complex traps).
#### Search Heuristics:
* **Unique/Non-Enemy Sprites:** When looking for a unique sprite (minigame, cutscene object, complex trap), check `bank_05.asm` first.
* **Finding Sprite Logic:** Search for the sprite's name (e.g., "MasterSword") or its hexadecimal ID (e.g., `Sprite_62`) to find its main routine.
### 9.8. Bank $06: Main Sprite Engine & Helpers
**File:** `ALTTP/bank_06.asm`
**Address Range:** `$068000` - `$06FFFF`
**Summary:** Contains the main sprite processing engine and a vast library of shared helper subroutines used by sprites game-wide.
#### Key Structures & Routines:
* **`Sprite_Main:` (#_068328)**: The master sprite loop that iterates through all 16 sprite slots.
* **`Sprite_ExecuteSingle:` (#_0684E2)**: The state machine dispatcher for an individual sprite, reading `SprState` (`$7E0DD0,X`).
* **`SpriteModule_Initialize:` (#_06864D)**: Master initialization routine. Contains a massive jump table pointing to a specific `SpritePrep_...` routine for nearly every sprite type.
* **`Sprite_SpawnSecret` (`#_068264`):** Determines the "secret" item that appears under a liftable bush or rock.
#### Search Heuristics:
* **Sprite Initialization (HP, damage, etc.):** In `bank_06.asm`, go to `SpriteModule_Initialize`. Find the sprite's ID in the large jump table to get the label for its `SpritePrep_...` routine.
* **Sprite Core AI:** In `bank_06.asm`, go to `SpriteModule_Active`. Find the sprite's ID in its jump table to find the entry point to its main AI logic (which may be in another bank).
* **Bush/Rock Item Drops:** Locate the `Sprite_SpawnSecret` routine and examine the `.ID` table at `#_0681F4` to see the prize mappings.
### 9.9. Bank $08: Ancilla Engine
**File:** `ALTTP/bank_08.asm`
**Address Range:** `$088000` - `$08FFFF`
**Summary:** The engine for "Ancillae" (projectiles, particle effects, etc.). Contains the execution logic for entities like arrows, bombs, and magic spells.
#### Search Heuristics:
* **Projectile/Effect Logic:** In `bank_08.asm`, find the main jump table in `Ancilla_ExecuteOne` (at `#_08837F`). Look up the ancilla's ID in this table to find the label for its logic routine (e.g., `Ancilla07_Bomb`).
* **Projectile Properties (speed, graphics):** Go to the ancilla's main logic routine (e.g., `Ancilla09_Arrow`) and look for writes to its WRAM properties (e.g., `$0C2C` for X-speed).
### 9.10. Bank $09: Ancilla Spawning & Item Logic
**File:** `ALTTP/bank_09.asm`
**Address Range:** `$098000` - `$09FFFF`
**Summary:** Contains the ancilla *creation* engine (a library of `AncillaAdd_...` functions) and the critical logic for giving items to the player.
#### Search Heuristics:
* **Projectile/Effect Creation:** To find where a projectile is created, search the codebase for `JSL` calls to its corresponding `AncillaAdd_...` function in this bank (e.g., `JSL AncillaAdd_Bomb`).
* **Item "Get" Properties:** To change the properties of an item the player receives, find the `AncillaAdd_ItemReceipt` routine and examine the large data tables starting at `#_098404`.
### 9.11. Bank $0A: World Map & Flute Menu Engine
**File:** `ALTTP/bank_0A.asm`
**Address Range:** `$0A8000` - `$0AFFFF`
**Summary:** Controls all full-screen map interfaces (pause menu map, flute destination map).
#### Search Heuristics:
* **Flute Warp Destinations:** In `bank_0A.asm`, find the `FluteMenu_LoadTransport` routine. The table within it maps the 8 flute spots to screen indexes.
* **Map Icon Locations:** Search for the `WorldMapIcon_posx_...` and `WorldMapIcon_posy_...` tables to adjust icon coordinates.
### 9.12. Bank $0B: Overworld Environment & State Helpers
**File:** `ALTTP/bank_0B.asm`
**Address Range:** `$0B8000` - `$0BFFFF`
**Summary:** Miscellaneous helper functions related to the overworld environment and player state.
#### Search Heuristics:
* **Overworld Area Palette:** To change the background color of an overworld area, modify the color values loaded in `Overworld_SetFixedColAndScroll`. The logic checks WRAM `$8A` to decide which color to use.
* **Wall Master Capture:** To change what happens when captured, find the `WallMaster_SendPlayerToLastEntrance` routine.
### 9.13. Bank $0C: Intro & Credits Sequence
**File:** `ALTTP/bank_0C.asm`
**Address Range:** `$0C8000` - `$0CFFFF`
**Summary:** Handles the game's intro and end-game credits sequences.
#### Search Heuristics:
* **Intro/Credits Scene Logic:** Start at the `Module00_Intro` or `Module1A_Credits` jump tables. The sub-mode in WRAM `$11` determines which part of the sequence is running. Follow the jump table to the routine for the scene you want to change.
### 9.14. Bank $0D: Link Animation & OAM Data
**File:** `ALTTP/bank_0D.asm`
**Address Range:** `$0D8000` - `$0DFFFF`
**Summary:** A massive graphical database defining every frame of Link's animation. It is not executable code.
#### Search Heuristics:
* **Link's Animation Sequence:** To modify an animation, find the action in `LinkOAM_AnimationSteps`. The values are indices into the `LinkOAM_PoseData` table, which defines the body parts for each frame.
* **Link's Item Positioning:** To change how Link holds an item, find the animation frame index in `LinkOAM_AnimationSteps` and use it to find the corresponding entries in the `LinkOAM_SwordOffsetX/Y` or `LinkOAM_ShieldOffsetX/Y` tables.
### 9.15. Bank $0E: Tile Properties & Credits Engine
**File:** `ALTTP/bank_0E.asm`
**Address Range:** `$0E8000` - `$0EFFFF`
**Summary:** Contains fundamental game assets (font, tile properties) and the credits engine.
#### Search Heuristics:
* **Tile Behavior (e.g., making a wall walkable):** Identify the tile's graphical ID and find its entry in the `OverworldTileTypes` or `UnderworldTileTypes` tables. Change its byte value to match a tile with the desired properties.
* **Custom Tile Physics (e.g., ice):** Search for the `Underworld_LoadCustomTileTypes` function to see how alternate tile property sets are loaded for specific dungeons.
### 9.16. Bank $0F: Miscellaneous Game Logic & Helpers
**File:** `ALTTP/bank_0F.asm`
**Address Range:** `$0F8000` - `$0FFFFF`
**Summary:** A collection of important miscellaneous subroutines, including player death and dialogue box initiation.
#### Search Heuristics:
* **Player Death Sequence:** The entry points are `PrepareToDie` and `Link_SpinAndDie`.
* **Dialogue Box Trigger:** Search for `JSL Interface_PrepAndDisplayMessage`. The code immediately preceding it sets up the message ID to be displayed.
### 9.17. Bank $10-$18: Graphics Sheets for Link, Dungeon, Overworld, Sprites
### 9.18. Bank $19: Sound Data
### 9.19. Bank $1A: Miscellaneous Sprites & Cutscenes
**File:** `ALTTP/bank_1A.asm`
**Address Range:** `$1A8000` - `$1AFFFF`
**Summary:** Logic for a variety of unique sprites, NPCs, and cutscene events that are too specific for the main sprite engine.
#### Search Heuristics:
* **Pyramid of Power Opening:** Search for `BatCrash` or `CreatePyramidHole`.
* **Waterfall of Wishing Splash:** Search for `SpawnHammerWaterSplash`.
* **Secret Item Substitution:** To understand how items under rocks are sometimes replaced by enemies, analyze `Overworld_SubstituteAlternateSecret`.
### 9.20. Bank $1B: Overworld Interaction & Palettes
**File:** `ALTTP/bank_1B.asm`
**Address Range:** `$1B8000` - `$1BFFFF`
**Summary:** The heart of the overworld interaction system. Manages all entrances, pits, and item-based tile interactions (digging, bombing). Also contains a very large store of palette data.
#### Search Heuristics:
* **Overworld Entrances:** To change where a door leads, find its entry in the `Overworld_Entrance...` tables at the top of the bank.
* **Hidden Item Locations:** To change the item under a specific bush, find the correct `OverworldData_HiddenItems_Screen_XX` table and modify the entry for that bush's coordinates.
* **Sprite/Armor Colors:** To change a color, find the correct palette in the `PaletteData` section and modify the desired color values.
### 9.21. Bank $1C: Text Data
### 9.22. Bank $1D & $1E: Advanced Sprite & Boss AI
**Files:** `ALTTP/bank_1D.asm`, `ALTTP/bank_1E.asm`
**Summary:** These banks contain the specific, complex AI for most of the game's major bosses and late-game enemies (Ganon, Moldorm, Trinexx, Helmasaur King, Kholdstare, Agahnim, etc.).
#### Search Heuristics:
* **Boss/Enemy AI:** To modify a specific boss or advanced enemy, search for its `Sprite_...` routine in these two banks (e.g., `Sprite_92_HelmasaurKing` in bank $1E).
* **Sprite Dispatch Table:** The jump table at `SpriteModule_Active_Bank1E` in `bank_1E.asm` provides a comprehensive list of all sprites managed by that bank and is a good starting point for investigation.
### 9.23. Bank $1F: Dungeon Room Data
## 10. ZScream Expanded ROM Map
> **Last Updated:** 02/28/2025
> **Note:** All addresses are in PC format unless otherwise stated.
> **Note:** Some features are supported in yaze (yet another zelda3 editor) but not all.
ZScream reserves:
- All space up to **1.5MB** (`0x150000`)
- An additional **3 banks** at the end of the 2.0MB range (`0x1E8000` to `0x1FFFFF`)
### Bank Allocation Overview
| Address Range | Size | Purpose/Contents |
|---------------------- |---------- |----------------------------------------------------|
| `0x100000 - 0x107FFF` | 1 Bank | *(Unused?)* |
| `0x108000 - 0x10FFFF` | 1 Bank | Title screen data, Dungeon map data |
| `0x110000 - 0x117FFF` | 1 Bank | Default room header location |
| | | (Old dungeon object data expansion, now moved) |
| `0x118000 - 0x11FFFF` | 1 Bank | (Old dungeon object data expansion, now moved) |
| `0x120000 - 0x127FFF` | 1 Bank | Expanded overlay data |
| `0x128000 - 0x12FFFF` | 1 Bank | Custom collision data |
| `0x130000 - 0x137FFF` | 1 Bank | Overworld map data overflow |
| `0x138000 - 0x13FFFF` | 1 Bank | Expanded dungeon object data |
| `0x140000 - 0x147FFF` | 1 Bank | Custom overworld data |
| `0x148000 - 0x14FFFF` | 1 Bank | Expanded dungeon object data |
| `0x1E0000 - 0x1E7FFF` | 1 Bank | Custom ASM patches |
| `0x1E8000 - 0x1EFFFF` | 1 Bank | Expanded Tile16 space |
| `0x1F0000 - 0x1FFFFF` | 2 Banks | Expanded Tile32 space |
## 11. Oracle of Secrets Specific Guidelines for Gemini
To ensure accurate and consistent modifications within the Oracle of Secrets project, adhere to the following guidelines regarding memory management and code placement:
- **Understand `incsrc` Order:** The order of `incsrc` directives in `Oracle_main.asm` is paramount. It dictates the final ROM layout, especially for code and data placed using `org`. Always consult `Oracle_main.asm` and `Docs/Core/MemoryMap.md` to understand the current memory allocation before introducing new `org` directives.
- **`org` for New Features:** When implementing new features that require significant code or data, use `org $XXXXXX` to place them in an appropriate free bank. Refer to the detailed memory map in `Docs/Core/MemoryMap.md` and the `Oracle_main.asm` comment for available and designated banks. If a new bank is needed, ensure it does not conflict with existing allocations or ZScream reserved space.
- **`pushpc`/`pullpc` for Patches:** For small, targeted modifications to vanilla code or data (e.g., changing a few bytes, hooking a jump), use `pushpc`/`pullpc`. These directives are ideal for non-intrusive patches that don't require a dedicated bank. Examine `Core/patches.asm` and `Util/item_cheat.asm` for examples of this usage.
- **Consult Memory Map:** Before any code modification involving `org` or `pushpc`/`pullpc`, always cross-reference with `Docs/Core/MemoryMap.md` and the `Oracle_main.asm` comment to prevent memory conflicts and ensure proper placement.
- **Prioritize Existing Conventions:** Mimic the existing style and structure of the codebase. If a new feature is similar to an existing one, follow its implementation pattern, including how it manages memory.
- **Avoid Arbitrary `org`:** Never use `org` without a clear understanding of the target address and its implications for the overall ROM layout. Unplanned `org` directives can lead to crashes or unexpected behavior.

51
Docs/General/AsarUsage.md Normal file
View File

@@ -0,0 +1,51 @@
# Asar Usage and ROM Management
This document outlines the best practices for using Asar and managing ROM files within the Oracle of Secrets project.
## Safety First: Preserve the Clean ROM
The most important rule is to **never modify the clean ROM directly**. The clean ROM for this project is expected to be `Roms/oos169.sfc`. All patches must be applied to a *copy* of this file. This ensures that you always have a pristine base to work from and prevents irreversible changes to the original game file.
The `Roms/` directory is ignored by git, so you don't have to worry about accidentally committing large ROM files.
## The Build Script
A `build.sh` script is provided to automate the build process and enforce safe ROM management.
### Usage
To build the ROM, run the script from the project root. You can optionally provide a version number.
**Build with a version number:**
```sh
./build.sh 1.0
```
This will create a patched ROM named `Roms/oos-v1.0.sfc`.
**Build without a version number:**
```sh
./build.sh
```
This will create a patched ROM named `Roms/oos-patched.sfc`.
### What it Does
1. **Copies the ROM**: It creates a copy of `Roms/oos169.sfc`.
2. **Applies the Patch**: It runs `asar` to apply the main patch file (`Oracle_main.asm`) to the newly created ROM copy.
3. **Output**: The final, patched ROM is placed in the `Roms/` directory.
## Manual Build Process (Not Recommended)
If you need to run the build process manually, follow these steps:
1. **Create a copy of the clean ROM**:
```sh
cp Roms/oos169.sfc Roms/my_patched_rom.sfc
```
2. **Run Asar**:
```sh
asar Oracle_main.asm Roms/my_patched_rom.sfc
```
Using the `build.sh` script is highly recommended to avoid mistakes.

View File

@@ -0,0 +1,332 @@
# Oracle of Secrets Development Guidelines
## 1. Introduction
This document outlines the established coding conventions, architectural patterns, and best practices for the Oracle of Secrets project. Adhering to these guidelines is crucial for maintaining code quality, consistency, and long-term maintainability.
The Oracle of Secrets is a large-scale ROM hack of "The Legend of Zelda: A Link to the Past" for the Super Nintendo. It is built using the `asar` assembler and features a highly modular and data-driven architecture. The project's core philosophy is to replace hardcoded vanilla logic with flexible, data-driven systems, allowing for easier expansion and modification.
## 2. Core Architecture
### 2.1. Game State Management
The game's main loop and state management are handled in `bank_00.asm`. The `Module_MainRouting` routine acts as the primary state machine, using a jump table to execute the logic for the current game state (e.g., Overworld, Underworld, Menu).
### 2.2. Memory Management
The project makes extensive use of both WRAM and SRAM to store custom data and game state.
* **WRAM (Work RAM):** Located at `$7E0000`, WRAM holds the game's volatile state. A custom region starting at `$7E0730` is reserved for new features, including the Time System, Mask System, and custom item states.
* **SRAM (Save RAM):** Located at `$7EF000`, SRAM stores the player's save data. The save format has been significantly expanded to accommodate new items, progress flags (`OOSPROG`), and new item data.
### 2.3. Assembly Best Practices (`asar`)
To ensure modern and maintainable assembly code, the project adheres to the following `asar` best practices:
* **`org` for New Code and Data:** Use `org $XXXXXX` to place larger blocks of new code or data into designated free space banks. The `incsrc` order in `Oracle_main.asm` is critical when using `org`, as it directly determines the final ROM layout. Moving `org` blocks or changing the `incsrc` order can lead to memory conflicts or incorrect addressing.
* **`pushpc`/`pullpc` for Targeted Patches:** Use `pushpc`/`pullpc` for small, targeted modifications to existing vanilla code or data. This directive temporarily changes the program counter, allowing a small patch to be inserted at a specific address without affecting the surrounding `org` context. Files like `Core/patches.asm` and `Util/item_cheat.asm` extensively use `pushpc`/`pullpc` for this purpose.
* **Scoping:** Use labels followed by `{}` to define local scopes for new logic blocks. This is the established convention, and `subroutine`/`endsubroutine` are not used.
* **Data Structures:** Use `struct` for complex, related data (e.g., sprite state) and `table` for jump tables or data arrays. This improves readability and reduces errors from manual offset calculations.
* **Constants:** Use `!` or `define()` to create named constants for RAM/SRAM addresses, item IDs, sprite states, and other "magic numbers." This makes the code self-documenting and easier to maintain.
### 2.4. Namespace Architecture
Oracle of Secrets uses a mixed namespace architecture to organize code and manage symbol visibility:
* **`Oracle` Namespace:** Most custom code is placed within the `namespace Oracle { }` block. This includes Items, Menu, Masks, Time System, and most custom features.
* **ZScream (No Namespace):** The `ZSCustomOverworld` system operates outside any namespace, as it needs to hook directly into vanilla bank addresses.
* **Cross-Namespace Calling:** When Oracle code needs to call ZScream functions, or vice versa, proper exports must be defined:
```asm
// In ZScream file:
LoadOverworldSprites_Interupt:
{
; ... ZScream code ...
RTL
}
// Export to Oracle namespace:
namespace Oracle
{
Oracle_LoadOverworldSprites_Interupt = LoadOverworldSprites_Interupt
}
```
* **Bridge Functions:** When ZScream needs to call Oracle code, use a bridge function pattern:
```asm
// Oracle implementation:
namespace Oracle
{
CheckIfNight:
; Main implementation
RTL
}
// Bridge function (no namespace):
ZSO_CheckIfNight:
{
JSL Oracle_CheckIfNight ; Can call INTO Oracle
RTL
}
// Export bridge:
namespace Oracle
{
Oracle_ZSO_CheckIfNight = ZSO_CheckIfNight
}
```
**Important:** Always use the `Oracle_` prefix when calling exported functions from within the Oracle namespace. See `Docs/World/Overworld/ZSCustomOverworldAdvanced.md` Section 5 for detailed examples.
### 2.5. Processor State Management
The 65816 processor has critical flags (M and X) that control register sizes:
* **M Flag (bit 5):** Controls Accumulator size (0=16-bit, 1=8-bit)
* **X Flag (bit 4):** Controls Index register size (0=16-bit, 1=8-bit)
**Best Practices:**
1. **Initialize at function entry:**
```asm
MyFunction:
PHP ; Save caller's state
SEP #$30 ; Set to known 8-bit state
; ... your code ...
PLP ; Restore caller's state
RTL
```
2. **Be explicit about sizes:**
```asm
REP #$20 ; A = 16-bit
LDA.w #$1234 ; Load 16-bit value
SEP #$20 ; A = 8-bit
LDA.b #$12 ; Load 8-bit value only
```
3. **Document function requirements:**
```asm
; Function: CalculateOffset
; Inputs: A=16-bit (offset), X=8-bit (index)
; Outputs: A=16-bit (result)
; Status: Returns with P unchanged (uses PHP/PLP)
```
4. **Cross-namespace calls:** Be especially careful when calling between Oracle and ZScream code, as they may use different processor states.
See `Docs/General/Troubleshooting.md` Section 3 for common processor state issues and solutions.
## 3. Key Custom Systems
Oracle of Secrets introduces several major custom systems that form the foundation of the hack.
### 3.1. `ZSCustomOverworld`
`ZSCustomOverworld` is a data-driven system for managing the overworld. It is configured via a series of tables located at `org $288000` in `Overworld/ZSCustomOverworld.asm`. This system controls:
* **Palettes:** Day/night and seasonal palette transitions.
* **Graphics:** Custom graphics sets for different areas.
* **Overlays:** Data-driven overlays for weather effects and other visual enhancements.
* **Layouts:** Custom tile arrangements and area layouts.
### 3.2. Time System
The Time System, implemented in `Overworld/time_system.asm`, provides a full day/night cycle. It interacts closely with `ZSCustomOverworld` to manage palette changes and other time-of-day effects.
### 3.3. Mask System
The Mask System, located in the `Masks/` directory, allows Link to transform into different forms with unique abilities. The core transformation logic is handled by the `Link_TransformMask` routine. Each mask has its own file (e.g., `deku_mask.asm`, `zora_mask.asm`) that defines its specific behavior and abilities. The system uses custom WRAM to store the current mask and its state.
### 3.4. Custom Menu & HUD
The `Menu/` directory contains a completely new menu and HUD system. This includes:
* A two-page menu for items and quest status.
* A custom item layout and drawing routines.
* A detailed quest status screen with new icons and text.
* A custom HUD with a new magic meter and layout.
### 3.5. Custom Items
The `Items/` directory contains the implementation for all new items, such as the Goldstar, Portal Rod, and Ocarina songs. These items often have complex interactions with the player state machine and other game systems.
### 3.6. Sprite Engine
While the main sprite engine from the original game is still used (`bank_06.asm`), Oracle of Secrets introduces a custom sprite system for managing complex sprite behaviors and interactions. The `Sprites/` directory contains the code for all new custom sprites, including NPCs, enemies, and bosses.
`Core/sprite_functions.asm`, `Core/sprite_macros.asm`, `Core/sprite_new_table.asm` and `Sprites/all_sprites.asm` contain the overriden sprite logic and includes for all custom sprites.
## 4. Coding Standards & Style
### 4.1. File and Directory Structure
The project is organized into a modular directory structure. New code should be placed in the appropriate directory based on its functionality (e.g., new items in `Items/`, new sprites in `Sprites/`).
### 4.2. Naming Conventions
* **Labels:** Use descriptive, CamelCase names for labels (e.g., `LinkState_Swimming`, `Menu_DrawItemName`).
* **Variables:** Use uppercase for constants (`!CONSTANT_NAME`) and CamelCase for RAM/SRAM variables (`VariableName`).
* **Macros:** Use CamelCase for macro names (`%MacroName()`).
### 4.3. Commenting
Comments should be used to explain the *why* behind a piece of code, not the *what*. For complex logic, a brief explanation of the algorithm or purpose is helpful. Avoid excessive or obvious comments.
### 4.4. Macros
Macros are used extensively to simplify common tasks and improve code readability. When creating new macros, follow the existing style and ensure they are well-documented.
## 5. Debugging
### 5.1. Common Issues
* **`BRK` Instructions:** A `BRK` instruction indicates a crash. This is often caused by:
* Jumping to invalid memory (uninitialized ROM, data instead of code)
* P-register mismatch (e.g., calling a 16-bit routine when in 8-bit mode)
* Stack corruption (unbalanced push/pop, JSR/JSL vs RTS/RTL mismatch)
* Return without matching call (RTL executed without previous JSL)
* **P-Register Mismatches:** Always ensure the M and X flags of the processor status register are in the correct state before calling a routine. Use `SEP` and `REP` to switch between 8-bit and 16-bit modes as needed.
* **Stack Corruption:** Ensure push/pop operations are balanced and that JSR is paired with RTS (2 bytes) while JSL is paired with RTL (3 bytes). Never mix them.
* **Namespace Visibility:** If you get "label not found" errors, verify:
* Label is exported with `Oracle_` prefix
* File is included in correct build order in `Oracle_main.asm`
* Namespace block is properly closed
* **Memory Conflicts:** If you get "overwrote some code" warnings:
* Check for overlapping `org` directives
* Use `assert pc() <= $ADDRESS` to protect boundaries
* Review ROM map in Section 6 for available space
**For comprehensive troubleshooting guidance, see `Docs/General/Troubleshooting.md` which covers:**
- BRK crash debugging with emulator tools
- Stack corruption patterns
- Processor status register issues
- Cross-namespace calling problems
- Memory conflicts and bank collisions
- Graphics/DMA timing issues
- ZScream-specific problems
### 5.2. Debugging Tools
* **Mesen-S (Recommended):** The most powerful SNES debugger with:
* Execution breakpoints with conditions
* Memory watchpoints (read/write/execute)
* Stack viewer
* Event viewer (NMI/IRQ timing)
* Live memory updates
* **BSNES-Plus:** Cycle-accurate emulator with:
* Memory editor with search
* Tilemap and VRAM viewers
* Debugger with disassembly
* **`!DEBUG` Flag:** The `!DEBUG` flag in `Util/macros.asm` can be used to enable or disable build-time logging.
* **`%print_debug()` Macro:** This macro can be used to print debug messages and register values during assembly. It is an invaluable tool for tracing code execution and identifying issues.
* **Breadcrumb Tracking:** Add markers to narrow down crash locations:
```asm
LDA.b #$01 : STA.l $7F5000 ; Breadcrumb 1
JSL SuspiciousFunction
LDA.b #$02 : STA.l $7F5000 ; Breadcrumb 2
; After crash, check $7F5000 to see which breadcrumb was reached
```
* **Vanilla Disassembly:** The ALTTP disassembly in `ALTTP/` is the primary reference for the original game's code. Use it to understand the context of vanilla routines that are being hooked or modified.
### 5.3. Debugging Checklist
When encountering an issue:
1. ✅ Check error message carefully - Asar errors are usually precise
2. ✅ Verify namespace - Is label prefixed correctly?
3. ✅ Check stack balance - Equal push/pop counts?
4. ✅ Verify processor state - REP/SEP correct for operation?
5. ✅ Check memory bounds - Assertions in place?
6. ✅ Test in Mesen-S first - Best debugger for SNES
7. ✅ Use breadcrumbs - Narrow down crash location
8. ✅ Check build order - Files included in correct order?
9. ✅ Review recent changes - Compare with known working version
10. ✅ Read vanilla code - Understand what you're hooking
## 6. ROM Map & Memory Layout
Oracle of Secrets utilizes the ZScream expanded ROM map, providing significant additional space for new code and data. The allocation of custom code and data within these banks is managed through `org` directives in the assembly files. The `incsrc` order in `Oracle_main.asm` is crucial, as it dictates the final placement of these blocks in the ROM.
Here is a detailed overview of the custom ROM bank allocations:
| Bank (Hex) | Address Range (PC) | Purpose / Contents | Defining File(s) |
|------------|--------------------|--------------------------------------------------------|---------------------------------------|
| $20 | `$208000` - `$20FFFF` | Expanded Music | `Music/all_music.asm` |
| $21-$27 | | ZScream Reserved | |
| $28 | `$288000` - `$28FFFF` | ZSCustomOverworld data and code | `Overworld/ZSCustomOverworld.asm` |
| $29-$2A | | ZScream Reserved | |
| $2B | `$2B8000` - `$2BFFFF` | Items | `Items/all_items.asm` |
| $2C | `$2C8000` - `$2CFFFF` | Underworld/Dungeons | `Dungeons/dungeons.asm` |
| $2D | `$2D8000` - `$2DFFFF` | Menu | `Menu/menu.asm` |
| $2E | `$2E8000` - `$2EFFFF` | HUD | `Menu/menu.asm` |
| $2F | `$2F8000` - `$2FFFFF` | Expanded Message Bank | `Core/message.asm` |
| $30 | `$308000` - `$30FFFF` | Sprites | `Sprites/all_sprites.asm` |
| $31 | `$318000` - `$31FFFF` | Sprites | `Sprites/all_sprites.asm` |
| $32 | `$328000` - `$32FFFF` | Sprites | `Sprites/all_sprites.asm` |
| $33 | `$338000` - `$33FFFF` | Moosh Form Gfx and Palette | `Masks/all_masks.asm` |
| $34 | `$348000` - `$34FFFF` | Time System, Custom Overworld Overlays, Gfx | `Masks/all_masks.asm` |
| $35 | `$358000` - `$35FFFF` | Deku Link Gfx and Palette | `Masks/all_masks.asm` |
| $36 | `$368000` - `$36FFFF` | Zora Link Gfx and Palette | `Masks/all_masks.asm` |
| $37 | `$378000` - `$37FFFF` | Bunny Link Gfx and Palette | `Masks/all_masks.asm` |
| $38 | `$388000` - `$38FFFF` | Wolf Link Gfx and Palette | `Masks/all_masks.asm` |
| $39 | `$398000` - `$39FFFF` | Minish Link Gfx | `Masks/all_masks.asm` |
| $3A | `$3A8000` - `$3AFFFF` | Mask Routines, Custom Ancillae (Deku Bubble) | `Masks/all_masks.asm` |
| $3B | `$3B8000` - `$3BFFFF` | GBC Link Gfx | `Masks/all_masks.asm` |
| $3C | | Unused | |
| $3D | | ZS Tile16 | |
| $3E | | LW ZS Tile32 | |
| $3F | | DW ZS Tile32 | |
| $40 | `$408000` - `$40FFFF` | LW World Map | `Overworld/overworld.asm` |
| $41 | `$418000` - `$41FFFF` | DW World Map | `Overworld/overworld.asm` |
| Patches | Various | Targeted modifications within vanilla ROM addresses | `Core/patches.asm`, `Util/item_cheat.asm` |
For a more detailed breakdown of the ROM map, refer to the `ZS ROM MAP.txt` file in the `Core/` directory, and `Docs/Core/MemoryMap.md` for a comprehensive overview of all custom memory regions.
---
## 7. Documentation
The following documents have been generated by analyzing the codebase and project files. They serve as key references for understanding the project's architecture and gameplay systems.
* **`Docs/Core/MemoryMap.md`:** A comprehensive map of all custom WRAM and SRAM variables, including repurposed vanilla blocks. See [MemoryMap.md](../Core/MemoryMap.md) for details.
* **`Docs/Core/Ram.md`:** High-level overview of WRAM and SRAM usage with verified custom variables. See [Ram.md](../Core/Ram.md) for details.
* **`Docs/World/Overworld/ZSCustomOverworldAdvanced.md`:** Advanced technical guide for ZScream integration, including hook architecture, sprite loading system, cross-namespace integration, and performance considerations. See [ZSCustomOverworldAdvanced.md](../World/Overworld/ZSCustomOverworldAdvanced.md) for details.
* **`Docs/General/Troubleshooting.md`:** Comprehensive troubleshooting guide covering BRK crashes, stack corruption, processor state issues, namespace problems, memory conflicts, and graphics issues. See [Troubleshooting.md](Troubleshooting.md) for details.
* **`Docs/QuestFlow.md`:** A detailed guide to the main story and side-quest progression, including trigger conditions and progression flags. See [QuestFlow.md](../QuestFlow.md) for details.
* **`Docs/SpriteCreationGuide.md`:** A step-by-step tutorial for creating a new custom sprite using the project's frameworks and conventions. See [SpriteCreationGuide.md](SpriteCreationGuide.md) for details.
* **`Docs/Menu.md`:** A detailed analysis of the custom menu and HUD systems. See [Menu.md](Menu.md) for details.
* **`Docs/Items.md`:** A detailed guide to the custom and modified items in the game. See [Items.md](Items.md) for details.
* **`Docs/Music.md`:** A guide to the custom music tracks and sound effects, including how to add new audio. See [Music.md](Music.md) for details.
* **`Docs/Masks.md`:** A comprehensive overview of the Mask System, including each mask's abilities and implementation details. See [Masks.md](Masks.md) for details.
* **`Docs/Dungeons.md`:** A breakdown of all dungeons, including layouts, enemy placements, and puzzle solutions. See [Dungeons.md](Dungeons.md) for details.
* **`Docs/Overworld.md`:** An analysis of the overworld systems, including `ZSCustomOverworld`, the time system, and other custom features. See [Overworld.md](Overworld.md) for details.
* **`Docs/NPCs.md`:** An analysis of the various NPC sprites. See [NPCs.md](NPCs.md) for details.
* **`Docs/Bosses.md`:** An analysis of the custom boss sprites. See [Bosses.md](Bosses.md) for details.
* **`Docs/Objects.md`:** An analysis of interactive object sprites. See [Objects.md](Objects.md) for details.
* **`Docs/Overlord.md`:** An analysis of the Overlord sprite system. See [Overlord.md](Overlord.md) for details.

File diff suppressed because it is too large Load Diff

177
Docs/Guides/QuestFlow.md Normal file
View File

@@ -0,0 +1,177 @@
# Quest & Event Flow
This document outlines the progression of the main story and major side-quests. It details the flags and conditions that control the game's narrative flow, making it easier to understand how events are triggered.
## 1. Main Quest Progression
*This section provides a step-by-step guide to the main story, detailing the sequence of events, required items, and the flags that are set at each milestone.*
### Chapter 0: A Hero is Born
1. **Trigger:** The game begins.
2. **Events:**
* The Farore intro sequence plays, explaining the backstory of the Triforce and the sealing of the Sacred Realm.
* Link is shipwrecked and awakens in the Eon Abyss.
* The Kydrog intro sequence plays, showing the game's antagonist.
* Link is transported to the Temporal Pyramid.
3. **Player Actions:**
* Navigate the Temporal Pyramid to find the **Moon Pearl**.
* Exit the pyramid to arrive in the Forest of Dreams.
* Obtain the **Lv1 Sword and Shield**.
4. **Progression Flags:**
| Flag | Address | Value/Bit | Notes |
|------------|----------|----------------|-------------------------------------|
| `GameState`| `$7EF3C5`| `0x02` | Set after the Farore intro. |
| `OosProg2` | `$7EF3C6`| `bit $04` set | Set after the Kydrog intro. |
### Chapter 1: The Maku Tree Awakens
1. **Trigger:** Player talks to the Maku Tree for the first time (`Sprites/NPCs/maku_tree.asm`).
2. **Events:** The Maku Tree speaks to Link, explaining the plight of the land.
3. **Reward:** A Heart Container is given to the player (`Link_ReceiveItem` with Y=`$3E`).
4. **Progression Flags & Consequences:**
| Flag | Address | Value/Bit | Consequence |
|-----------------|----------|---------------|--------------------------------------------------------------------------|
| `MakuTreeQuest` | `$7EF3D4`| `0x01` | The Maku Tree will now use a different dialogue branch on subsequent talks. |
| `MapIcon` | `$7EF3C7`| `0x01` | A red 'X' appears on the map over the Mushroom Grotto. |
| `OOSPROG` | `$7EF3D6`| `bit $02` set | A major story flag indicating the quest has officially begun. |
### Chapter 2: The Mushroom Grotto (D1)
1. **Trigger:** Player enters the Mushroom Grotto, west of Wayward Village.
2. **Events:** Player navigates the dungeon, facing the Vampire Bat miniboss and the Mothra boss.
3. **Reward:** **Bow**.
### Chapter 3: The Tail Palace (D2)
1. **Trigger:** Player enters Tail Palace.
2. **Events:** Player defeats the boss, a vanilla-style Big Moldorm.
3. **Reward:** **Roc's Feather**.
4. **World State Changes:** After completion, Deku NPCs will appear in the overworld area near Tail Palace.
### Chapter 4: The Path to the Castle
1. **Trigger:** This is a multi-part quest chain required to access Kalyxo Castle.
2. **Player Actions:**
* **Ocarina:** Complete the "Lost Ranch Girl" side-quest to obtain the Ocarina.
* **Song of Healing:** Learn the Song of Healing from the Happy Mask Salesman.
* **Running Boots:** Play the Song of Healing for the sick child in Wayward Village to receive the Running Boots.
* **Book of Secrets:** Use the Running Boots to get the Book of Secrets from the village library.
3. **Consequence:** The Book of Secrets is required to open the gates to Kalyxo Castle.
### Chapter 5: Kalyxo Castle (D3)
1. **Trigger:** Player enters Kalyxo Castle.
2. **Required Items:** Book of Secrets.
3. **Events:** Player defeats the Armos Knights boss.
4. **Reward:** **Meadow Blade (Lv2 Sword)**.
### Chapter 6: The Shrine of Wisdom (S1)
1. **Trigger:** Player enters the Shrine of Wisdom.
2. **Events:** Player must navigate a swampy overworld area.
3. **Reward:** **Zora Flippers**.
### Chapter 7: Zora Temple (D4)
1. **Trigger:** Player enters the Zora Temple.
2. **Required Items:** Zora Flippers.
3. **Events:** Player defeats an advanced variant of the Arrghus boss.
4. **Reward:** **Hookshot**, **Zora Mask** (via side-quest within the dungeon).
### Chapter 8: Glacia Estate (D5)
1. **Trigger:** Player enters Glacia Estate.
2. **Required Items:** **Goldstar** (from the "Old Man Mountain Quest").
3. **Events:** Player navigates ice puzzles and defeats the Twinrova boss.
4. **Reward:** **Fire Rod**.
### Chapter 9: The Shrine of Power (S2)
1. **Trigger:** Player enters the Shrine of Power.
2. **Reward:** **Power Glove**.
### Chapter 10: Goron Mines (D6)
1. **Trigger:** Player enters the Goron Mines.
2. **Required Items:** **Power Glove**, Completion of the "Goron Mines Quest".
3. **Events:** Player defeats the Lanmolas and the King Dodongo (Helmasaur variant) boss.
4. **Reward:** **Hammer**.
### Chapter 11: Dragon Ship (D7)
1. **Trigger:** Player enters the Dragon Ship.
2. **Reward:** **Somaria Rod**.
### Chapter 12: The Shrine of Courage (S3)
1. **Trigger:** Player enters the Shrine of Courage.
2. **Events:** Player defeats the boss Vaati (Vitreous variant).
3. **Reward:** **Mirror Shield**.
### Chapter 13: Fortress of Secrets (D8)
1. **Trigger:** Player enters the Fortress of Secrets.
2. **Events:** Player defeats Dark Link.
3. **Reward:** **Portal Rod**.
### Chapter 14: The Eon Core (Endgame)
1. **Trigger:** Player enters the final dungeon.
2. **Events:** Player faces the final bosses: Kydreeok and Ganon.
3. **Reward:** **The Triforce**.
---
## 2. Major Side-Quests
### The Lost Ranch Girl (Ocarina Quest)
1. **Mushroom:** Get a Mushroom from the old woman's house in the Mushroom Grotto area.
2. **Magic Powder:** Trade the Mushroom to the Potion Shop owner. Leave the area and return later to receive the Magic Powder.
3. **Ocarina:** Use the Magic Powder on the sleeping Cucco in the Ranch House. This wakes it up and it gives you the Ocarina.
### The Mask Salesman
1. **Trigger:** Player must have the Ocarina.
2. **Action:** Talk to the Happy Mask Salesman.
3. **Reward:** He teaches Link the **Song of Healing**.
### The Zora Mask
1. **Trigger:** Player talks to the Zora Princess in the Zora Temple. She gives message `$0C5`.
2. **Action:** Player must play the Song of Healing.
3. **Reward:** The princess gives the player the **Zora Mask**.
4. **Flag:** `ZoraMask` (`$7EF347`) is set in SRAM.
### The Wolf Mask
1. **Trigger:** A Wolfos sprite appears outside Kalyxo Castle at night.
2. **Action:** Player must defeat the Wolfos and then play the Song of Healing.
3. **Reward:** **Wolf Mask**.
### Old Man Mountain Quest
1. **Trigger:** Player takes the warp portal at the northwest point of Mount Snowpeak.
2. **Action:** Enter the Lava Lands cave to find an Old Man sprite. Escort him to a rock formation and use the Magic Mirror.
3. **Reward:** **Goldstar** (upgrade for the Hookshot).
### Goron Mines Quest
1. **Trigger:** Player needs to open the Goron Mines.
2. **Required Item:** Power Glove.
3. **Action:**
* Collect five pieces of Goron Rock Meat from Lupo Mountain.
* Give the five pieces to the Kalyxian Goron NPC in the desert.
4. **Consequence:** The Goron NPC opens the entrance to the Goron Mines.
### The Magic Bean
1. **Purchase:** Player buys the Magic Bean from the Bean Vendor for 100 rupees. Requires an empty bottle.
2. **Planting:** Player takes the bean to the fertile soil patch on the ranch. `MagicBeanProg` (`$7EF39B`) has bit `$01` set.
3. **Watering:** Player plays the Song of Storms. `MagicBeanProg` has bit `$04` set.
4. **Pollination:** Player must release a Good Bee from a bottle near the bean sprout. `MagicBeanProg` has bit `$02` set.
5. **Growth:** After 3 in-game day/night cycles, the beanstalk grows into a large flower.
6. **Reward:** The player can ride the flower to a Heart Container. `MagicBeanProg` has bit `$40` set upon completion.

View File

@@ -0,0 +1,877 @@
# Sprite Creation Guide
This guide provides a step-by-step walkthrough for creating a new custom sprite in Oracle of Secrets using the project's modern sprite system.
## 1. File Setup
1. **Create the Sprite File:** Create a new `.asm` file for your sprite in the appropriate subdirectory of `Sprites/`:
* `Sprites/Enemies/` - For enemy sprites
* `Sprites/Bosses/` - For boss sprites
* `Sprites/NPCs/` - For non-playable character sprites
* `Sprites/Objects/` - For interactive objects and items
2. **Include the File:** Open `Sprites/all_sprites.asm` and add an `incsrc` directive to include your new file. The file must be placed in the correct bank section:
* **Bank 30** (`$308000`) - First bank, includes `sprite_new_table.asm` and some core sprites
* **Bank 31** (`$318000`) - Second bank, includes `sprite_functions.asm` and more sprites
* **Bank 32** (`$328000`) - Third bank for additional sprites
* **Bank 2C** (Dungeon bank) - For sprites that are part of dungeon-specific content
Example:
```asm
; In Sprites/all_sprites.asm
org $318000 ; Bank 31
%log_start("my_new_enemy", !LOG_SPRITES)
incsrc "Sprites/Enemies/MyNewEnemy.asm"
%log_end("my_new_enemy", !LOG_SPRITES)
```
3. **Assign a Sprite ID:** Choose an unused sprite ID for your sprite. You can either:
* Use a completely new ID (e.g., `$A0` through `$FF` range)
* Override a vanilla sprite ID (for replacing existing sprites)
* Share an ID with another sprite and use `SprSubtype` to differentiate behaviors
## 2. Sprite Properties
At the top of your new sprite file, define its core properties using the provided template. These `!` constants are used by the `%Set_Sprite_Properties` macro to automatically configure the sprite's behavior and integrate it into the game.
```asm
; =========================================================
; Sprite Properties
; =========================================================
!SPRID = $XX ; CHOOSE AN UNUSED SPRITE ID or use a constant like Sprite_MyNewEnemy
!NbrTiles = 02 ; Number of 8x8 tiles used in the largest frame
!Harmless = 00 ; 00 = Harmful, 01 = Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 10 ; Number of Health the sprite has
!Damage = 04 ; Damage dealt to Link on contact (08 = whole heart, 04 = half heart)
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attacked, 01 = all attacks clink harmlessly
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 08 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = sprite continues to live offscreen
!Statis = 00 ; 00 = sprite is alive? (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layers for collision
!CanFall = 00 ; 01 = sprite can fall in holes, 00 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk in shallow water
!Blockable = 00 ; 01 = can be blocked by Link's shield
!Prize = 01 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is a statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
; This macro MUST be called after the properties
%Set_Sprite_Properties(Sprite_MyNewEnemy_Prep, Sprite_MyNewEnemy_Long)
```
### Property Details
**Memory Mapping:** The `%Set_Sprite_Properties` macro writes these properties to specific ROM addresses:
* `$0DB080+!SPRID` - OAM/Harmless/HVelocity/NbrTiles
* `$0DB173+!SPRID` - Sprite HP
* `$0DB266+!SPRID` - Sprite Damage
* `$0DB359+!SPRID` - Death Animation/Impervious/Shadow/Palette flags
* `$0DB44C+!SPRID` - Collision Layer/Statis/Persist/Hitbox
* `$0DB53F+!SPRID` - DeflectArrow/Boss/CanFall flags
* `$0DB632+!SPRID` - Interaction/WaterSprite/Blockable/Sound/Prize
* `$0DB725+!SPRID` - Statue/DeflectProjectiles/Impervious flags
The macro also sets up the jump table entries at:
* `$069283+(!SPRID*2)` - Vanilla Sprite Main Pointer
* `$06865B+(!SPRID*2)` - Vanilla Sprite Prep Pointer
* `NewSprRoutinesLong+(!SPRID*3)` - New Long Sprite Pointer
* `NewSprPrepRoutinesLong+(!SPRID*3)` - New Long Sprite Prep Pointer
### Design Considerations
* **Multi-purpose Sprite IDs:** A single `!SPRID` can be used for multiple distinct behaviors (e.g., Keese, Fire Keese, Ice Keese, Vampire Bat all share sprite IDs) through the use of `SprSubtype`. This is a powerful technique for reusing sprite slots and creating variations of enemies.
* **Damage Handling for Bosses:** For boss sprites, `!Damage = 00` is common if damage is applied through other means, such as spawned projectiles or direct contact logic within the main routine.
* **Dynamic Health:** Many sprites set health dynamically in their `_Prep` routine based on game progression (e.g., Booki sets health based on Link's sword level, Darknut based on sword upgrades).
* **Custom Boss Logic:** Setting `!Boss = 00` for a boss sprite indicates that custom boss logic is being used, rather than relying on vanilla boss flags.
* **Shared Sprite IDs:** Multiple distinct NPCs or objects can share a single `!SPRID` by using `SprSubtype` for differentiation (e.g., `Sprite_Mermaid = $F0` is used for Mermaid, Maple, and Librarian with different subtypes).
## 3. Main Structure (`_Long` routine)
This is the main entry point for your sprite, called by the game engine every frame. Its primary job is to call the drawing and logic routines.
```asm
Sprite_MyNewEnemy_Long:
{
PHB : PHK : PLB ; Set up bank registers (Push Bank, Push K, Pull Bank)
JSR Sprite_MyNewEnemy_Draw
JSL Sprite_DrawShadow ; Optional: Draw a shadow (use appropriate shadow function)
JSL Sprite_CheckActive : BCC .SpriteIsNotActive ; Only run logic if active
JSR Sprite_MyNewEnemy_Main
.SpriteIsNotActive
PLB ; Restore bank register
RTL ; Return from long routine
}
```
### Important Notes
* **Bank Register Management:** Always use `PHB : PHK : PLB` at the start and `PLB` before `RTL` to ensure proper bank context.
* **Sprite_CheckActive:** This critical function checks if the sprite should execute logic based on its state, freeze status, and pause flags. Returns carry set if active.
* **Drawing Order:** Drawing is typically done before the main logic, though the order can vary based on sprite needs.
* **Conditional Drawing:** Shadow drawing might be conditional based on the sprite's current action or state (e.g., Thunder Ghost only draws shadow when grounded).
## 4. Initialization (`_Prep` routine)
This routine runs *once* when the sprite is first spawned. Use it to set initial values for timers, its action state, and any other properties. For dynamic difficulty scaling, you can adjust properties based on game progression here.
```asm
Sprite_MyNewEnemy_Prep:
{
PHB : PHK : PLB
; Set dynamic health based on sword level (optional)
LDA.l Sword : DEC A : TAY
LDA.w .health, Y : STA.w SprHealth, X
%GotoAction(0) ; Set the initial state to the first one in the jump table
%SetTimerA(120) ; Set a general-purpose timer to 120 frames (2 seconds)
PLB
RTL
; Optional: Dynamic health table
.health
db $04, $08, $10, $18 ; Health values for sword levels 1-4
}
```
### Available Sprite RAM Variables
The following WRAM addresses are available for sprite-specific data (all indexed by X):
**Position & Movement:**
* `SprY, SprX` ($0D00, $0D10) - 8-bit position coordinates (low byte)
* `SprYH, SprXH` ($0D20, $0D30) - High bytes of position
* `SprYSpeed, SprXSpeed` ($0D40, $0D50) - Movement velocities
* `SprYRound, SprXRound` ($0D60, $0D70) - Sub-pixel precision
* `SprCachedX, SprCachedY` ($0FD8, $0FDA) - Cached coordinates
**Animation & Graphics:**
* `SprAction` ($0D80) - Current state in state machine
* `SprFrame` ($0D90) - Current animation frame index
* `SprGfx` ($0DC0) - Graphics offset for drawing
* `SprFlash` ($0B89) - Flash color for damage indication
**Timers:**
* `SprTimerA-F` ($0DF0, $0E00, $0E10, $0EE0, $0F10, $0F80) - Six general-purpose timers
* Note: `SprTimerF` decreases by 2 each frame (used for gravity)
**Miscellaneous Data:**
* `SprMiscA-G` ($0DA0, $0DB0, $0DE0, $0E90, $0EB0, $0EC0, $0ED0) - Seven general-purpose variables
* `SprCustom` ($1CC0) - Additional custom data storage
**State & Properties:**
* `SprState` ($0DD0) - Sprite state (0x00=dead, 0x08=spawning, 0x09=active, etc.)
* `SprType` ($0E20) - Sprite ID
* `SprSubtype` ($0E30) - Sprite subtype for variations
* `SprHealth` ($0E50) - Current health
* `SprNbrOAM` ($0E40) - Number of OAM slots + flags
* `SprFloor` ($0F20) - Layer (0=top, 1=bottom)
* `SprHeight` ($0F80) - Z-position for altitude/jumping
### Common Initialization Patterns
```asm
; Set sprite to be impervious initially (e.g., for a boss with phases)
LDA.b #$80 : STA.w SprDefl, X
; Configure tile collision behavior
LDA.b #%01100000 : STA.w SprTileDie, X
; Set bump damage type
LDA.b #$09 : STA.w SprBump, X
; Initialize custom variables
STZ.w SprMiscA, X
STZ.w SprMiscB, X
```
## 5. Main Logic & State Machine (`_Main` routine)
This is the heart of your sprite. Use the `%SpriteJumpTable` macro to create a state machine. The sprite's current state is stored in `SprAction, X`.
```asm
Sprite_MyNewEnemy_Main:
{
%SpriteJumpTable(State_Idle, State_Attacking, State_Hurt)
State_Idle:
{
%PlayAnimation(0, 1, 15) ; Animate between frames 0 and 1 every 15 game frames
; Check distance to player. If less than 80 pixels, switch to attacking state.
JSL GetDistance8bit_Long : CMP.b #$50 : BCS .player_is_far
%GotoAction(1) ; Switch to State_Attacking
.player_is_far
RTS
}
State_Attacking:
{
%PlayAnimation(2, 3, 8)
%MoveTowardPlayer(12) ; Move toward the player with speed 12
%DoDamageToPlayerSameLayerOnContact()
; Check if the player has hit the sprite
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
%GotoAction(2) ; Switch to State_Hurt
.no_damage
RTS
}
State_Hurt:
{
; Sprite was hit, flash and get knocked back
JSL Sprite_DamageFlash_Long
JSL Sprite_CheckIfRecoiling
; Return to attacking after recoil
LDA.w SprRecoil, X : BNE .still_recoiling
%GotoAction(1)
.still_recoiling
RTS
}
}
```
### Available Macros
**State Management:**
* `%GotoAction(action)` - Set `SprAction` to switch states
* `%SpriteJumpTable(state1, state2, ...)` - Create state machine jump table
* `%JumpTable(index, state1, state2, ...)` - Jump table with custom index
**Animation:**
* `%PlayAnimation(start, end, speed)` - Animate frames (uses `SprTimerB`)
* `%PlayAnimBackwards(start, end, speed)` - Animate in reverse
* `%StartOnFrame(frame)` - Ensure animation starts at a minimum frame
* `%SetFrame(frame)` - Directly set animation frame
**Movement:**
* `%MoveTowardPlayer(speed)` - Apply speed toward player and move
* `%SetSpriteSpeedX(speed)` - Set horizontal velocity
* `%SetSpriteSpeedY(speed)` - Set vertical velocity
**Timers:**
* `%SetTimerA-F(length)` - Set timer values
**Player Interaction:**
* `%DoDamageToPlayerSameLayerOnContact()` - Damage on contact (same layer only)
* `%PlayerCantPassThrough()` - Prevent Link from passing through sprite
* `%ShowSolicitedMessage(id)` - Show message when player presses A
* `%ShowMessageOnContact(id)` - Show message on contact
* `%ShowUnconditionalMessage(id)` - Show message immediately
**Sprite Properties:**
* `%SetHarmless(value)` - 0=harmful, 1=harmless
* `%SetImpervious(value)` - Toggle invulnerability
* `%SetRoomFlag(value)` - Set room completion flag
**Audio:**
* `%PlaySFX1(id)`, `%PlaySFX2(id)` - Play sound effect
* `%PlayMusic(id)` - Change background music
* `%ErrorBeep()` - Play error sound
**Utility:**
* `%ProbCheck(mask, label)` - Random check, branch if result is non-zero
* `%ProbCheck2(mask, label)` - Random check, branch if result is zero
* `%SetupDistanceFromSprite()` - Setup distance calculation
### Common Functions
**Movement & Physics:**
* `Sprite_Move` / `Sprite_MoveLong` - Apply velocity to position
* `Sprite_MoveHoriz` / `Sprite_MoveVert` - Move in one axis
* `Sprite_BounceFromTileCollision` - Bounce off walls
* `Sprite_CheckTileCollision` - Check for tile collision
* `Sprite_ApplySpeedTowardsPlayer` - Calculate speed toward player
* `Sprite_FloatTowardPlayer` - Float toward player with altitude
* `Sprite_FloatAwayFromPlayer` - Float away from player
* `Sprite_InvertSpeed_X` / `Sprite_InvertSpeed_Y` - Reverse velocity
**Combat:**
* `Sprite_CheckDamageFromPlayer` - Check if player attacked sprite
* `Sprite_CheckDamageToPlayer` - Check if sprite damaged player
* `Sprite_DamageFlash_Long` - Flash sprite when damaged
* `Sprite_CheckIfRecoiling` - Handle knockback after being hit
* `Guard_ParrySwordAttacks` - Parry sword attacks (like Darknut)
**Spawning:**
* `Sprite_SpawnDynamically` - Spawn a new sprite
* `Sprite_SpawnProbeAlways_long` - Spawn probe projectile
* `Sprite_SpawnSparkleGarnish` - Spawn sparkle effect
**Distance & Direction:**
* `GetDistance8bit_Long` - Get 8-bit distance to player
* `Sprite_DirectionToFacePlayer` - Get direction to face player
* `Sprite_IsToRightOfPlayer` - Check if sprite is to right of player
**Randomness:**
* `GetRandomInt` - Get random 8-bit value
### Code Style Guidelines
* **Named Constants:** Always use named constants for magic numbers:
```asm
GoriyaMovementSpeed = 10
LDA.b #GoriyaMovementSpeed : STA.w SprXSpeed, X
```
* **Processor Status Flags:** Explicitly manage 8-bit/16-bit mode with `REP #$20` (16-bit) and `SEP #$20` (8-bit), especially during OAM calculations
* **State Machine Pattern:** Use `SprAction` with `%SpriteJumpTable` for clear state management
* **Timer Usage:** Use dedicated timers for different purposes (e.g., `SprTimerA` for state changes, `SprTimerB` for animation, `SprTimerC` for cooldowns)
## 6. Drawing (`_Draw` routine)
This routine renders your sprite's graphics. The project provides the `%DrawSprite()` macro for standard drawing, which reads from data tables you define.
### Standard Drawing with %DrawSprite()
```asm
Sprite_MyNewEnemy_Draw:
{
JSL Sprite_PrepOamCoord ; Prepare OAM coordinates
JSL Sprite_OAM_AllocateDeferToPlayer ; Allocate OAM slots
%DrawSprite()
; --- OAM Data Tables ---
.start_index ; Starting index in the tables for each animation frame
db $00, $02, $04, $06
.nbr_of_tiles ; Number of tiles to draw for each frame (actual count minus 1)
db 1, 1, 1, 1
.x_offsets ; X-position offset for each tile (16-bit values)
dw -8, 8, -8, 8, -8, 8, -8, 8
.y_offsets ; Y-position offset for each tile (16-bit values)
dw -8, -8, -8, -8, -8, -8, -8, -8
.chr ; The character (tile) number from the graphics sheet
db $C0, $C2, $C4, $C6, $C8, $CA, $CC, $CE
.properties ; OAM properties (palette, priority, flips)
db $3B, $7B, $3B, $7B, $3B, $7B, $3B, $7B
.sizes ; Size of each tile (e.g., $02 for 16x16)
db $02, $02, $02, $02, $02, $02, $02, $02
}
```
### OAM Property Byte Format
The `.properties` byte contains flags for each tile:
* Bits 0-2: Palette (0-7)
* Bit 3: Priority (0=front, 1=behind BG)
* Bit 4: Unused
* Bit 5: Horizontal flip
* Bit 6: Vertical flip
* Bit 7: Unused
Example values:
* `$39` = Palette 1, no flip, front priority
* `$79` = Palette 1, horizontal flip, front priority
* `$B9` = Palette 1, vertical flip, front priority
### Custom Drawing Logic
For complex drawing needs (multi-part sprites, dynamic flipping, etc.), implement custom drawing:
```asm
Sprite_MyNewEnemy_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY ; Get animation frame
LDA.w .start_index, Y : STA $06 ; Get starting index
LDA.w SprFlash, X : STA $08 ; Store flash value
LDA.w SprMiscC, X : STA $09 ; Store direction for flipping
PHX
LDX .nbr_of_tiles, Y ; Load number of tiles minus 1
LDY.b #$00 ; OAM buffer index
.nextTile
PHX ; Save tile index
TXA : CLC : ADC $06 : PHA ; Calculate absolute tile index
ASL A : TAX ; Multiply by 2 for 16-bit offsets
REP #$20 ; 16-bit accumulator
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y ; Write X position
AND.w #$0100 : STA $0E ; Store X high bit
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y ; Write Y position
CLC : ADC #$0010 : CMP.w #$0100 ; Check if on screen
SEP #$20 ; Back to 8-bit
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y : STA $0E ; Move offscreen
.on_screen_y
PLX ; Restore absolute tile index
INY
LDA .chr, X : STA ($90), Y ; Write character
INY
; Apply horizontal flip based on direction
LDA.b $09 : BEQ .no_flip
LDA.b #$79 : JMP .write_prop
.no_flip
LDA .properties, X
.write_prop
ORA $08 : STA ($90), Y ; Write properties with flash
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; Write size
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
; Data tables follow...
}
```
### Important Drawing Notes
* **16-bit Calculations:** Always use `REP #$20` before 16-bit position calculations and `SEP #$20` afterward
* **OAM Allocation:** Different allocation functions for different scenarios:
* `Sprite_OAM_AllocateDeferToPlayer` - Standard allocation
* `OAM_AllocateFromRegionE` - For large sprites (bosses)
* `Sprite_OAM_AllocateDeferToPlayerLong` - Long version
* **Shadow Drawing:** Call `Sprite_DrawShadow` in the `_Long` routine, not in `_Draw`
* **Multi-Layer Drawing:** For objects like minecarts that Link can be "inside", draw in multiple parts from different OAM regions to create depth
* **Conditional Drawing:** Some sprites (like followers or bosses) dispatch to different draw routines based on `SprSubtype` or current state
## 7. Final Integration
The `%Set_Sprite_Properties()` macro you added in Step 2 handles the final integration automatically. It:
1. Writes your sprite properties to the appropriate ROM addresses
2. Sets up pointers in the vanilla sprite jump tables
3. Adds your `_Prep` and `_Long` routines to the new sprite table in `Core/sprite_new_table.asm`
Your sprite is now ready to be placed in the game world using your level editor!
## 8. Testing Your Sprite
1. **Build the ROM:** Run your build script (`build.sh` or `build.bat`)
2. **Place in Editor:** Use your level editor to place the sprite in a room
3. **Test Behavior:** Load the room and verify:
* Sprite spawns correctly
* Animation plays as expected
* Movement works properly
* Collision detection functions
* Damage and health mechanics work
* State transitions occur correctly
## 9. Common Issues and Solutions
### Sprite Doesn't Appear
* Check that the sprite ID is not already in use
* Verify the `incsrc` directive is in the correct bank
* Ensure `%Set_Sprite_Properties` is called after property definitions
* Check that the sprite is being placed in a compatible room type
### Graphics are Corrupted
* Verify 16-bit mode (`REP #$20`) is used for OAM calculations
* Check that `.start_index`, `.nbr_of_tiles`, and data tables are correctly sized
* Ensure `.sizes` table uses correct values ($00=8x8, $02=16x16)
* Verify character numbers (`.chr`) match your graphics sheet
### Sprite Behaves Incorrectly
* Check that timers are being set and checked correctly
* Verify state transitions in the jump table
* Ensure `Sprite_CheckActive` is called before main logic
* Check that collision functions are being called in the right order
### Performance Issues
* Reduce `!NbrTiles` if using too many tiles
* Optimize drawing routine (avoid redundant calculations)
* Use simpler collision detection where possible
* Consider using `!Persist = 00` for non-critical sprites
## 10. Advanced Sprite Design Patterns
## 10. Advanced Sprite Design Patterns
### 10.1. Multi-Part Sprites and Child Sprites
For complex bosses or entities, break them down into a main parent sprite and multiple child sprites. Examples include Kydreeok (body + heads), Darknut (knight + probes), Goriya (enemy + boomerang), and Helmet Chuchu (body + detachable helmet).
**Parent Sprite Responsibilities:**
* Spawns and manages child sprites using `Sprite_SpawnDynamically`
* Stores child sprite IDs in global variables or `SprMisc` slots
* Monitors child sprite states to determine phases or defeat conditions
* Handles overall movement, phase transitions, and global effects
**Child Sprite Responsibilities:**
* Handles independent logic, movement, and attacks
* May be positioned relative to parent sprite
* Uses `SprSubtype` to differentiate between multiple instances
**Example: Kydreeok Boss**
```asm
; In Kydreeok body sprite
SpawnLeftHead:
{
LDA #$CF ; Kydreeok Head sprite ID
JSL Sprite_SpawnDynamically : BMI .return
TYA : STA.w Offspring1_Id ; Store child ID globally
LDA.b #$00 : STA.w SprSubtype, Y ; Subtype 0 = left head
; Position relative to parent
REP #$20
LDA.w SprCachedX : SEC : SBC.w #$0010
SEP #$20
STA.w SprX, Y : XBA : STA.w SprXH, Y
; ... more initialization
.return
RTS
}
; Check if all heads are defeated
Sprite_Kydreeok_CheckIfDead:
{
LDA.w Offspring1_Id : TAY
LDA.w SprState, Y : BNE .not_dead ; Check if left head alive
LDA.w Offspring2_Id : TAY
LDA.w SprState, Y : BNE .not_dead ; Check if right head alive
; All heads defeated - trigger death sequence
.not_dead
RTS
}
```
**Shared Sprite IDs for Variations:**
A single sprite ID can represent different enemy types using `SprSubtype`:
* Keese sprite ID shared by: Regular Keese, Fire Keese, Ice Keese, Vampire Bat
* Mermaid sprite ID ($F0) shared by: Mermaid, Maple, Librarian (all using different subtypes)
* This efficiently reuses sprite slots and base logic
### 10.2. Quest Integration and Dynamic Progression
Boss fights and NPC interactions can be deeply integrated with quest progression using SRAM flags, dynamic health management, and multi-phase battles.
**Phase Transitions:**
Trigger new phases based on health thresholds, timers, or child sprite states:
```asm
; Check health threshold for phase change
LDA.w SprHealth, X : CMP.b #$10 : BCS .phase_one
LDA.w SprMiscD, X : CMP.b #$02 : BEQ .already_phase_two
LDA.b #$02 : STA.w SprMiscD, X ; Switch to phase 2
JSR LoadPhase2Graphics
JSR SpawnPhase2Adds
.already_phase_two
.phase_one
```
**Health Management:**
* **Direct Health:** Use `SprHealth` for straightforward health tracking
* **Indirect Health:** Base defeat on child sprite states (e.g., Kydreeok defeated when all heads are killed)
* **Phase-Based Health:** Refill health between phases for extended boss fights
* **Dynamic Scaling:** Adjust health based on Link's sword level or progression
**Quest Integration Examples:**
* **Wolfos:** After being subdued, plays Song of Healing animation and grants Wolf Mask
* **Bug Net Kid:** Dialogue changes based on whether Link has the Bug Net
* **Maple:** Spawns items and interacts with Link differently based on quest flags
* **Mask Salesman:** Complex shop system with inventory checks and rupee deduction
* **Zora Princess:** Quest rewards and dialogue conditional on SRAM flags
**SRAM Flag Usage:**
```asm
; Check if quest item has been obtained
LDA.l $7EF3XX : CMP.b #$XX : BNE .not_obtained
; Quest item obtained - change behavior
%ShowUnconditionalMessage(MessageID)
JMP .quest_complete
.not_obtained
```
### 10.4. Code Reusability and Best Practices
**Shared Logic Functions:**
Create reusable functions for common behaviors across multiple sprites:
```asm
; Shared by Goriya and Darknut
Goriya_HandleTileCollision:
{
JSL Sprite_CheckTileCollision
LDA.w SprCollision, X : BEQ .no_collision
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X
STA.w SprMiscE, X
%SetTimerC(60)
.no_collision
RTS
}
```
**Named Constants:**
Always use named constants instead of magic numbers:
```asm
; Good
GoriyaMovementSpeed = 10
MinecartSpeed = 20
DoubleSpeed = 30
LDA.b #GoriyaMovementSpeed : STA.w SprXSpeed, X
; Bad
LDA.b #10 : STA.w SprXSpeed, X ; What does 10 mean?
```
**Processor Status Management:**
Explicitly manage 8-bit/16-bit modes:
```asm
REP #$20 ; 16-bit accumulator
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
SEP #$20 ; Back to 8-bit
```
**State Machine Pattern:**
Use `SprAction` with jump tables for clear state management:
```asm
Sprite_Enemy_Main:
{
%SpriteJumpTable(State_Idle, State_Chase, State_Attack, State_Retreat)
State_Idle: { /* ... */ RTS }
State_Chase: { /* ... */ RTS }
State_Attack: { /* ... */ RTS }
State_Retreat: { /* ... */ RTS }
}
```
**Timer Management:**
Use different timers for different purposes:
* `SprTimerA` - State transitions, cooldowns
* `SprTimerB` - Animation (automatically used by `%PlayAnimation`)
* `SprTimerC` - Movement changes, direction changes
* `SprTimerD` - Attack cooldowns
* `SprTimerE` - Special effects
* `SprTimerF` - Gravity/altitude (decrements by 2)
### 10.5. Centralized Handlers and Multi-Purpose Sprites
Many sprite files serve as central handlers for multiple distinct entities, using conditional logic to dispatch behaviors.
**Examples:**
* **Followers** (`followers.asm`) - Zora Baby, Old Man, Kiki
* **Mermaid** (`mermaid.asm`) - Mermaid (subtype 0), Maple (subtype 1), Librarian (subtype 2)
* **Zora** (`zora.asm`) - Various Zora NPCs with different roles
* **Collectible** (`collectible.asm`) - Different collectible items
* **Deku Leaf** (`deku_leaf.asm`) - Deku Leaf and Beach Whirlpool
**Implementation Pattern:**
```asm
Sprite_MultiPurpose_Long:
{
PHB : PHK : PLB
; Dispatch based on subtype
LDA.w SprSubtype, X
JSL JumpTableLocal
dw Type0_Routine
dw Type1_Routine
dw Type2_Routine
Type0_Routine:
JSR Type0_Draw
JSR Type0_Main
PLB : RTL
Type1_Routine:
JSR Type1_Draw
JSR Type1_Main
PLB : RTL
}
```
### 10.6. Overriding Vanilla Sprites
To replace vanilla sprite behavior while keeping the original sprite ID:
```asm
; In a patch file or at the start of your sprite file
pushpc
org $069283+($XX*2) ; Replace vanilla main pointer
dw NewCustomBehavior_Main
org $06865B+($XX*2) ; Replace vanilla prep pointer
dw NewCustomBehavior_Prep
pullpc
NewCustomBehavior_Main:
{
; Check if custom behavior should activate
LDA.l $7EF3XX : CMP.b #$YY : BNE .use_vanilla
JSL CustomImplementation_Long
RTS
.use_vanilla
JML $OriginalVanillaAddress
}
```
### 10.7. Interactive Objects and Environmental Triggers
**Player-Manipulated Objects:**
Objects like Ice Block and Minecart require precise collision and alignment:
```asm
; Round position to 8-pixel grid for proper alignment
RoundCoords:
{
LDA.b $00 : CLC : ADC.b #$04 : AND.b #$F8 : STA.b $00 : STA.w SprY, X
LDA.b $02 : CLC : ADC.b #$04 : AND.b #$F8 : STA.b $02 : STA.w SprX, X
JSR UpdateCachedCoords
RTS
}
```
**Environmental Triggers:**
Switch objects respond to player actions and modify game state:
```asm
; Mine switch changes track configuration
Sprite_Mineswitch_OnActivate:
{
LDA.w SprMiscA, X : BEQ .currently_off
; Switch is on, turn it off
STZ.w SprMiscA, X
JSR UpdateTrackTiles_Off
JMP .done
.currently_off
; Switch is off, turn it on
LDA.b #$01 : STA.w SprMiscA, X
JSR UpdateTrackTiles_On
.done
%PlaySFX2($14) ; Switch sound
RTS
}
```
### 10.8. Shop and Item Management
**Transaction System:**
```asm
Shopkeeper_SellItem:
{
; Check if player has enough rupees
REP #$20
LDA.l $7EF360 : CMP.w #ItemCost : BCC .not_enough
; Deduct rupees
SEC : SBC.w #ItemCost : STA.l $7EF360
SEP #$20
; Grant item
LDA.b #ItemID : STA.l $7EF3XX
%ShowUnconditionalMessage(ThankYouMessage)
RTS
.not_enough
SEP #$20
%ErrorBeep()
%ShowUnconditionalMessage(NotEnoughRupeesMessage)
RTS
}
```
**Item Granting with Quest Tracking:**
```asm
NPC_GrantQuestItem:
{
; Check if already received
LDA.l $7EF3XX : BNE .already_obtained
; Grant item
LDA.b #$01 : STA.l $7EF3XX
LDA.b #ItemID
JSL Link_ReceiveItem
%ShowUnconditionalMessage(ItemReceivedMessage)
RTS
.already_obtained
%ShowUnconditionalMessage(AlreadyHaveMessage)
RTS
}
```
### 10.9. Player State Manipulation
For cinematic sequences and special interactions:
```asm
Cutscene_LinkSleep:
{
; Prevent player input
%PreventPlayerMovement()
; Set Link's animation
LDA.b #$XX : STA.w LinkAction
; Play sleep animation
LDA.b #$XX : STA.w LinkGraphics
; Wait for timer
LDA.w SprTimerA, X : BNE .still_waiting
%AllowPlayerMovement()
%GotoAction(NextState)
.still_waiting
RTS
}
```
### 10.10. Error Handling and Player Feedback
**Robust Error Prevention:**
```asm
; Portal sprite checks for valid placement
Sprite_Portal_CheckValidTile:
{
LDA.w CurrentTileType : CMP.b #ValidTileMin : BCC .invalid
CMP.b #ValidTileMax : BCS .invalid
CMP.b #$XX : BEQ .invalid ; Check specific invalid tiles
; Valid placement
SEC
RTS
.invalid
%ErrorBeep()
STZ.w SprState, X ; Despawn sprite
CLC
RTS
}
```
**Clear Player Feedback:**
```asm
; Provide audio/visual feedback
%ErrorBeep() ; Sound for errors
%PlaySFX1($14) ; Sound for success
JSL Sprite_ShowMessageUnconditional ; Text feedback
```
## 11. Additional Resources
**Core Files:**
* `Core/sprite_macros.asm` - All available macros and their implementations
* `Core/sprite_functions.asm` - Reusable sprite functions
* `Core/sprite_new_table.asm` - Sprite table initialization
* `Core/symbols.asm` - RAM address definitions
* `Core/structs.asm` - Sprite structure definitions
**Documentation:**
* `Docs/Sprites/` - Detailed documentation for existing sprites
* `Docs/Sprites/Overlords.md` - Overlord system documentation
* `Sprites/all_sprites.asm` - See how sprites are organized and included
**Example Sprites:**
* **Simple Enemy:** `Sprites/Enemies/sea_urchin.asm` - Basic enemy with minimal logic
* **Advanced Enemy:** `Sprites/Enemies/booki.asm` - Dynamic AI with state management
* **Boss:** `Sprites/Bosses/kydreeok.asm` - Multi-part boss with child sprites
* **Interactive Object:** `Sprites/Objects/minecart.asm` - Complex player interaction
* **NPC:** `Sprites/NPCs/mask_salesman.asm` - Shop system and dialogue

View File

@@ -0,0 +1,48 @@
# BG Color / Overlay Regression — Resolved (March 2026)
## Resolution Summary
The "Too Bright" and "Flash to Day" bugs have been resolved by fixing the register management in `ZSCustomOverworld.asm`.
**The Problem:**
When transitioning from an area with an overlay (like Rain/Storms) to an area without one (Overlay ID `$FF`), the code cleared the Subscreen Enable register (`$1D`) but **failed to clear the Color Math Control register (`$9A`)**.
- Rain sets `$9A` to `$72` (Additive Math).
- If `$9A` remains `$72` in a normal area, the SNES PPU continues to perform additive color math using the Fixed Color registers (`$9C`/`$9D`).
- This caused the background to appear significantly brighter (approx +6 per channel), turning the dark night tint into a "bright yellow-ish green".
- This also caused the "Flash to Day" effect during transitions, as the additive brightness kicked in immediately.
**The Fix:**
Modified `ZSCustomOverworld.asm` in two key locations to ensure `$9A` is always cleared when no overlay is present.
1. **Walking Transitions (`Overworld_ReloadSubscreenOverlay_Interupt`):**
Added a check for Overlay `$FF` to explicitly clear `$9A`. This prevents the brightness glitch during scrolling.
```asm
; In Overworld_ReloadSubscreenOverlay_Interupt
CPX.b #$FF : BNE .checkScroll
LDA.b #$00 ; Disable Color Math
BRA .loadOverlay
```
2. **Dungeon/Warp/Bird Transitions (`Overworld_LoadBGColorAndSubscreenOverlay`):**
Added `STZ.b $9A` to the block handling the `$FF` case. This prevents the glitch when exiting dungeons or warping.
```asm
; In Overworld_LoadBGColorAndSubscreenOverlay
CMP.w #$00FF : BNE .noCustomFixedColor
SEP #$30
STZ.b $9A ; FIX: Clear color math
; ...
```
## Verification
- **Brightness:** The background color in normal areas should now correctly reflect the Time System tint without extra brightness.
- **Transitions:** Walking from a Rain area to a Normal area should no longer result in a brightness jump.
- **Song of Storms:** Summoning and dismissing storms should work correctly, with the overlay and color math engaging and disengaging as expected.
## Technical Details
- **File:** `Overworld/ZSCustomOverworld.asm`
- **Routines:** `Overworld_LoadBGColorAndSubscreenOverlay`, `Overworld_ReloadSubscreenOverlay_Interupt`.
- **Registers:** `$1D` (Subscreen), `$9A` (CGADDSUB Mirror), `$9C`/`$9D` (COLDATA Mirrors).
## Outstanding Issues
- None related to BG Color Brightness.

View File

@@ -0,0 +1,45 @@
# Issue: Lost Woods Transition Coordinate Desync
## Status: Active / Low Priority
**Created:** March 2026
**Impact:** Visual/Gameplay discontinuity when exiting the Lost Woods (Area 0x29) back to the West (0x28).
## Problem Description
The custom Lost Woods puzzle uses a coordinate manipulation trick (`INC/DEC $21`, `INC/DEC $E7`) to simulate an infinite loop.
- **Symptoms:**
- When completing the puzzle (Exit East -> 0x2A), the fix implemented (`LostWoods_ResetCoordinates`) correctly snaps Link to the left edge of the new screen, preventing him from skipping the map.
- **Regression:** When *returning* to the previous map (Exit West -> 0x28), Link may appear at incorrect coordinates or the camera may be misaligned relative to the player.
- The "Snapping" logic forces Link's X/Y to the base of Area 0x29 (e.g., X=0x0200). However, the transition logic in `ZSCustomOverworld.asm` uses these coordinates to calculate the *destination* position in the new area. If the snap happens too early or incorrectly, the destination calculation (Start X - Offset) might underflow or misalign.
## Technical Analysis
### Custom Logic (`lost_woods.asm`)
The puzzle modifies:
- `$21` / `$23`: Link's High-Byte Coordinates (World Grid Position).
- `$E1` / `$E7` / `$E9`: Overlay and BG Scroll Registers.
This desynchronizes the "Visible" position from the "Logical" position expected by the standard Overworld engine.
### ZSOW Transition Logic
`OverworldHandleTransitions` in `ZSCustomOverworld.asm` relies on:
- `$20` / `$22`: Link's 16-bit absolute coordinates.
- `Pool_OverworldTransitionPositionX/Y`: Lookup tables for screen boundaries.
### Root Cause Hypothesis
1. **Coordinate Mismatch:** The `LostWoods_ResetCoordinates` routine snaps Link to `X=0x0200` (Left edge of 0x29).
2. **Transition Calc:** When moving West to 0x28, the engine expects Link to be crossing the boundary.
3. **Vanilla vs. Custom:** Vanilla ALTTP does not use infinite looping coordinates in the overworld. This mechanic is entirely custom and fights the static grid nature of the engine.
## Future Investigation Strategy (Reference `usdasm`)
1. **Vanilla Transitions:** Study `Bank02.asm` in `usdasm` to see how `Module09_Overworld` handles coordinate handoffs.
- Look for `Overworld_ScrollMap` and `Overworld_HandleCardinalCollision`.
2. **Camera Re-centering:** Search for routines that "center" the camera on Link after a transition (`Overworld_SetCameraBoundaries`). We may need to manually invoke this *after* the transition logic finishes, rather than snapping coordinates *before*.
3. **Scroll Register Reset:** Instead of zeroing `$E1` etc., we might need to recalculate them based on the *new* area's properties immediately upon load.
## Workaround
The bug is non-fatal. Players can navigate out of the area, though the visual transition may be jarring.
## Related Files
- `Overworld/lost_woods.asm`
- `Overworld/ZSCustomOverworld.asm`
- `usdasm/bank_02.asm` (Reference)

26
Docs/README.md Normal file
View File

@@ -0,0 +1,26 @@
# Oracle of Secrets Documentation
Welcome to the documentation for Oracle of Secrets. This directory is organized to help you find information about the project's architecture, systems, and content.
## Directory Structure
- `./General/`: High-level project information, including development guidelines and build instructions.
- `./Core/`: Documentation for the core engine components, such as memory maps, the player engine (`Link.md`), and system interaction analysis.
- `./Features/`: Detailed analysis of major gameplay features.
- `./Features/Items/`: Information on custom and modified items.
- `./Features/Masks/`: Details on the mask transformation system.
- `./Features/Menu/`: Analysis of the custom menu and HUD.
- `./Features/Music/`: Guide to the music system and composition workflow.
- `./World/`: Information about the game world's construction.
- `./World/Overworld/`: Documentation for the overworld engine, including `ZSCustomOverworld` and the time system.
- `./World/Dungeons/`: Details on dungeon mechanics and custom features.
- `./Sprites/`: Analysis of all sprite types, including bosses, NPCs, and interactive objects.
- `./Guides/`: Step-by-step guides and tutorials, such as the sprite creation guide and the main quest flowchart.
## Key Documents
- **`General/DevelopmentGuidelines.md`**: The primary guide for coding standards, architecture, and best practices. Start here to understand the project's philosophy.
- **`Core/MemoryMap.md`**: A comprehensive map of custom WRAM and SRAM variables.
- **`Guides/QuestFlow.md`**: A detailed walkthrough of the main story and side-quest progression.
- **`Guides/SpriteCreationGuide.md`**: A tutorial for creating new custom sprites.
- **`World/Overworld/ZSCustomOverworld.md`**: A deep dive into the data-driven overworld engine that powers the game world.

77
Docs/Sprites/Bosses.md Normal file
View File

@@ -0,0 +1,77 @@
# Bosses Analysis
This document provides an analysis of the boss sprites found in the `Sprites/Bosses/` directory. These sprites are typically complex, with multiple phases and unique behaviors.
## File Overview
| Filename | Sprite ID(s) | Description |
|---|---|---|
| `arrghus.asm` | (Hooks `$1EB593`) | A custom version of Arrghus that spawns fireballs. |
| `dark_link.asm` | `Sprite_DarkLink` (`$C1`) | A multi-phase boss fight against a shadow version of Link. |
| `king_dodongo.asm`| (Hooks `$1E811A`) | A custom version of King Dodongo with a new health system. |
| `kydreeok.asm` | `Sprite_Kydreeok` | A multi-headed sea monster boss. Parent sprite for `kydreeok_head.asm`. |
| `kydreeok_head.asm`| `Sprite_KydreeokHead` | The individual head of the Kydreeok boss, which can be attacked. |
| `kydrog.asm` | `Sprite_KydrogNPC` | A cutscene version of Kydrog that appears before the boss fight. |
| `kydrog_boss.asm` | `Sprite_KydrogBoss` | The main Kydrog boss fight, a large amphibious creature. |
| `lanmola.asm` | (Hooks `$05A377`) | A custom version of the Lanmola boss. |
| `lanmola_expanded.asm`| (Expansion) | Contains additional data and drawing logic for the custom Lanmola. |
| `manhandla.asm` | `Sprite_Manhandla` | A two-phase boss fight against Manhandla, which later becomes a Big Chuchu. |
| `octoboss.asm` | (Hooks `Sprite_A2_Kholdstare`) | A custom boss fight against two octopuses, replacing Kholdstare. |
| `twinrova.asm` | `Sprite_Twinrova` (`$CE`) | A custom boss fight replacing Blind the Thief with the twin witches, Koume and Kotake. |
| `vampire_bat.asm` | (Subtype of Keese) | A vampire bat mini-boss. |
| `wolfos.asm` | `Sprite_Wolfos` | A Wolfos mini-boss that guards the Wolf Mask. |
## Detailed Boss Analysis
### `dark_link.asm`
- **Sprite ID:** `Sprite_DarkLink` (`$C1`)
- **Summary:** A complex, multi-action boss that mimics Link's abilities. The fight has multiple stages, including a Ganon-like form.
- **Key Logic:**
- The main routine is a large state machine driven by `SprAction, X`.
- **Actions:** Includes standard walking, sword slashes, jump attacks, dodging, and using items like bombs and the Magic Cape.
- **AI:** The AI in the `Handler` routine decides which action to take based on the distance to the player. It can choose to slash, dodge, or use a special attack.
- **Enrage Mechanic:** At a certain health threshold (`SprHealth < $20`), the boss can enter an "enraged" state (`Enraging` action), which refills its health and makes its attacks faster.
- **Ganon Subtype:** If `SprSubtype` is 5, it uses Ganon's draw and main logic, acting as a final phase.
### `kydreeok.asm` / `kydreeok_head.asm`
- **Sprite IDs:** `Sprite_Kydreeok` (body), `Sprite_KydreeokHead` (head, ID `$CF`)
- **Summary:** A large, stationary sea monster boss with multiple heads that act as its weak points. The main body sprite (`Kydreeok`) is a controller that spawns and manages the head sprites.
- **Key Logic:**
- **`Kydreeok_Prep`:** Spawns two `KydreeokHead` sprites (`SpawnLeftHead`, `SpawnRightHead`).
- **`Kydreeok_Main`:** The body moves around the arena, and the heads follow its position, controlled via shared RAM addresses (`LeftNeck1_X`, etc.).
- **`KydreeokHead_Main`:** The heads have their own AI. They move in a rotational pattern and randomly shoot fireballs at the player.
- **Damage:** Only the head sprites can be damaged. When both heads are defeated, the main body sprite is killed.
### `manhandla.asm`
- **Sprite ID:** `Sprite_Manhandla` (`$88`)
- **Summary:** A two-phase boss. The first phase is a plant-like creature with three heads. The second phase is a large Big Chuchu.
- **Key Logic:**
- **Phase 1 (Manhandla):** The main body (`Manhandla_Body`) moves around the room, and three head sprites are spawned as offspring. The boss is only vulnerable when the heads are defeated.
- **Phase Transition:** When all three heads are killed, `Sprite_Manhandla_CheckForNextPhaseOrDeath` sets `SprMiscD` to 1, refills the boss's health, and transitions to the `BigChuchu_Emerge` action.
- **Phase 2 (Big Chuchu):** The sprite changes its appearance and behavior to that of a large slime. It moves around, spawns smaller slime projectiles (`Chuchu_SpawnBlast`), and has a central flower weak point.
### `octoboss.asm`
- **Sprite ID:** (Replaces `Sprite_A2_Kholdstare`)
- **Summary:** A custom boss fight featuring two octopus brothers who replace the vanilla Kholdstare boss.
- **Key Logic:**
- The fight begins when the player approaches, triggering the `Emerge` sequence.
- The first octopus spawns its brother (`SpawnAndAwakeHisBrother`), and they both don hats (`SpawnPirateHats`).
- The two sprites then move independently, attacking the player. Their total health is tracked via `ReturnTotalHealth`.
- When their combined health is low enough, they surrender (`WaitMessageBeforeSurrender`), remove their hats, and one submerges to give the player the Quake Medallion.
### `twinrova.asm`
- **Sprite ID:** `Sprite_Twinrova` (`$CE`, replaces Blind the Thief)
- **Summary:** A custom, multi-phase boss fight against the twin witches Koume (fire) and Kotake (ice). This sprite completely replaces the vanilla Blind the Thief boss, including the cutscene leading up to it.
- **Key Logic:**
- **Trigger:** The fight begins when the Blind Maiden follower is brought into the boss room. `Follower_CheckBlindTrigger` detects this, and `Blind_SpawnFromMaiden` despawns the maiden and spawns the Twinrova sprite.
- **Phase 1:** The combined Twinrova form moves around the room, alternating between fire (`Twinrova_FireAttack`) and ice (`Twinrova_IceAttack`) attacks.
- **Phase 2:** When health is low, the boss splits. The `Twinrova_MoveState` action will randomly choose between `KoumeMode` (fire) and `KotakeMode` (ice). In these modes, the boss has different attack patterns, including spawning Keese and changing the floor tiles.
### `wolfos.asm`
- **Sprite ID:** `Sprite_Wolfos`
- **Summary:** A mini-boss that guards the Wolf Mask. It is designed to be subdued rather than killed.
- **Key Logic:**
- The Wolfos attacks Link with lunges and swipes.
- When its health is depleted, `Sprite_Wolfos_CheckIfDefeated` transitions it to the `Wolfos_Subdued` action instead of killing it.
- In the subdued state, it waits for the player to play the Song of Healing (`SongFlag`).
- Once the song is played, it grants the Wolf Mask (`ITEMGET` ID `$10F`) and then despawns.

View File

@@ -0,0 +1,31 @@
# Dark Link Sprite Analysis
## Overview
Dark Link (Sprite ID: `$C1`) is a boss sprite known for its dynamic and challenging combat. It features a variety of attacks, including sword slashes, jump attacks, and projectile spawning. A notable aspect of this sprite is its ability to transform into a Ganon-like entity via a subtype, suggesting a multi-phase boss encounter.
## Key Properties:
* **Sprite ID:** `$C1`
* **Number of Tiles:** 4
* **Health:** 34 (decimal)
* **Damage:** 0 (Damage is handled by spawned attacks or direct contact logic, not directly by the sprite's `!Damage` property.)
* **Special Properties:**
* `!DeflectProjectiles = 01` (Deflects all projectiles)
* `!ImperviousArrow = 01` (Impervious to arrows)
* `!Boss = 00` (Despite being a boss, this flag is not set, indicating custom boss logic rather than reliance on vanilla boss flags.)
## Subtypes:
* **Subtype `$05` (Ganon):** This subtype completely alters Dark Link's behavior to that of a Ganon boss, executing `Sprite_Ganon_Main` and `Sprite_Ganon_Draw`. This mechanism allows for a multi-stage boss fight or an entirely different boss using the same sprite slot.
* **Subtype `$01` (Sword Damage):** This subtype is used for a temporary sprite spawned during Dark Link's sword attacks to handle collision and damage detection.
## In-Game Behavior:
Dark Link is an active and engaging boss. It moves strategically towards Link, performs various sword attacks (including a jump attack with screen shake), can utilize a cape for evasion, and throws bombs. It reacts to damage with visual recoil and flashing, and enters an "enraging" state (indicated by a red palette change) which likely alters its attack patterns or aggression. The Ganon subtype suggests a significant shift in combat during the fight.
## Original Sprite Replaced:
The code does not explicitly state which vanilla sprite `dark_link` replaces. However, the integration of `GanonInit` and Ganon-related logic strongly suggests it either heavily modifies an existing Ganon boss fight or is a completely new boss utilizing a custom sprite ID.
## Development Goals for Oracle of Secrets:
* **Variety in Attacks:** Introduce more diverse attack patterns and abilities to enhance the fight's complexity and challenge.
* **Unique Oracle of Secrets Attacks:** Implement attacks that are thematic and unique to the Oracle of Secrets project, moving beyond standard ALTTP boss mechanics.
## Code Quality Notes:
The code, while functional and effective in creating a competent boss, is noted to be somewhat "messy" due to its origin from Zarby89's ZScream project. This implies that while it works, future modifications might require careful navigation through its structure.

View File

@@ -0,0 +1,65 @@
# Kydreeok Sprite Analysis
## Overview
The `kydreeok` sprite (ID: `Sprite_Kydreeok`, which is `$7A`) represents the main Kydreeok boss. It orchestrates the entire boss fight, including spawning and managing its child head sprites (`kydreeok_head`), controlling its own movement phases, and handling its overall defeat. This is a multi-headed boss where the heads are separate sprites.
## Key Properties:
* **Sprite ID:** `Sprite_Kydreeok` (`$7A`)
* **Description:** The main Kydreeok boss, controlling the overall fight and its child heads.
* **Number of Tiles:** 8
* **Health:** `00` (The boss's health is managed through its child heads and custom logic, not directly by this sprite's `!Health` property.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its heads or custom logic.)
* **Special Properties:**
* `!Boss = 01` (This sprite is correctly identified as a boss.)
* `!Hitbox = $07`
## Main States/Actions (`Sprite_Kydreeok_Main` Jump Table):
The boss's behavior is divided into several phases:
* **`Kydreeok_Start` (0x00):** Initial state. Applies graphics and palette, prevents Link from passing through, and transitions to `Kydreeok_StageControl` after a timer. Stores its own sprite index in `Kydreeok_Id`.
* **`Kydreeok_StageControl` (0x01):** Manages the boss's movement stage, setting velocities and checking boundaries.
* **`Kydreeok_MoveXandY` (0x02):** Moves the boss in both X and Y directions towards Link, checking boundaries and handling damage.
* **`Kydreeok_MoveXorY` (0x03):** Moves the boss in either X or Y direction towards Link, checking boundaries and handling damage.
* **`Kydreeok_KeepWalking` (0x04):** Continues walking, with a random chance to transition to a flying state.
* **`Kydreeok_Dead` (0x05):** Handles the boss's death sequence, including visual effects (flickering, explosions) and eventually despawning the sprite.
* **`Kydreeok_Flying` (0x06):** The boss enters a flying state, moving towards Link at a set height, checking boundaries and handling damage.
## Initialization (`Sprite_Kydreeok_Prep`):
* Sets initial timers and movement speeds.
* Caches its own origin position.
* **Spawns its child heads:** Calls `JSR SpawnLeftHead` and `JSR SpawnRightHead`. A `SpawnCenterHead` routine is commented out, suggesting a potential for a three-headed boss.
* Initializes neck offsets to zero.
* Applies a custom palette (`JSR ApplyPalette`).
* Sets the boss theme music.
## Death and Respawn Logic (`Sprite_Kydreeok_CheckIfDead`, `MaybeRespawnHead`):
* **`Sprite_Kydreeok_CheckIfDead`:** This crucial routine checks the state of its child heads (`Offspring1_Id`, `Offspring2_Id`). If both heads are defeated, it triggers a "dead" phase, changes its graphics, respawns both heads, and then transitions to the `Kydreeok_Dead` state. This indicates a multi-phase boss where heads can be temporarily defeated.
* **`MaybeRespawnHead`:** Randomly respawns a head if its corresponding child sprite is dead, adding a dynamic challenge to the fight.
## Head Spawning (`SpawnLeftHead`, `SpawnRightHead`):
* These routines spawn `Sprite_KydreeokHead` (`$CF`) sprites.
* They assign `SprSubtype` to the spawned heads (`$00` for left, `$01` for right), allowing the child sprites to differentiate their behavior.
* They store the IDs of the spawned heads in global variables (`Offspring1_Id`, `Offspring2_Id`).
* They set the initial position of the heads relative to the main boss and initialize neck segment coordinates.
## Movement (`MoveBody`, `StopIfOutOfBounds`):
* **`MoveBody`:** Manages the main body's movement, calling `JSL Sprite_Move` and updating background scrolling based on its movement. It reuses logic from `Trinexx_MoveBody`.
* **`StopIfOutOfBounds`:** Prevents the boss from moving beyond screen boundaries. It also subtly adjusts the neck positions when hitting a boundary, creating a visual "pushing" effect.
## Palette Management (`ApplyPalette`, `ApplyEndPalette`):
* **`ApplyPalette`:** Sets the initial palette for the boss.
* **`ApplyEndPalette`:** Sets a different palette, likely for a defeated state or phase change.
## Graphics Transfer (`ApplyKydreeokGraphics`):
* Handles DMA transfer of graphics data (`kydreeok.bin`, `kydreeok_phase2.bin`) to VRAM, allowing for different graphical appearances across phases.
## Global Variables for Neck Control:
* `LeftNeck1_X` to `LeftNeck3_Y`, `RightNeck1_X` to `RightNeck3_Y`: Global RAM addresses used to store the coordinates of the neck segments, enabling the heads to track them.
* `Kydreeok_Id`: Stores the sprite index of the main Kydreeok boss.
* `Offspring1_Id`, `Offspring2_Id`: Store the sprite indices of the spawned heads.
## Discrepancies/Notes:
* The `!Health` and `!Damage` properties are `00`, confirming that the boss's health and damage are managed through its heads (`Sprite_KydreeokHead`) and custom logic within `Sprite_Kydreeok_CheckIfDead`.
* The `Sprite_Kydreeok_CheckIfDead` routine clearly defines a multi-phase fight where the heads can be defeated, respawned, and ultimately lead to the main boss's defeat.
* The commented-out `SpawnCenterHead` suggests a potential for a three-headed Kydreeok that was either removed or is an unimplemented feature.
* Reusing movement logic from `Trinexx_MoveBody` is efficient but should be considered for unique boss feel.
* Hardcoded addresses for `JSL` calls could be replaced with named labels for better maintainability.

View File

@@ -0,0 +1,68 @@
# Kydreeok Head Sprite Analysis
## Overview
The `kydreeok_head` sprite (ID: `Sprite_KydreeokHead`, which is `$CF`) is a child sprite of the main `Kydreeok` boss. It represents one of the multi-headed boss's individual heads, possessing independent movement, attack patterns, and damage handling. Its primary role is to move, rotate, and attack Link, contributing to the overall boss encounter.
## Key Properties:
* **Sprite ID:** `Sprite_KydreeokHead` (`$CF`)
* **Description:** Child sprite of the Kydreeok boss, responsible for individual head behavior.
* **Number of Tiles:** 7
* **Health:** `$C8` (200 decimal) - This high health value indicates it's a significant component of the boss fight.
* **Damage:** `00` (Damage is likely applied through its spawned attacks.)
* **Special Properties:**
* `!Boss = 00` (Not marked as a boss itself, as it's a component of a larger boss.)
* `!Hitbox = 09`
## Subtypes:
The `SprSubtype, X` register is crucial for differentiating the heads and their behavior:
* **Subtype `$00`:** Controls the "Left Head" via `Neck1_Control`.
* **Subtype `$01`:** Controls the "Right Head" via `Neck2_Control`.
This allows the same sprite ID to manage multiple distinct heads.
## Main States/Actions (`Sprite_KydreeokHead_Main` Jump Table):
The head's behavior is governed by a state machine:
* **`KydreeokHead_ForwardAnim` (0x00):** Default state, plays forward animation, handles damage, performs rotational movement, and randomly attacks. Transitions to other directional states based on Link's position.
* **`KydreeokHead_RightAnim` (0x01):** Plays right-facing animation, handles damage, rotation, and attacks.
* **`KydreeokHead_LeftAnim` (0x02):** Plays left-facing animation, handles damage, rotation, and attacks.
* **`KydreeokHead_FarRight` (0x03):** Plays far-right animation, moves towards Link, handles damage, rotation, and attacks.
* **`KydreeokHead_FarLeft` (0x04):** Plays far-left animation, moves towards Link, handles damage, rotation, and attacks.
* **`KydreeokHead_SummonFire` (0x05):** Moves towards Link, checks damage, and utilizes `JSL Sprite_Twinrova_FireAttack` to deal damage. The head sprite is then killed after a timer.
## Initialization (`Sprite_KydreeokHead_Prep`):
* Sets initial health to `$FF` (255 decimal), though the `!Health` property is `$C8`. This discrepancy might be overridden by the parent `Kydreeok` sprite or is a temporary value.
* Sets `SprBump = $09` (bump damage type).
* Initializes `SprMiscE, X` to `0`.
## Drawing (`Sprite_KydreeokHead_Draw`):
* Uses standard OAM allocation routines.
* The main drawing routine calls `JMP Sprite_KydreeokHead_DrawNeck`, indicating that the neck segments are drawn after the head.
* Includes logic for flashing when damaged.
## Neck Control (`KydreeokHead_NeckControl`, `Neck1_Control`, `Neck2_Control`, `Sprite_KydreeokHead_DrawNeck`, `DrawNeckPart`):
This is a sophisticated system for managing the multi-segmented neck:
* `KydreeokHead_NeckControl` dispatches to `Neck1_Control` (for the left head) or `Neck2_Control` (for the right head) based on `SprSubtype, X`.
* `Neck1_Control` and `Neck2_Control` manage the movement and positioning of three neck segments, ensuring they follow the head while maintaining specific distances.
* `Sprite_KydreeokHead_DrawNeck` and `DrawNeckPart` handle the rendering of these segments.
## Movement and Rotation (`KydreeokHead_RotationMove`, `RotateHeadUsingSpeedValues`, `MoveWithBody`):
* **`KydreeokHead_RotationMove`:** Generates random speeds, dispatches to neck control, moves with the main body, and applies rotational movement.
* **`RotateHeadUsingSpeedValues`:** Uses sine/cosine tables (`XSpeedSin`, `YSpeedSin`) to apply smooth rotational movement.
* **`MoveWithBody`:** Ensures the head's position is correctly offset and relative to the main `Kydreeok` boss, adjusting for left or right heads.
## Attacks (`RandomlyAttack`, `KydreeokHead_SummonFire`):
* **`RandomlyAttack`:** Randomly spawns a fire-based projectile (which is actually the `Sprite_KydreeokHead` itself entering the `SummonFire` state).
* **`KydreeokHead_SummonFire`:** This state is entered when a fire projectile is spawned. It moves towards Link and uses `JSL Sprite_Twinrova_FireAttack` to deal damage, after which the head sprite is killed.
## Key Macros/Functions Used:
* `%Set_Sprite_Properties`, `%GotoAction`, `%StartOnFrame`, `%PlayAnimation`, `%MoveTowardPlayer`
* `JSL JumpTableLocal`, `JSL Sprite_CheckDamageFromPlayer`, `JSL Sprite_CheckDamageToPlayer`, `JSL Sprite_DamageFlash_Long`
* `JSL GetRandomInt`, `JSL Sprite_MoveLong`, `JSL Sprite_IsToRightOfPlayer`
* `JSL Sprite_SpawnDynamically`, `JSL Sprite_SetSpawnedCoords`
* `JSL Sprite_Twinrova_FireAttack`, `JSL Fireball_SpawnTrailGarnish`
* `JSR GetDistance8bit`
## Discrepancies/Notes:
* The `!Health` property is `$C8`, but `Sprite_KydreeokHead_Prep` sets `SprHealth, X` to `$FF`. This needs clarification.
* The reuse of `JSL Sprite_Twinrova_FireAttack` for Kydreeok's head is an example of code reuse, but it's important to ensure it fits the thematic design of Kydreeok.
* The neck control system is quite intricate, highlighting advanced sprite design.
* Several hardcoded addresses for `JSL` calls could be replaced with named labels for better maintainability.

View File

@@ -0,0 +1,90 @@
# Kydrog Boss Sprite Analysis
## Overview
The `kydrog_boss` sprite (ID: `Sprite_KydrogBoss`, which is `$CB`) represents the main Kydrog boss. This boss features multiple phases, dynamic movement, and the ability to summon stalfos offspring. It's a complex encounter designed to challenge the player through varied attack patterns and phase transitions.
## Key Properties:
* **Sprite ID:** `Sprite_KydrogBoss` (`$CB`)
* **Description:** The main Kydrog boss, controlling its own movement, phases, and spawning stalfos offspring.
* **Number of Tiles:** 11
* **Health:** `00` (The boss's health is managed through `CheckForNextPhase` and `Sprite_KydrogBoss_CheckIfDead`, not directly by this property.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks or spawned offspring.)
* **Special Properties:**
* `!Boss = $01` (Correctly identified as a boss.)
* `!Shadow = 01` (Draws a shadow.)
* `!Hitbox = 03`
## Custom Variables:
* `!ConsecutiveHits = $AC`: Tracks consecutive hits on the boss, influencing its behavior.
* `!KydrogPhase = $7A`: Manages the current phase of the boss fight.
* `!WalkSpeed = 10`: Defines the boss's walking speed.
## Main States/Actions (`Sprite_KydrogBoss_Main` Jump Table):
The boss's behavior is governed by a detailed state machine:
* **`KydrogBoss_Init` (0x00):** Initial state, plays an "Arms Crossed" animation, and transitions to `KydrogBoss_WalkState` after an intro timer.
* **`KydrogBoss_WalkState` (0x01):** The primary walking state. Manages phase transitions, handles damage, taunting, and determines the next walking direction (forward, backward, left, right) based on Link's position and proximity.
* **`KydrogBoss_WalkForward` (0x02), `KydrogBoss_WalkLeft` (0x03), `KydrogBoss_WalkRight` (0x04), `KydrogBoss_WalkBackward` (0x05):** These states handle movement in specific directions, playing corresponding animations and executing core movement logic.
* **`KydrogBoss_TakeDamage` (0x06):** Manages the boss taking damage. Increments `!ConsecutiveHits`, plays a damage animation, spawns stalfos offspring, and can trigger an ascend action.
* **`KydrogBoss_TauntPlayer` (0x07):** Plays a taunting animation, handles damage, and transitions to `KydrogBoss_SummonStalfos`.
* **`KydrogBoss_SummonStalfos` (0x08):** Plays a summoning animation, handles damage, spawns stalfos offspring, and can throw a bone projectile at Link.
* **`KydrogBoss_Death` (0x09):** Handles the boss's death sequence, including killing spawned friends, playing a flickering animation, and despawning.
* **`KydrogBoss_Ascend` (0x0A):** The boss ascends off-screen, increasing its `SprHeight` and spawning stalfos offspring. Transitions to `KydrogBoss_Descend`.
* **`KydrogBoss_Descend` (0x0B):** The boss descends, tracking Link's position, decreasing its `SprHeight`, and spawning stalfos offspring. Transitions back to `KydrogBoss_WalkState`.
* **`KydrogBoss_Abscond` (0x0C):** The boss moves away from Link, increasing its speed, and transitions back to `KydrogBoss_WalkState`.
## Initialization (`Sprite_KydrogBoss_Prep`):
* Initializes `!KydrogPhase` to `00`.
* Sets initial health to `$A0` (160 decimal).
* Configures deflection (`SprDefl`), hitbox (`SprHitbox`), and bump damage (`SprBump`).
* Sets `SprGfxProps` to not invincible.
* Calls `JSR KydrogBoss_Set_Damage` to define its damage vulnerabilities.
* Sets initial sprite speeds and `!Harmless = 00`.
* Sets an intro timer (`SprTimerD = $80`).
## Death Check (`Sprite_KydrogBoss_CheckIfDead`):
* Monitors `SprHealth, X`. If health is zero or negative, it triggers the boss's death sequence, setting `SprState = $04` (kill sprite boss style) and `SprAction = $09` (KydrogBoss_Death stage).
## Phase Management (`CheckForNextPhase`):
This routine dynamically manages the boss's phases based on its current health:
* **Phase One (`!KydrogPhase = $00`):** Transitions to Phase Two when health drops below `$20`.
* **Phase Two (`!KydrogPhase = $01`):** Transitions to Phase Three when health drops below `$20`. Resets health to `$80`, sets action to `KydrogBoss_WalkState`, and increments `SprFlash, X`.
* **Phase Three (`!KydrogPhase = $02`):** Transitions to Phase Four when health drops below `$20`. Resets health to `$80`, sets action to `KydrogBoss_WalkState`.
* **Phase Four (`!KydrogPhase = $03`):** Sets action to `KydrogBoss_WalkState`.
## Damage Table (`KydrogBoss_Set_Damage`):
* Defines how KydrogBoss reacts to various attack types (Boomerang, Sword, Arrow, Bomb, etc.), stored in a damage properties table.
## Offspring Spawning (`RandomStalfosOffspring`, `Sprite_Offspring_Spawn`, `Sprite_Offspring_SpawnHead`):
* **`RandomStalfosOffspring`:** Randomly spawns either a normal stalfos offspring (`Sprite_Offspring_Spawn`) or a stalfos head offspring (`Sprite_Offspring_SpawnHead`), with a limit of 4 active stalfos.
* **`Sprite_Offspring_Spawn`:** Spawns a stalfos offspring (Sprite ID `$A7` or `$85`).
* **`Sprite_Offspring_SpawnHead`:** Spawns a stalfos head offspring (Sprite ID `$7C` or `$02`).
## Attacks (`Kydrog_ThrowBoneAtPlayer`):
* **`Kydrog_ThrowBoneAtPlayer`:** Spawns a bone projectile (Sprite ID `$A7`) that moves towards Link.
## Movement (`KydrogBoss_DoMovement`, `BounceBasedOnPhase`):
* **`KydrogBoss_DoMovement`:** Handles damage checks, applies damage to Link on contact, flashes when damaged, and incorporates phase-based bouncing and stalfos spawning.
* **`BounceBasedOnPhase`:** Adjusts the boss's bounce speed based on the current `!KydrogPhase`.
## Drawing (`Sprite_KydrogBoss_Draw`):
* Uses standard OAM allocation routines.
* Handles complex animation frames, x/y offsets, character data, properties, and sizes for drawing the boss.
* Utilizes 16-bit operations (`REP #$30`, `SEP #$30`) for precise drawing calculations.
## Other Routines:
* **`StopIfTooClose()` macro:** Prevents the boss from getting too close to Link.
* **`Sprite_CheckIfFrozen`:** Checks if the sprite is frozen and unfreezes it after a timer.
* **`GetNumberSpawnStalfos`:** Counts the number of active stalfos offspring.
* **`SpawnSplash`:** Spawns a splash effect.
* **`SpawnBossPoof`:** Spawns a boss poof effect.
* **`HandleMovingSplash`:** Handles splash effects during movement.
* **`SpawnMedallion` / `SpawnMedallionAlt`:** Spawns a medallion.
## Discrepancies/Notes:
* The main boss's health is intricately managed through `SprHealth, X` and `!KydrogPhase`, requiring a clear understanding of their interplay.
* The stalfos offspring are spawned using specific sprite IDs, which should be cross-referenced for full understanding.
* Many hardcoded values for timers, speeds, and offsets could be replaced with named constants for improved readability and maintainability.
* The code includes direct calls to sound effect functions (`JSL $0DBB8A`) and a commented-out call to `JSL $01F3EC` (Light Torch), which might be a leftover or an unimplemented feature.
## Hardcoded Activation Trigger:
* As noted by the user, the activation trigger for KydrogBoss is hardcoded. Specifically, in the `WaitForPlayerToApproach` routine, the boss checks `LDA.b $20 : CMP #$08C8`. `$20` represents Link's Y position, and `$08C8` is a hardcoded Y-coordinate. This means the boss will only activate when Link reaches this specific Y-coordinate, making it difficult to relocate the boss to other overworld maps without modifying this value.

View File

@@ -0,0 +1,79 @@
# Manhandla / Big Chuchu Sprite Analysis
## Overview
The `manhandla` sprite (ID: `Sprite_Manhandla`, which is `$88`) is a multi-phase boss. It begins as Manhandla, a multi-headed plant-like enemy, and upon the defeat of its individual heads, it transforms into a Big Chuchu. This design creates a dynamic and evolving boss encounter.
## Key Properties:
* **Sprite ID:** `Sprite_Manhandla` (`$88`)
* **Description:** A multi-phase boss that transforms from Manhandla to Big Chuchu.
* **Number of Tiles:** 3
* **Health:** `00` (Health is managed by its spawned heads in the first phase and then by its own `SprHealth` in the second phase.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its heads or spawned projectiles.)
* **Special Properties:**
* `!Boss = 01` (Correctly identified as a boss.)
* `!DeathAnimation = 01` (Indicates custom death handling rather than a standard animation.)
* `!Hitbox = 00`
## Custom Variables:
* `Offspring1_Id`, `Offspring2_Id`, `Offspring3_Id`: Global variables used to track the sprite indices of the spawned Manhandla heads.
## Main States/Actions (`Sprite_Manhandla_Main` Jump Table):
The boss's behavior is governed by a detailed state machine across its phases:
* **`Manhandla_Intro` (0x00):** Initial state. Spawns the three Manhandla heads (`SpawnLeftManhandlaHead`, `SpawnRightManhandlaHead`, `SpawnCenterMandhandlaHead`) and transitions to `Manhandla_Body`.
* **`Manhandla_FrontHead` (0x01), `Manhandla_LeftHead` (0x02), `Manhandla_RightHead` (0x03):** These states are likely executed by the individual Manhandla head child sprites, managing their movement, damage, and contact with Link.
* **`BigChuchu_Main` (0x04):** The primary state for the Big Chuchu phase. Handles movement, damage, and can spawn Chuchu blasts.
* **`Flower_Flicker` (0x05):** A transitional state that flickers the background (BG2) and spawns a new `Sprite_Manhandla` (with `SprSubtype = $08`, representing the Big Chuchu head) after a timer, as part of the transformation.
* **`Manhandla_Body` (0x06):** The main state for the Manhandla body. Handles movement, damage, updates the positions of its spawned heads, and can spawn Mothula beams.
* **`BigChuchu_Emerge` (0x07):** Manages the emergence animation of the Big Chuchu.
* **`BigChuchu_Flower` (0x08):** A state for the Big Chuchu, possibly related to its visual appearance or an attack.
* **`BigChuchu_Dead` (0x09):** Handles the death sequence of the Big Chuchu.
* **`ChuchuBlast` (0x0A):** Manages the movement and damage of the spawned Chuchu blast projectile.
## Initialization (`Sprite_Manhandla_Prep`):
* Sets initial movement speeds and enables BG1 movement.
* Configures deflection properties (`SprDefl = $80`).
* Sets initial health to `$80`.
* Initializes `SprAction, X` based on `SprSubtype, X`.
## Phase Transition and Death Check (`Sprite_Manhandla_CheckForNextPhaseOrDeath`):
This critical routine orchestrates the boss's transformation:
* It checks if all three Manhandla heads (`Offspring1_Id`, `Offspring2_Id`, `Offspring3_Id`) are dead.
* If all heads are defeated, it triggers the transition to the Big Chuchu phase:
* Sets `SprMiscD, X = $01` (phase flag).
* Refills health (`SprHealth = $40`).
* Adjusts OAM entries (`SprNbrOAM = $08`).
* Sets `SprAction = $07` (BigChuchu_Emerge).
* It also manages the Big Chuchu's defeat, transitioning to `BigChuchu_Dead` when its health drops below `$04`.
## Head Spawning (`SpawnLeftManhandlaHead`, `SpawnRightManhandlaHead`, `SpawnCenterMandhandlaHead`):
* These routines spawn `Sprite_Manhandla` (`$88`) sprites as child heads.
* They assign specific `SprSubtype` values (`$03` for left, `$02` for right, `$01` for center) to differentiate the heads.
* They store the IDs of the spawned heads in global variables (`Offspring1_Id`, `Offspring2_Id`, `Offspring3_Id`).
* They set the initial position, health, and properties for each head.
## Head Positioning (`SetLeftHeadPos`, `SetRightHeadPos`, `SetCenterHeadPos`):
* These routines dynamically calculate and set the positions of the spawned heads relative to the main Manhandla body.
## Movement (`Sprite_Manhandla_Move`, `Manhandla_StopIfOutOfBounds`):
* **`Sprite_Manhandla_Move`:** The core movement logic for the Manhandla body, utilizing a jump table for `StageControl`, `MoveXandY`, `MoveXorY`, and `KeepWalking` states.
* **`Manhandla_StopIfOutOfBounds`:** Prevents the boss from moving beyond predefined screen boundaries.
## Attacks (`Chuchu_SpawnBlast`, `Mothula_SpawnBeams`):
* **`Chuchu_SpawnBlast`:** Spawns a Chuchu blast projectile (Sprite ID `$88` with `SprSubtype = $0A`).
* **`Mothula_SpawnBeams`:** Spawns beam projectiles (Sprite ID `$89`), called from `Manhandla_Body`.
## Drawing (`Sprite_Manhandla_Draw`, `Sprite_BigChuchu_Draw`):
* **`Sprite_Manhandla_Draw`:** Renders the Manhandla body and its heads.
* **`Sprite_BigChuchu_Draw`:** Renders the Big Chuchu form.
* Both utilize standard OAM allocation routines and handle animation frames, offsets, character data, properties, and sizes.
## Graphics and Palette (`ApplyManhandlaGraphics`, `ApplyManhandlaPalette`):
* **`ApplyManhandlaGraphics`:** Handles DMA transfer of graphics data (`manhandla.bin`) to VRAM.
* **`ApplyManhandlaPalette`:** Sets the custom palette for Manhandla.
## Discrepancies/Notes:
* The `!Health` property is `00`, indicating that the boss's health is managed by its heads in the first phase and then by its own `SprHealth` in the Big Chuchu phase.
* The `Sprite_Manhandla` ID (`$88`) is efficiently reused for the main boss, its heads, and the Chuchu blast projectile, with `SprSubtype` differentiating their roles.
* The reuse of `Mothula_SpawnBeams` for Manhandla is an example of code reuse.
* Hardcoded values for timers, speeds, and offsets could be replaced with named constants for improved readability and maintainability.
* A commented-out `org` for `Sprite_DoTheDeath#PrepareEnemyDrop.post_death_stuff` suggests potential modifications to the death routine.

View File

@@ -0,0 +1,254 @@
# Anti Kirby Sprite Analysis
## 1. Overview
The Anti Kirby sprite (`Sprite_AntiKirby`) is an enemy that exhibits unique behaviors, including a "suck" attack that can steal Link's items (bombs, arrows, rupees, or shield). It has distinct states for walking, sucking, being full (after stealing an item), and being "hatted" (presumably after Link gets his item back or a specific condition is met).
## 2. Sprite Properties
The sprite properties are defined at the beginning of `Sprites/Enemies/anti_kirby.asm`:
```asm
!SPRID = Sprite_AntiKirby
!NbrTiles = 02
!Harmless = 00
!HVelocity = 00
!Health = $08
!Damage = 04
!DeathAnimation = 00
!ImperviousAll = 00
!SmallShadow = 00
!Shadow = 01
!Palette = 00
!Hitbox = 03
!Persist = 00
!Statis = 00
!CollisionLayer = 00
!CanFall = 00
!DeflectArrow = 00
!WaterSprite = 00
!Blockable = 00
!Prize = 00
!Sound = 00
!Interaction = 00
!Statue = 00
!DeflectProjectiles = 00
!ImperviousArrow = 00
!ImpervSwordHammer = 00
!Boss = 00
```
**Key Observations:**
* `!SPRID = Sprite_AntiKirby`: This uses a named constant for the sprite ID, which is good practice.
* `!Health = $08`: Anti Kirby has 8 health points.
* `!Damage = 04`: Deals half a heart of damage to Link.
* `!Hitbox = 03`: A relatively small hitbox.
* `!Shadow = 01`: It draws a shadow.
* `!Boss = 00`: It is not classified as a boss sprite, despite its complex behavior.
## 3. Main Structure (`Sprite_AntiKirby_Long`)
This routine follows the standard structure for sprites, calling the draw routine, shadow routine, and then the main logic if the sprite is active.
```asm
Sprite_AntiKirby_Long:
{
PHB : PHK : PLB
JSR Sprite_AntiKirby_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_AntiKirby_Main
.SpriteIsNotActive
PLB
RTL
}
```
## 4. Initialization (`Sprite_AntiKirby_Prep`)
The `_Prep` routine initializes several sprite-specific variables and sets its `SprBump`, `SprHealth`, and `SprPrize` based on Link's current sword level (or a similar progression metric, inferred from `LDA.l Sword : DEC : TAY`). This is an interesting way to scale enemy difficulty.
```asm
Sprite_AntiKirby_Prep:
{
PHB : PHK : PLB
STZ.w SprDefl, X
STZ.w SprTileDie, X
STZ.w SprMiscB, X
LDA.l Sword : DEC : TAY
LDA .bump_damage, Y : STA.w SprBump, X
LDA .health, Y : STA.w SprHealth, X
LDA .prize_pack, Y : STA.w SprPrize, X
PLB
RTL
.bump_damage
db $81, $88, $88, $88
.health
db 06, 10, 20, 20
.prize_pack
db 6, 3, 3, 3
}
```
**Insight:** The use of `LDA.l Sword : DEC : TAY` to index into `.bump_damage`, `.health`, and `.prize_pack` tables demonstrates a dynamic difficulty scaling mechanism based on player progression (likely sword upgrades). This is a valuable pattern for making enemies adapt to the player's power level.
## 5. Main Logic & State Machine (`Sprite_AntiKirby_Main`)
The `_Main` routine implements a complex state machine using `JSL JumpTableLocal` and a series of `dw` (define word) entries pointing to different states.
```asm
Sprite_AntiKirby_Main:
{
JSL Sprite_IsToRightOfPlayer
TYA : CMP #$01 : BNE .WalkRight
.WalkLeft
LDA.b #$40 : STA.w SprMiscC, X
JMP +
.WalkRight
STZ.w SprMiscC, X
+
JSL Sprite_DamageFlash_Long
JSL Sprite_CheckIfRecoiling
LDA.w SprAction, X
JSL JumpTableLocal
dw AntiKirby_Main ; State 0: Normal movement/attack
dw AntiKirby_Hurt ; State 1: Recoiling from damage
dw AntiKirby_BeginSuck ; State 2: Initiating suck attack
dw AntiKirby_Sucking ; State 3: Actively sucking Link
dw AntiKirby_Full ; State 4: Full after stealing item
dw AntiKirby_Hatted ; State 5: Hatted (after Link gets item back?)
dw AntiKirby_HattedHurt ; State 6: Hatted and hurt
dw AntiKirby_Death ; State 7: Death animation
; ... (State implementations below) ...
}
```
**State Breakdown:**
* **`AntiKirby_Main` (State 0):**
* Checks health and transitions to `AntiKirby_Full` if health is low (this seems like a bug, should probably be `AntiKirby_Death`).
* Randomly initiates the `AntiKirby_BeginSuck` state.
* Plays walking animation (`%PlayAnimation(0, 2, 10)`).
* Handles damage from player and transitions to `AntiKirby_Hurt`.
* Deals damage to Link on contact (`%DoDamageToPlayerSameLayerOnContact()`).
* Moves toward Link (`%MoveTowardPlayer(8)`) and bounces from tile collisions.
* **`AntiKirby_Hurt` (State 1):** Plays a hurt animation and waits for a timer (`SprTimerA`) to expire before returning to `AntiKirby_Main`.
* **`AntiKirby_BeginSuck` (State 2):**
* Plays a "suck" animation (`%PlayAnimation(4, 5, 10)`).
* Checks for damage from player.
* Checks Link's proximity (`$0E`, `$0F` are likely relative X/Y coordinates to Link). If Link is close enough, it transitions to `AntiKirby_Sucking` and sets up a projectile speed towards Link.
* **`AntiKirby_Sucking` (State 3):**
* Plays a "sucking" animation (`%PlayAnimation(5, 5, 10)`).
* Uses `JSL Sprite_DirectionToFacePlayer` and `JSL DragPlayer` to pull Link towards it if he's close enough.
* If Link is very close, it "consumes" Link, storing Link's position in `SprMiscB` and `SprMiscA`, sets a timer, and transitions to `AntiKirby_Full`.
* **`AntiKirby_Full` (State 4):**
* Plays a "full" animation (`%PlayAnimation(10, 10, 10)`).
* Sets Link's position to the stored `SprMiscA`/`SprMiscB` (effectively "spitting" Link out).
* Transitions to `AntiKirby_Hatted` after a timer.
* **`AntiKirby_Hatted` (State 5):**
* Plays a "hatted" animation (`%PlayAnimation(6, 8, 10)`).
* Moves toward Link, deals damage, and handles damage from player (transitions to `AntiKirby_HattedHurt`).
* **`AntiKirby_HattedHurt` (State 6):** Plays a hurt animation for the "hatted" state and returns to `AntiKirby_Hatted`.
* **`AntiKirby_Death` (State 7):** Sets `SprState` to `$06` (likely a death state) and plays a sound effect.
**Insight:** The `AntiKirby_Main` state's health check `LDA.w SprHealth, X : CMP.b #$01 : BCS .NotDead : %GotoAction(4)` seems to incorrectly transition to `AntiKirby_Full` (State 4) instead of `AntiKirby_Death` (State 7) when health is 0. This might be a bug or an intentional design choice for a specific game mechanic.
## 6. Item Stealing Logic (`AntiKirby_StealItem`)
This is a separate routine that is likely called when Anti Kirby successfully "sucks" Link. It checks Link's inventory and steals a random item (bomb, arrow, rupee, or shield).
```asm
AntiKirby_StealItem:
{
REP #$20
; ... (collision checks) ...
SEP #$20
LDA.w SprTimerA, X : CMP.b #$2E : BCS .exit ; Timer check
JSL GetRandomInt
AND.b #$03
INC A
STA.w SprMiscG, X
STA.w SprMiscE, X
CMP.b #$01 : BNE .dont_steal_bomb
LDA.l $7EF343 : BEQ .dont_steal_anything ; Check bombs
DEC A
STA.l $7EF343
RTS
.dont_steal_anything
SEP #$20
STZ.w SprMiscG,X
RTS
.dont_steal_bomb
CMP.b #$02 : BNE .dont_steal_arrow
LDA.l $7EF377 : BEQ .dont_steal_anything ; Check arrows
DEC A
STA.l $7EF377
RTS
.dont_steal_arrow
CMP.b #$03 : BNE .dont_steal_rupee
REP #$20
LDA.l $7EF360 : BEQ .dont_steal_anything ; Check rupees
DEC A
STA.l $7EF360
.exit
SEP #$20
RTS
; -----------------------------------------------------
.dont_steal_rupee
LDA.l $7EF35A : STA.w SprSubtype, X : BEQ .dont_steal_anything ; Check shield
CMP.b #$03 : BEQ .dont_steal_anything
LDA.b #$00
STA.l $7EF35A
RTS
}
```
**Key Observations:**
* Uses `REP #$20` and `SEP #$20` to explicitly control the accumulator size (16-bit for address calculations, 8-bit for item counts). This is crucial for correct memory access.
* Randomly selects an item to steal using `JSL GetRandomInt : AND.b #$03 : INC A`.
* Directly modifies SRAM addresses (`$7EF343` for bombs, `$7EF377` for arrows, `$7EF360` for rupees, `$7EF35A` for shield) to decrement item counts or remove the shield.
* The shield stealing logic (`LDA.l $7EF35A : STA.w SprSubtype, X : BEQ .dont_steal_anything : CMP.b #$03 : BEQ .dont_steal_anything : LDA.b #$00 : STA.l $7EF35A`) is a bit convoluted. It seems to check the shield type and only steals if it's not a specific type (possibly the Mirror Shield, which is type 3).
**Insight:** The `AntiKirby_StealItem` routine is a good example of how to interact directly with Link's inventory in SRAM. It also highlights the importance of explicitly managing the processor status flags (`REP`/`SEP`) when dealing with mixed 8-bit and 16-bit operations, especially when accessing memory.
## 7. Drawing (`Sprite_AntiKirby_Draw`)
The drawing routine uses `JSL Sprite_PrepOamCoord` and `JSL Sprite_OAM_AllocateDeferToPlayer` for OAM management. It then uses a series of tables (`.start_index`, `.nbr_of_tiles`, `.x_offsets`, `.y_offsets`, `.chr`, `.properties`, `.sizes`) to define the sprite's animation frames and tile data.
```asm
Sprite_AntiKirby_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
LDA.w SprMiscC, X : STA $09
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
; ... (OAM manipulation logic) ...
.start_index
db $00, $01, $02, $03, $04, $05, $06, $08, $0A, $0C, $0E, $10
.nbr_of_tiles
db 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1
; ... (other OAM tables) ...
}
```
**Key Observations:**
* The drawing logic includes a check for `SprMiscC, X` to determine if the sprite is facing left or right, and uses different `.x_offsets` tables (`.x_offsets` vs `.x_offsets_2`) accordingly. This is a common pattern for horizontal flipping.
* The `.properties` table defines the palette, priority, and flip bits for each tile.
* The `.sizes` table defines the size of each tile (e.g., `$02` for 16x16).
## 8. Advanced Design Patterns Demonstrated
* **Dynamic Difficulty Scaling:** The `_Prep` routine adjusts health, bump damage, and prize based on `Link's Sword` level.
* **Complex State Machine:** The `_Main` routine uses a jump table to manage multiple distinct behaviors (walking, sucking, full, hatted, hurt, death).
* **Direct SRAM Interaction:** The `AntiKirby_StealItem` routine directly modifies Link's inventory in SRAM, demonstrating how to implement item-related mechanics.
* **Explicit Processor Status Management:** The `AntiKirby_StealItem` routine explicitly uses `REP #$20` and `SEP #$20` to ensure correct 8-bit/16-bit operations when accessing SRAM.
* **Conditional Drawing/Flipping:** The `_Draw` routine uses `SprMiscC, X` to conditionally flip the sprite horizontally.

View File

@@ -0,0 +1,290 @@
# Booki Sprite Analysis
This document provides a detailed analysis of the `booki.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Booki's fundamental characteristics:
```asm
!SPRID = Sprite_Booki
!NbrTiles = 02 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 00 ; Number of Health the sprite have (dynamically set in _Prep)
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` and `!Damage` are initially set to `00` but are dynamically determined during initialization.
## 2. Core Routines
### 2.1. `Sprite_Booki_Long` (Main Loop)
This is the primary entry point for Booki's per-frame execution, called by the game engine. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_Booki_Long:
{
PHB : PHK : PLB ; Set up bank registers
JSR Sprite_Booki_Draw ; Call drawing routine
JSL Sprite_DrawShadow ; Draw a shadow (if !Shadow is 01)
JSL Sprite_CheckActive : BCC .SpriteIsNotActive ; Check if sprite is active
JSR Sprite_Booki_Main ; If active, run main logic
.SpriteIsNotActive
PLB ; Restore bank register
RTL ; Return from long routine
}
```
### 2.2. `Sprite_Booki_Prep` (Initialization)
This routine is executed once when Booki is first spawned. It dynamically sets Booki's health based on Link's current sword level and initializes `SprMiscB`.
```asm
Sprite_Booki_Prep:
{
PHB : PHK : PLB
LDA.l Sword : DEC A : TAY ; Get Link's sword level (0-3), adjust to 0-indexed
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
STZ.w SprMiscB, X ; Initialize SprMiscB to 0
PLB
RTL
.health ; Health values for each sword level
db $04, $08, $10, $18 ; 4, 8, 16, 24 HP
}
```
### 2.3. `Sprite_Booki_Main` (Behavioral State Machine)
This routine manages Booki's AI through a state machine, using `SprAction, X` to determine the current behavior. It utilizes `JumpTableLocal` for efficient state transitions.
```asm
Sprite_Booki_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal ; Jump to the routine specified by SprAction
dw StalkPlayer ; State 0
dw HideFromPlayer ; State 1
dw HiddenFromPlayer ; State 2
dw ApproachPlayer ; State 3
StalkPlayer:
{
%PlayAnimation(0,1,16) ; Animate frames 0-1 every 16 frames
JSR Sprite_Booki_Move ; Handle movement
RTS
}
HideFromPlayer:
{
%PlayAnimation(0,4,16) ; Animate frames 0-4 every 16 frames
LDA.w SprTimerA, X : BNE + ; Check timer
INC.w SprAction, X ; If timer is 0, transition to HiddenFromPlayer
+
RTS
}
HiddenFromPlayer:
{
%PlayAnimation(4,4,16) ; Animate frame 4 every 16 frames (static)
JSR Sprite_Booki_Move ; Handle movement
JSL GetRandomInt : AND.b #$03 : BEQ + ; Random chance to transition
INC.w SprAction, X ; If random condition met, transition to ApproachPlayer
+
RTS
}
ApproachPlayer:
{
%PlayAnimation(5,9,16) ; Animate frames 5-9 every 16 frames
JSR Sprite_Booki_Move ; Handle movement
RTS
}
}
```
### 2.4. `Sprite_Booki_Move` (Movement and Interaction Logic)
This routine is called by the various states in `Sprite_Booki_Main` to handle Booki's physical interactions and movement. It also manages Booki's "float" behavior (`SlowFloat` or `FloatAway`) based on `SprMiscB`.
```asm
Sprite_Booki_Move:
{
JSL Sprite_Move ; Apply velocity
JSL Sprite_BounceFromTileCollision ; Handle collision with tiles
JSL Sprite_PlayerCantPassThrough ; Prevent player from passing through Booki
JSL Sprite_DamageFlash_Long ; Handle damage flashing
JSL Sprite_CheckIfRecoiling ; Check for recoil state
JSL Sprite_IsToRightOfPlayer : CPY.b #$01 : BNE .ToRight ; Determine if Booki is to the right of Link
LDA.b #$01 : STA.w SprMiscC, X ; Set SprMiscC to 1 (for horizontal flip)
JMP .Continue
.ToRight
STZ.w SprMiscC, X ; Set SprMiscC to 0 (no flip)
.Continue
JSL Sprite_CheckDamageToPlayer ; Check if Booki damages Link
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage ; Check if Link damages Booki
LDA.b #$01 : STA.w SprMiscB, X ; If damaged, set SprMiscB to 1 (FloatAway state)
.no_damage
LDA.w SprMiscB, X
JSL JumpTableLocal ; Jump to movement routine based on SprMiscB
dw SlowFloat ; SprMiscB = 0
dw FloatAway ; SprMiscB = 1
SlowFloat:
{
LDY #$04
JSL GetRandomInt : AND.b #$04 ; Introduce some randomness to movement
JSL Sprite_FloatTowardPlayer ; Float towards Link
PHX
JSL Sprite_DirectionToFacePlayer ; Update facing direction
; Check if too close to player
LDA.b $0E : CMP.b #$1A : BCS .NotTooClose
LDA.b $0F : CMP.b #$1A : BCS .NotTooClose
LDA.b #$01 : STA.w SprMiscB, X ; If too close, switch to FloatAway
LDA.b #$20 : STA.w SprTimerA, X ; Set timer
%GotoAction(1) ; Transition to HideFromPlayer state
.NotTooClose
PLX
RTS
}
FloatAway:
{
JSL GetRandomInt : AND.b #$04 ; Introduce some randomness to movement
JSL Sprite_FloatAwayFromPlayer ; Float away from Link
PHX
JSL Sprite_DirectionToFacePlayer ; Update facing direction
; Check if far enough from player
LDA.b $0E : CMP.b #$1B : BCC .NotTooClose
LDA.b #$1B : CMP.b $0F : BCC .NotTooClose ; Corrected comparison for $0F
LDA.b #$00 : STA.w SprMiscB, X ; If far enough, switch to SlowFloat
%GotoAction(0) ; Transition to StalkPlayer state
.NotTooClose
PLX
RTS
}
}
```
### 2.5. `Sprite_Booki_Draw` (Drawing Routine)
This routine is responsible for rendering Booki's graphics. It uses a custom OAM (Object Attribute Memory) allocation and manipulation logic rather than the `%DrawSprite()` macro. It dynamically determines the animation frame and applies horizontal flipping based on `SprMiscC`.
```asm
Sprite_Booki_Draw:
{
JSL Sprite_PrepOamCoord ; Prepare OAM coordinates
JSL Sprite_OAM_AllocateDeferToPlayer ; Allocate OAM slots, deferring to player
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY ; Calculate animation frame index
LDA .start_index, Y : STA $06 ; Store start index for tiles
LDA.w SprFlash, X : STA $08 ; Store flash status
LDA.w SprMiscC, X : STA $09 ; Store horizontal flip status (0 or 1)
PHX
LDX .nbr_of_tiles, Y ; Load number of tiles for current frame (minus 1)
LDY.b #$00 ; Initialize Y for OAM buffer offset
.nextTile
PHX ; Save current Tile Index
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset
ASL A : TAX ; Multiply by 2 for word access
REP #$20 ; Set A to 16-bit mode
LDA $00 : STA ($90), Y ; Store Y-coordinate
AND.w #$0100 : STA $0E ; Check if Y-coord is off-screen (high bit)
INY
LDA $02 : STA ($90), Y ; Store X-coordinate
CLC : ADC #$0010 : CMP.w #$0100 ; Check if X-coord is off-screen
SEP #$20 ; Set A to 8-bit mode
BCC .on_screen_y ; If on screen, continue
LDA.b #$F0 : STA ($90), Y ; If off-screen, move sprite off-screen
STA $0E
.on_screen_y
PLX ; Restore Tile Index
INY
LDA .chr, X : STA ($90), Y ; Store character (tile) number
INY
LDA.b $09 : BEQ .ToRight ; Check SprMiscC for horizontal flip
LDA.b #$29 : JMP .Prop ; If 1, use properties for flipped
.ToRight
LDA.b #$69 ; If 0, use properties for normal
.Prop
ORA $08 : STA ($90), Y ; Apply flash and store OAM properties
PHY
TYA : LSR #2 : TAY ; Calculate OAM buffer index for size
LDA.b #$02 : ORA $0F : STA ($92), Y ; Store size (16x16) in OAM buffer
PLY : INY
PLX : DEX : BPL .nextTile ; Loop for next tile
PLX ; Restore X (sprite index)
RTS
; =========================================================
; OAM Data Tables
.start_index
db $00, $01, $02, $03, $04, $05, $06, $07, $08, $09
.nbr_of_tiles
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; All frames use 1 tile (0-indexed)
.chr
db $0E, $0C, $0A, $2C, $2E, $2E, $0A, $2C, $0C, $0E ; Tile numbers for each frame
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Health:** Booki's health is not a fixed property but is determined at spawn time based on Link's current sword level. This allows for dynamic difficulty scaling.
* **State Management:** Booki employs a robust state machine using `SprAction, X` and `JumpTableLocal` to manage its behaviors: `StalkPlayer`, `HideFromPlayer`, `HiddenFromPlayer`, and `ApproachPlayer`. Transitions between these states are triggered by timers, random chance, or player proximity.
* **Player Interaction:**
* **Stalking/Approaching:** Booki uses `Sprite_FloatTowardPlayer` to move towards Link.
* **Hiding/Floating Away:** Booki uses `Sprite_FloatAwayFromPlayer` to retreat from Link, often triggered by taking damage or getting too close.
* **Damage:** Booki can damage Link on contact (`Sprite_CheckDamageToPlayer`) and reacts to damage from Link by transitioning to a `FloatAway` state.
* **Directional Facing:** `SprMiscC, X` is used as a flag to control horizontal flipping in the drawing routine, ensuring Booki always faces Link.
* **Custom OAM Drawing:** Unlike many sprites that might use the `%DrawSprite()` macro, Booki implements its OAM drawing logic directly. This provides fine-grained control over its appearance, including dynamic tile selection and horizontal flipping. The `REP #$20` and `SEP #$20` instructions are used to temporarily switch the accumulator to 16-bit mode for coordinate calculations, demonstrating careful management of the Processor Status Register.
* **Randomness:** `GetRandomInt` is used to introduce variability in Booki's movement patterns and state transitions, making its behavior less predictable.
* **`SprMiscB` Usage:** This variable acts as a sub-state for movement, toggling between `SlowFloat` (approaching) and `FloatAway` (retreating) behaviors.
* **`SprTimerA` Usage:** Used in the `HideFromPlayer` state to control how long Booki remains in that state before transitioning.
* **`Sprite_PlayerCantPassThrough`:** Ensures Booki acts as a solid object that Link cannot simply walk through.

View File

@@ -0,0 +1,122 @@
# Business Scrub
## Overview
The Business Scrub is a custom enemy sprite that likely overrides a vanilla sprite ID. It is characterized by its low health and harmless contact damage, suggesting its primary threat comes from projectiles or other interactions defined within its main logic.
## Sprite Properties
* **`!SPRID`**: `$00` (Vanilla sprite ID, likely overridden)
* **`!NbrTiles`**: `$02`
* **`!Health`**: `$01`
* **`!Damage`**: `$00` (Harmless contact)
* **`!Harmless`**: `$00`
* **`!Hitbox`**: `$08`
* **`!ImperviousAll`**: `$00`
* **`!Statue`**: `$00`
* **`!Prize`**: `$00`
* **`!Boss`**: `$00`
* **Collision Properties**: All collision-related properties (`!Defl`, `!SprColl`, etc.) are set to `$00`, indicating that direct contact damage and knockback are not handled by these properties. Interaction and damage are likely managed within the sprite's main logic.
## Main Structure (`Sprite_BusinessScrub_Long`)
This routine is the main entry point for the Business Scrub, executed every frame. It sets up bank registers, calls the drawing routine, and then executes the main logic if the sprite is active.
```asm
Sprite_BusinessScrub_Long:
{
PHB : PHK : PLB
JSR Sprite_BusinessScrub_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_BusinessScrub_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_BusinessScrub_Prep`)
This routine runs once when the Business Scrub is spawned. It initializes the sprite's action state to `0` and sets a general-purpose timer (`SprTimerA`) to `120` frames (2 seconds).
```asm
Sprite_BusinessScrub_Prep:
{
PHB : PHK : PLB
%GotoAction(0)
%SetTimerA(120)
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_BusinessScrub_Main`)
The core behavior of the Business Scrub is managed by a state machine using `%SpriteJumpTable`. The current states are:
* **`State_Idle`**: The initial state where the scrub is idle. It plays an animation and checks for player proximity. If Link is within 80 pixels, it transitions to `State_Attacking`.
* **`State_Attacking`**: In this state, the scrub plays an attack animation, moves towards the player, and deals damage on contact. It also checks if it has been hit by the player and transitions to `State_Hurt` if so.
* **`State_Hurt`**: This state handles the sprite being hit, causing it to flash and be knocked back.
```asm
Sprite_BusinessScrub_Main:
{
%SpriteJumpTable(State_Idle, State_Attacking, State_Hurt)
State_Idle:
{
%PlayAnimation(0, 1, 15)
JSL GetDistance8bit_Long : CMP.b #$50 : BCS .player_is_far
%GotoAction(1)
.player_is_far
RTS
}
State_Attacking:
{
%PlayAnimation(2, 3, 8)
%MoveTowardPlayer(12)
%DoDamageToPlayerSameLayerOnContact()
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
%GotoAction(2)
.no_damage
RTS
}
State_Hurt:
{
JSL Sprite_DamageFlash_Long
RTS
}
}
```
## Drawing (`Sprite_BusinessScrub_Draw`)
The drawing routine uses the `%DrawSprite()` macro to render the sprite's graphics based on defined OAM data tables.
```asm
Sprite_BusinessScrub_Draw:
{
%DrawSprite()
.start_index
db $00, $02, $04, $06
.nbr_of_tiles
db 1, 1, 1, 1
.x_offsets
dw -8, 8, -8, 8, -8, 8, -8, 8
.y_offsets
dw -8, -8, -8, -8, -8, -8, -8, -8
.chr
db $C0, $C2, $C4, $C6, $C8, $CA, $CC, $CE
.properties
db $3B, $7B, $3B, $7B, $3B, $7B, $3B, $7B
}
```
## Design Patterns
* **State Machine**: Utilizes a clear state machine (`%SpriteJumpTable`) for managing different behaviors (Idle, Attacking, Hurt).
* **Player Interaction**: Incorporates distance checks (`GetDistance8bit_Long`) to trigger state changes and direct damage on contact (`DoDamageToPlayerSameLayerOnContact`).
* **Damage Handling**: Includes a basic damage reaction (`Sprite_CheckDamageFromPlayer`, `Sprite_DamageFlash_Long`).
* **Vanilla ID Override**: The use of `!SPRID = $00` suggests this sprite is intended to replace or modify the behavior of a vanilla sprite with ID $00.

View File

@@ -0,0 +1,328 @@
# Darknut Sprite Analysis
This document provides a detailed analysis of the `darknut.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Darknut's fundamental characteristics:
```asm
!SPRID = Sprite_Darknut
!NbrTiles = 03 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 12 ; Number of Health the sprite have (dynamically set in _Prep)
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 12 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is initially set to `12` but is dynamically determined during initialization based on Link's sword level. `!Damage` is `00`, implying damage is handled through other means (e.g., contact with Link's sword).
## 2. Core Routines
### 2.1. `Sprite_Darknut_Long` (Main Loop)
This is the primary entry point for Darknut's per-frame execution, called by the game engine. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_Darknut_Long:
{
PHB : PHK : PLB ; Set up bank registers
JSR Sprite_Darknut_Draw ; Call drawing routine
JSL Sprite_DrawShadow ; Draw a shadow (if !Shadow is 01)
JSL Sprite_CheckActive : BCC .SpriteIsNotActive ; Check if sprite is active
JSR Sprite_Darknut_Main ; If active, run main logic
.SpriteIsNotActive
PLB ; Restore bank register
RTL ; Return from long routine
}
```
### 2.2. `Sprite_Darknut_Prep` (Initialization)
This routine is executed once when Darknut is first spawned. It dynamically sets Darknut's health based on Link's current sword level, initializes `SprDefl` (deflection timer), and `SprTileDie` (tile for death animation).
```asm
Sprite_Darknut_Prep:
{
PHB : PHK : PLB
LDA.l $7EF359 : TAY ; Get Link's sword level (0-3), adjust to 0-indexed
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
LDA.b #$80 : STA.w SprDefl, X ; Initialize deflection timer
LDA.b #%01100000 : STA.w SprTileDie, X ; Set tile for death animation
PLB
RTL
.health ; Health values for each sword level
db $04, $06, $08, $0A ; 4, 6, 8, 10 HP
}
```
### 2.3. `Sprite_Darknut_Main` (Behavioral Logic)
This routine manages Darknut's AI, including probe spawning, parrying, movement, and animation. It uses `SprAction, X` to control its facing direction and animation.
```asm
Sprite_Darknut_Main:
{
JSL GetDistance8bit_Long : CMP.b #$80 : BCS .no_probe ; Check distance to Link
JSL Sprite_SpawnProbeAlways_long ; If close, spawn a probe
.no_probe
JSL Guard_ParrySwordAttacks ; Handle parrying Link's sword attacks
JSL Sprite_Move ; Apply velocity
JSL Sprite_BounceFromTileCollision ; Handle collision with tiles
JSL Sprite_DamageFlash_Long ; Handle damage flashing
JSL Sprite_CheckIfRecoiling ; Check for recoil state
JSL Sprite_CheckDamageFromPlayer : BCC .no_dano ; Check if Link damages Darknut
LDA.b #$FF : STA.w SprTimerD, X ; If damaged, set timer D
.no_dano
LDA.w SprTimerA, X : BEQ + ; Check timer A
LDA.b #$90 : STA.w SprTimerD, X ; If timer A is not 0, set timer D
+
LDA.w SprTimerD, X : BEQ ++ ; Check timer D
LDA.b #$08 : JSL Sprite_ApplySpeedTowardsPlayer ; Apply speed towards Link
JSL Sprite_DirectionToFacePlayer ; Update facing direction
TYA
STA.w SprMiscC, X ; Store facing direction in SprMiscC
STA.w SprMiscE, X ; Store facing direction in SprMiscE
STA.w SprAction, X ; Set SprAction to facing direction
JSL Guard_ChaseLinkOnOneAxis ; Chase Link along one axis
JMP +++
++
JSR Sprite_Darknut_BasicMove ; If no timers, use basic movement
+++
JSR Goriya_HandleTileCollision ; Handle tile collision (specific to Goriya, but used here)
LDA.w SprAction, X
JSL JumpTableLocal ; Jump to animation routine based on SprAction
dw FaceRight
dw FaceLeft
dw FaceDown
dw FaceUp
FaceUp:
{
%PlayAnimation(0,1,10) ; Animate frames 0-1 every 10 frames
RTS
}
FaceDown:
{
%StartOnFrame(2)
%PlayAnimation(2,3,10) ; Animate frames 2-3 every 10 frames
RTS
}
FaceLeft:
{
%StartOnFrame(4)
%PlayAnimation(4,5,10) ; Animate frames 4-5 every 10 frames
RTS
}
FaceRight:
{
%StartOnFrame(6)
%PlayAnimation(6,7,10) ; Animate frames 6-7 every 10 frames
RTS
}
}
```
### 2.4. `Sprite_Darknut_BasicMove` (Basic Movement Logic)
This routine defines Darknut's basic movement patterns, which are executed when no special conditions (like being damaged or timers) are active. It uses `SprAction, X` to determine the current movement direction.
```asm
Sprite_Darknut_BasicMove:
{
LDA.w SprAction, X
JSL JumpTableLocal ; Jump to movement routine based on SprAction
dw MoveRight
dw MoveLeft
dw MoveDown
dw MoveUp
MoveUp:
{
LDA.b #-DarknutSpeed : STA.w SprYSpeed, X ; Set Y-speed to negative (move up)
STZ.w SprXSpeed, X ; Clear X-speed
RTS
}
MoveDown:
{
LDA.b #DarknutSpeed : STA.w SprYSpeed, X ; Set Y-speed to positive (move down)
STZ.w SprXSpeed, X ; Clear X-speed
RTS
}
MoveLeft:
{
LDA.b #-DarknutSpeed : STA.w SprXSpeed, X ; Set X-speed to negative (move left)
STZ.w SprYSpeed, X ; Clear Y-speed
RTS
}
MoveRight:
{
LDA.b #DarknutSpeed : STA.w SprXSpeed, X ; Set X-speed to positive (move right)
STZ.w SprYSpeed, X ; Clear Y-speed
RTS
}
}
```
### 2.5. `Sprite_Darknut_Draw` (Drawing Routine)
This routine is responsible for rendering Darknut's graphics. It uses a custom OAM (Object Attribute Memory) allocation and manipulation logic, similar to Booki, to handle its multi-tile appearance and animation. It dynamically determines the animation frame and applies offsets for each tile.
```asm
Sprite_Darknut_Draw:
{
JSL Sprite_PrepOamCoord ; Prepare OAM coordinates
JSL Sprite_OAM_AllocateDeferToPlayer ; Allocate OAM slots, deferring to player
LDA.w SprGfx, X : CLC : ADC $0D90, X : TAY ; Calculate animation frame index
LDA .start_index, Y : STA $06 ; Store start index for tiles
LDA.w SprFlash, X : STA $08 ; Store flash status
PHX
LDX .nbr_of_tiles, Y ; Load number of tiles for current frame (minus 1)
LDY.b #$00 ; Initialize Y for OAM buffer offset
.nextTile
PHX ; Save current Tile Index
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset
ASL A : TAX ; Multiply by 2 for word access
REP #$20 ; Set A to 16-bit mode
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y ; Store Y-coordinate with X-offset
AND.w #$0100 : STA $0E ; Check if Y-coord is off-screen (high bit)
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y ; Store X-coordinate with Y-offset
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20 ; Set A to 8-bit mode
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ; If off-screen, move sprite off-screen
STA $0E
.on_screen_y
PLX ; Restore Tile Index
INY
LDA .chr, X : STA ($90), Y ; Store character (tile) number
INY
LDA .properties, X : ORA $08 : STA ($90), Y ; Apply flash and store OAM properties
PHY
TYA : LSR #2 : TAY ; Calculate OAM buffer index for size
LDA.w .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile ; Loop for next tile
PLX ; Restore X (sprite index)
RTS
; =========================================================
; OAM Data Tables
.start_index
db $00, $03, $06, $09, $0C, $0E, $10, $12
.nbr_of_tiles
db 2, 2, 2, 2, 1, 1, 1, 1
.x_offsets
dw 0, 0, 0
dw 0, 0, 0
dw 0, 0, 0
dw 0, 0, 0
dw 0, -12
dw 0, -12
dw 0, 12
dw 0, 12
.y_offsets
dw -4, 0, -12
dw -4, 0, -12
dw 0, 12, 20
dw 0, 12, 20
dw 0, 8
dw 0, 8
dw 0, 8
dw 0, 8
.chr
db $EF, $E6, $FF
db $EF, $E6, $FF
db $E2, $EF, $FF
db $E2, $EF, $FF
db $E0, $E8
db $E4, $E8
db $E0, $E8
db $E4, $E8
.properties
db $B9, $39, $B9
db $B9, $79, $B9
db $39, $39, $39
db $79, $39, $39
db $39, $79
db $39, $79
db $79, $39
db $79, $39
.sizes
db $00, $02, $00
db $00, $02, $00
db $02, $00, $00
db $02, $00, $00
db $02, $02
db $02, $02
db $02, $02
db $02, $02
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Health:** Darknut's health is determined at spawn time based on Link's current sword level, similar to Booki, allowing for dynamic difficulty scaling.
* **Probe Spawning:** Darknut has the ability to spawn a probe (`Sprite_SpawnProbeAlways_long`) when Link is within a certain distance, adding a ranged attack or detection mechanism.
* **Parrying Mechanics:** The `Guard_ParrySwordAttacks` routine suggests Darknut can actively defend against Link's sword attacks, potentially deflecting them or becoming temporarily invulnerable.
* **Chasing on One Axis:** When damaged or under certain timer conditions, Darknut uses `Guard_ChaseLinkOnOneAxis` to pursue Link along either the horizontal or vertical axis, making its movement more predictable but still challenging.
* **Basic Movement:** Darknut has a set of basic directional movements (`MoveUp`, `MoveDown`, `MoveLeft`, `MoveRight`) that it cycles through when not actively chasing or reacting to damage.
* **Custom OAM Drawing:** Darknut utilizes a custom OAM drawing routine, similar to Booki, to handle its multi-tile sprite. This routine precisely positions and animates multiple 8x8 tiles to form the larger Darknut sprite. The use of `REP #$20` and `SEP #$20` for 16-bit coordinate calculations is also present here.
* **`SprDefl` and `SprTileDie`:** `SprDefl` is used as a deflection timer, likely related to the parrying mechanic. `SprTileDie` specifies a custom tile to be used during its death animation.
* **`SprMiscC` and `SprMiscE`:** These variables are used to store Darknut's facing direction, which influences both its movement and animation. `SprMiscC` is likely used for animation frame selection, while `SprMiscE` might be used for other directional logic.
* **`Goriya_HandleTileCollision`:** The use of a collision handler named `Goriya_HandleTileCollision` suggests code reuse from another sprite, indicating a shared collision logic for certain enemy types.

View File

@@ -0,0 +1,122 @@
# Eon Scrub
## Overview
The Eon Scrub is a custom enemy sprite, likely a variation of the Business Scrub, that overrides a vanilla sprite ID. It shares similar characteristics with the Business Scrub, including low health and harmless contact damage, implying its primary threat comes from projectiles or other interactions defined within its main logic.
## Sprite Properties
* **`!SPRID`**: `$00` (Vanilla sprite ID, likely overridden)
* **`!NbrTiles`**: `$02`
* **`!Health`**: `$01`
* **`!Damage`**: `$00` (Harmless contact)
* **`!Harmless`**: `$00`
* **`!Hitbox`**: `$08`
* **`!ImperviousAll`**: `$00`
* **`!Statue`**: `$00`
* **`!Prize`**: `$00`
* **`!Boss`**: `$00`
* **Collision Properties**: All collision-related properties (`!Defl`, `!SprColl`, etc.) are set to `$00`, indicating that direct contact damage and knockback are not handled by these properties. Interaction and damage are likely managed within the sprite's main logic.
## Main Structure (`Sprite_EonScrub_Long`)
This routine is the main entry point for the Eon Scrub, executed every frame. It sets up bank registers, calls the drawing routine, and then executes the main logic if the sprite is active.
```asm
Sprite_EonScrub_Long:
{
PHB : PHK : PLB
JSR Sprite_EonScrub_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_EonScrub_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_EonScrub_Prep`)
This routine runs once when the Eon Scrub is spawned. It initializes the sprite's action state to `0` and sets a general-purpose timer (`SprTimerA`) to `120` frames (2 seconds).
```asm
Sprite_EonScrub_Prep:
{
PHB : PHK : PLB
%GotoAction(0)
%SetTimerA(120)
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_EonScrub_Main`)
The core behavior of the Eon Scrub is managed by a state machine using `%SpriteJumpTable`. The current states are:
* **`State_Idle`**: The initial state where the scrub is idle. It plays an animation and checks for player proximity. If Link is within 80 pixels, it transitions to `State_Attacking`.
* **`State_Attacking`**: In this state, the scrub plays an attack animation, moves towards the player, and deals damage on contact. It also checks if it has been hit by the player and transitions to `State_Hurt` if so.
* **`State_Hurt`**: This state handles the sprite being hit, causing it to flash and be knocked back.
```asm
Sprite_EonScrub_Main:
{
%SpriteJumpTable(State_Idle, State_Attacking, State_Hurt)
State_Idle:
{
%PlayAnimation(0, 1, 15)
JSL GetDistance8bit_Long : CMP.b #$50 : BCS .player_is_far
%GotoAction(1)
.player_is_far
RTS
}
State_Attacking:
{
%PlayAnimation(2, 3, 8)
%MoveTowardPlayer(12)
%DoDamageToPlayerSameLayerOnContact()
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
%GotoAction(2)
.no_damage
RTS
}
State_Hurt:
{
JSL Sprite_DamageFlash_Long
RTS
}
}
```
## Drawing (`Sprite_EonScrub_Draw`)
The drawing routine uses the `%DrawSprite()` macro to render the sprite's graphics based on defined OAM data tables.
```asm
Sprite_EonScrub_Draw:
{
%DrawSprite()
.start_index
db $00, $02, $04, $06
.nbr_of_tiles
db 1, 1, 1, 1
.x_offsets
dw -8, 8, -8, 8, -8, 8, -8, 8
.y_offsets
dw -8, -8, -8, -8, -8, -8, -8, -8
.chr
db $C0, $C2, $C4, $C6, $C8, $CA, $CC, $CE
.properties
db $3B, $7B, $3B, $7B, $3B, $7B, $3B, $7B
}
```
## Design Patterns
* **State Machine**: Utilizes a clear state machine (`%SpriteJumpTable`) for managing different behaviors (Idle, Attacking, Hurt).
* **Player Interaction**: Incorporates distance checks (`GetDistance8bit_Long`) to trigger state changes and direct damage on contact (`DoDamageToPlayerSameLayerOnContact`).
* **Damage Handling**: Includes a basic damage reaction (`Sprite_CheckDamageFromPlayer`, `Sprite_DamageFlash_Long`).
* **Vanilla ID Override**: The use of `!SPRID = $00` suggests this sprite is intended to replace or modify the behavior of a vanilla sprite with ID $00.

View File

@@ -0,0 +1,469 @@
# Goriya Sprite Analysis
This document provides a detailed analysis of the `goriya.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Goriya's fundamental characteristics:
```asm
!SPRID = Sprite_Goriya
!NbrTiles = 03 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 00 ; Number of Health the sprite have (dynamically set in _Prep)
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` and `!Damage` are initially set to `00` but are dynamically determined during initialization.
## 2. Core Routines
### 2.1. `Sprite_Goriya_Long` (Main Loop)
This is the primary entry point for Goriya's per-frame execution, called by the game engine. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active. Notably, it checks `SprSubtype, X` to determine if it's the main Goriya sprite or a boomerang, and calls the appropriate drawing routine.
```asm
Sprite_Goriya_Long:
{
PHB : PHK : PLB
LDA.w SprSubtype, X : BEQ + ; Check SprSubtype
JSR Sprite_Boomerang_Draw ; If SprSubtype is not 0, draw as boomerang
JMP ++
+
JSR Sprite_Goriya_Draw ; If SprSubtype is 0, draw as Goriya
JSL Sprite_DrawShadow
++
JSL Sprite_CheckActive : BCC .SpriteIsNotActive ; Check if sprite is active
JSR Sprite_Goriya_Main ; If active, run main logic
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_Goriya_Prep` (Initialization)
This routine is executed once when Goriya is first spawned. It sets Goriya's health to `08` (one heart).
```asm
Sprite_Goriya_Prep:
{
PHB : PHK : PLB
LDA.b #$08 : STA.w SprHealth, X ; Set health to 8
PLB
RTL
}
```
### 2.3. `Sprite_Goriya_Main` (Behavioral State Machine)
This routine manages Goriya's AI through a state machine, using `SprAction, X` to determine the current behavior. It utilizes `JumpTableLocal` for efficient state transitions, including walking in different directions and a boomerang attack state.
```asm
Sprite_Goriya_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal ; Jump to the routine specified by SprAction
dw Goriya_WalkingUp
dw Goriya_WalkingDown
dw Goriya_WalkingLeft
dw Goriya_WalkingRight
dw BoomerangAttack
Goriya_WalkingUp:
{
%PlayAnimation(0, 1, 10) ; Animate frames 0-1 every 10 frames
JSR Sprite_Goriya_Move ; Handle movement
RTS
}
Goriya_WalkingDown:
{
%PlayAnimation(2, 3, 10) ; Animate frames 2-3 every 10 frames
JSR Sprite_Goriya_Move ; Handle movement
RTS
}
Goriya_WalkingLeft:
{
%StartOnFrame(4)
%PlayAnimation(4, 5, 10) ; Animate frames 4-5 every 10 frames
JSR Sprite_Goriya_Move ; Handle movement
RTS
}
Goriya_WalkingRight:
{
%StartOnFrame(6)
%PlayAnimation(6, 7, 10) ; Animate frames 6-7 every 10 frames
JSR Sprite_Goriya_Move ; Handle movement
RTS
}
BoomerangAttack:
{
%PlayAnimation(0, 3, 6) ; Animate frames 0-3 every 6 frames
LDA.w SprTimerD, X : BNE + ; Check timer D
LDA.b #$16
JSL Sprite_ApplySpeedTowardsPlayer ; Apply speed towards Link
%SetTimerD($50) ; Set timer D
+
JSL Sprite_Move ; Apply velocity
JSL Sprite_SpawnSparkleGarnish ; Spawn sparkle effect
JSL Sprite_CheckDamageToPlayer : BCC .no_dano ; Check if Goriya damages Link
LDA.b #$FF : STA.w SprTimerD, X ; If damaged, set timer D
JSL Sprite_InvertSpeed_XY ; Invert speed
.no_dano
JSL Sprite_CheckDamageFromPlayer : BCC + ; Check if Link damages Goriya
JSL Sprite_InvertSpeed_XY ; If damaged, invert speed
+
JSL Sprite_CheckTileCollision ; Check for tile collision
LDA.w SprCollision, X : BEQ + ; If no collision
STZ.w SprState, X ; Clear sprite state (despawn?)
+
RTS
}
}
```
### 2.4. `Sprite_Goriya_Move` (Movement and Interaction Logic)
This routine is called by the various walking states in `Sprite_Goriya_Main` to handle Goriya's physical interactions and movement. It also manages the logic for throwing a boomerang and changing movement directions.
```asm
Sprite_Goriya_Move:
{
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
JSL Sprite_PlayerCantPassThrough
JSL Sprite_DamageFlash_Long
JSL Sprite_CheckDamageToPlayer
JSL Sprite_CheckDamageFromPlayer
JSL Sprite_CheckIfRecoiling
JSR Goriya_HandleTileCollision ; Handle tile collision and change direction
LDA.w SprTimerD, X : BNE ++
JSL GetRandomInt : AND.b #$9F : BNE ++
LDA.b #$04 : STA.w SprMiscB, X ; Set SprMiscB for boomerang attack
%SetTimerD($FF)
JSR Goriya_BoomerangAttack ; Spawn boomerang
JMP +
++
LDA.w SprTimerC, X : BNE +
JSL GetRandomInt : AND.b #$03
STA.w SprMiscB, X ; Set SprMiscB for new movement direction
%SetTimerC(60)
+
LDA.w SprMiscB, X
JSL JumpTableLocal ; Jump to movement routine based on SprMiscB
dw Goriya_MoveUp
dw Goriya_MoveDown
dw Goriya_MoveLeft
dw Goriya_MoveRight
dw Goriya_Wait
Goriya_MoveUp:
{
LDA.b #-GoriyaMovementSpeed : STA.w SprYSpeed, X
STZ.w SprXSpeed, X
%GotoAction(0) ; Transition to Goriya_WalkingUp
LDA.b #$00 : STA.w SprMiscE, X
RTS
}
Goriya_MoveDown:
{
LDA.b #GoriyaMovementSpeed : STA.w SprYSpeed, X
STZ.w SprXSpeed, X
%GotoAction(1) ; Transition to Goriya_WalkingDown
LDA.b #$01 : STA.w SprMiscE, X
RTS
}
Goriya_MoveLeft:
{
STZ.w SprYSpeed, X
LDA.b #-GoriyaMovementSpeed : STA.w SprXSpeed, X
%GotoAction(2) ; Transition to Goriya_WalkingLeft
LDA.b #$02 : STA.w SprMiscE, X
RTS
}
Goriya_MoveRight:
{
STZ.w SprYSpeed, X
LDA.b #GoriyaMovementSpeed : STA.w SprXSpeed, X
%GotoAction(3) ; Transition to Goriya_WalkingRight
LDA.b #$03 : STA.w SprMiscE, X
RTS
}
Goriya_Wait:
{
STZ.w SprXSpeed, X
STZ.w SprYSpeed, X
%GotoAction(0) ; Transition to Goriya_WalkingUp (default)
RTS
}
}
```
### 2.5. `Goriya_HandleTileCollision`
This routine is called to handle Goriya's collision with tiles. Upon collision, it randomly selects a new movement direction and sets a timer (`SprTimerC`).
```asm
Goriya_HandleTileCollision:
{
JSL Sprite_CheckTileCollision
LDA.w SprCollision, X : BEQ ++
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X ; Randomly choose new direction
+
STA.w SprMiscE, X
%SetTimerC(60) ; Set timer C for 60 frames
++
RTS
}
```
### 2.6. `Goriya_BoomerangAttack`
This routine is responsible for spawning the boomerang sprite. It sets up the boomerang's initial properties, including its `SprSubtype` (to differentiate it from the main Goriya), action, position, and health.
```asm
Goriya_BoomerangAttack:
{
LDA.b #$2C ; Sprite ID for boomerang (assuming $2C is the boomerang sprite ID)
JSL Sprite_SpawnDynamically : BMI + ; Spawn a new sprite dynamically
LDA.b #$01 : STA.w SprSubtype, Y ; Set SprSubtype to 1 for the boomerang
LDA.b #$04 : STA.w SprAction, Y ; Set action for boomerang (e.g., flying)
LDA.w SprX, X : STA.w SprX, Y ; Copy Goriya's X position to boomerang
LDA.w SprY, X : STA.w SprY, Y ; Copy Goriya's Y position to boomerang
LDA.w SprXH, X : STA.w SprXH, Y
LDA.w SprYH, X : STA.w SprYH, Y
LDA.b #$01 : STA.w SprNbrOAM, Y ; Set number of OAM entries
LDA.b #$40 : STA.w SprHealth, Y ; Set boomerang health
LDA.b #$00 : STA.w SprHitbox, Y ; Set boomerang hitbox
+
RTS
}
```
### 2.7. `Sprite_Goriya_Draw` (Goriya Drawing Routine)
This routine is responsible for rendering Goriya's graphics. It uses a custom OAM allocation and manipulation logic to handle its multi-tile appearance and animation. It dynamically determines the animation frame and applies offsets for each tile.
```asm
Sprite_Goriya_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY ; Calculate animation frame index
LDA.w .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles - 1
LDY.b #$00
.nextTile
; -------------------------------------------------------
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E : INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
; Put the sprite out of the way
LDA.b #$F0 : STA ($90), Y : STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y : INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $02, $04, $06, $08, $0A, $0C, $0E
.nbr_of_tiles
db 1, 1, 1, 1, 1, 1, 1, 1
.x_offsets
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
.y_offsets
dw 0, -9
dw 0, -9
dw 0, -10
dw 0, -10
dw 0, -10
dw 0, -9
dw 0, -9
dw -1, -10
.chr
; Body Head
db $E4, $C0
db $E4, $C0
db $E6, $C2
db $E6, $C2
db $E2, $C4
db $E0, $C4
db $E2, $C4
db $E0, $C4
.properties
db $2D, $2D
db $6D, $2D
db $2D, $2D
db $6D, $2D
db $2D, $2D
db $2D, $2D
db $6D, $6D
db $6D, $6D
}
```
### 2.8. `Sprite_Boomerang_Draw` (Boomerang Drawing Routine)
This routine is responsible for rendering the boomerang's graphics. It also uses a custom OAM allocation and manipulation logic.
```asm
Sprite_Boomerang_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $02, $03
.nbr_of_tiles
db 0, 0, 0, 0
.chr
db $26
db $26
db $26
db $26
.properties
db $22
db $A2
db $E2
db $62
}
```
## 3. Key Behaviors and Implementation Details
* **Dual Role (Goriya and Boomerang):** The `Sprite_Goriya_Long` routine uses `SprSubtype, X` to determine if the current sprite instance is the main Goriya or a boomerang it has thrown. This allows a single sprite ID to manage two distinct entities.
* **Boomerang Attack:** Goriya actively throws a boomerang (`Goriya_BoomerangAttack`) at Link, which then becomes an independent sprite with its own drawing and movement logic (`BoomerangAttack` state in `Sprite_Goriya_Main` and `Sprite_Boomerang_Draw`).
* **Dynamic Health:** Goriya's health is set to a fixed value of `08` (one heart) during initialization.
* **State Management:** Goriya uses `SprAction, X` and `JumpTableLocal` to manage its walking states (`Goriya_WalkingUp`, `Goriya_WalkingDown`, `Goriya_WalkingLeft`, `Goriya_WalkingRight`) and its `BoomerangAttack` state.
* **Movement Patterns:** Goriya moves in random directions, with `Goriya_HandleTileCollision` triggering a new random direction upon hitting a tile. It also has a `Goriya_Wait` state.
* **Custom OAM Drawing:** Both the Goriya and its boomerang utilize custom OAM drawing routines (`Sprite_Goriya_Draw` and `Sprite_Boomerang_Draw`) for precise control over their multi-tile graphics and animation. The use of `REP`/`SEP` for 16-bit coordinate calculations is present in both.
* **Code Reuse:** The `Goriya_HandleTileCollision` routine is notably reused by the Darknut sprite, indicating a shared and modular approach to tile collision handling for certain enemy types.
* **`SprMiscB` Usage:** This variable is used to store the current movement direction (0-4) for Goriya's random movement.
* **`SprMiscE` Usage:** This variable also stores the current movement direction, likely for animation or other directional logic.
* **`SprTimerC` and `SprTimerD` Usage:** These timers are used to control the duration of movement states and the frequency of boomerang attacks.

View File

@@ -0,0 +1,433 @@
# Helmet Chuchu Sprite Analysis
This document provides a detailed analysis of the `helmet_chuchu.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Helmet Chuchu's fundamental characteristics:
```asm
!SPRID = Sprite_HelmetChuchu
!NbrTiles = 03 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = $10 ; Number of Health the sprite have
!Damage = 04 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is initially set to `$10` but is dynamically determined during initialization based on Link's sword level.
## 2. Core Routines
### 2.1. `Sprite_HelmetChuchu_Long` (Main Loop)
This is the primary entry point for Helmet Chuchu's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_HelmetChuchu_Long:
{
PHB : PHK : PLB
JSR Sprite_HelmetChuchu_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_HelmetChuchu_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_HelmetChuchu_Prep` (Initialization)
This routine is executed once when Helmet Chuchu is first spawned. It sets its health based on Link's sword level, randomly assigns an initial `SprAction` (determining its type and initial frame), and initializes `SprMiscB` and `SprMiscD` to zero.
```asm
Sprite_HelmetChuchu_Prep:
{
PHB : PHK : PLB
LDA.l Sword : DEC A : TAY
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
JSL GetRandomInt : AND.b #$02 : STA.w SprAction, X ; Randomly set initial action (0, 1, or 2)
STZ.w SprMiscB, X
STZ.w SprMiscD, X
LDA.w SprAction, X : BNE +
LDA.b #$04 : STA.w SprFrame, X ; If action 0, set frame to 4 (Helmet Green)
+
CMP.b #$02 : BNE +
LDA.b #$02 : STA.w SprFrame, X ; If action 2, set frame to 2 (Mask Red)
+
PLB
RTL
.health
db $08, $0C, $0F, $10 ; Health values for each sword level
}
```
### 2.3. `Sprite_HelmetChuchu_Main` (Behavioral State Machine)
This routine manages Helmet Chuchu's AI through a state machine, using `SprAction, X` to determine its current behavior. It includes states for different Chuchu types (Green/Red, Helmet/No Helmet, Mask/No Mask) and separate states for the detached helmet and mask.
```asm
Sprite_HelmetChuchu_Main:
{
JSL Sprite_DamageFlash_Long
%SpriteJumpTable(GreenChuchu_Helmet,
GreenChuchu_NoHelmet,
RedChuchu_Masked,
RedChuchu_NoMask,
HelmetSubtype,
MaskSubtype)
GreenChuchu_Helmet:
{
%StartOnFrame(4)
%PlayAnimation(4, 5, 16)
JSR Sprite_CheckForHookshot : BCC +
LDA.w SprFlash, X : BEQ +
%GotoAction(1) ; Transition to GreenChuchu_NoHelmet if hookshot hit and not flashing
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
GreenChuchu_NoHelmet:
{
%StartOnFrame(0)
%PlayAnimation(0, 1, 16)
LDA.w SprMiscD, X : BNE +
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached helmet
LDA.b #$01 : STA.w SprMiscD, X ; Set flag to prevent re-spawning
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
RedChuchu_Masked:
{
%StartOnFrame(2)
%PlayAnimation(2, 3, 16)
JSR Sprite_CheckForHookshot : BCC +
LDA.w SprFlash, X : BEQ +
%GotoAction(3) ; Transition to RedChuchu_NoMask if hookshot hit and not flashing
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
RedChuchu_NoMask:
{
%StartOnFrame(6)
%PlayAnimation(6, 7, 16)
LDA.w SprMiscD, X : BNE +
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached mask
LDA.b #$01 : STA.w SprMiscD, X ; Set flag to prevent re-spawning
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
HelmetSubtype:
{
%StartOnFrame(8)
%PlayAnimation(8, 8, 16)
JSL Sprite_Move
JSL Sprite_CheckIfLifted
JSL Sprite_CheckIfRecoiling
JSL ThrownSprite_TileAndSpriteInteraction_long
RTS
}
MaskSubtype:
{
%StartOnFrame(8)
%PlayAnimation(9, 9, 16)
JSL Sprite_Move
JSL Sprite_CheckIfLifted
JSL Sprite_CheckIfRecoiling
JSL ThrownSprite_TileAndSpriteInteraction_long
RTS
}
}
```
### 2.4. `Sprite_Chuchu_Move` (Movement and Interaction Logic)
This routine handles Helmet Chuchu's movement, which involves bouncing towards or recoiling from the player. It uses `SprMiscB, X` to switch between these two behaviors.
```asm
Sprite_Chuchu_Move:
{
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
JSL Sprite_PlayerCantPassThrough
JSL Sprite_CheckIfRecoiling
LDA.w SprMiscB, X
JSL JumpTableLocal
dw BounceTowardPlayer
dw RecoilFromPlayer
BounceTowardPlayer:
{
JSL GetRandomInt : AND.b #$02 : STA $09 ; Speed
JSL GetRandomInt : AND.b #$07 : STA $08 ; Height
JSL Sprite_MoveAltitude
DEC.w $0F80,X : DEC.w $0F80,X
LDA.w SprHeight, X : BPL .aloft
STZ.w SprHeight, X
LDA.b $08 : STA.w $0F80, X ; set height from 08
LDA.b $09
JSL Sprite_ApplySpeedTowardsPlayer
.aloft
LDA.w SprHeight, X : BEQ .dontmove
JSL Sprite_Move
.dontmove
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
INC.w SprMiscB, X ; Switch to RecoilFromPlayer
LDA.b #$20 : STA.w SprTimerB, X
.no_damage
JSL Sprite_CheckDamageToPlayer : BCC .no_attack
INC.w SprMiscB, X ; Switch to RecoilFromPlayer
LDA.b #$20 : STA.w SprTimerB, X
.no_attack
RTS
}
RecoilFromPlayer:
{
JSL GetRandomInt : AND.b #$02 : STA $09 ; Speed
LDA.w SprX, X : CLC : ADC $09 : STA $04
LDA.w SprY, X : SEC : SBC $09 : STA $06
LDA.w SprXH, X : ADC #$00 : STA $05
LDA.w SprYH, X : ADC #$00 : STA $07
LDA $09 : STA $00 : STA $01
JSL Sprite_ProjectSpeedTowardsEntityLong
LDA.w SprTimerB, X : BNE .not_done
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached helmet/mask
STZ.w SprMiscB, X ; Switch back to BounceTowardPlayer
.not_done
RTS
}
}
```
### 2.5. `HelmetChuchu_SpawnHookshotDrag`
This routine is responsible for spawning the detached helmet or mask as a separate sprite when the Chuchu is hit by a hookshot. It determines whether to spawn a helmet or a mask based on the Chuchu's current `SprAction`.
```asm
HelmetChuchu_SpawnHookshotDrag:
{
; Based on the subtype either spawn the helmet or the mask
PHX
LDA.w SprAction, X : CMP.b #$01 : BEQ .spawn_helmet
CMP.b #$03 : BEQ .spawn_mask
.spawn_helmet
LDA.b #$05 ; Sprite ID for helmet/mask (assuming $05 is the ID)
JSL Sprite_SpawnDynamically : BMI .no_space
LDA.b #$05 : STA.w SprAction, Y ; Set action for detached helmet
JMP .prepare_mask
.no_space
JMP .no_space2
.spawn_mask
LDA.b #$05 ; Sprite ID for helmet/mask
JSL Sprite_SpawnDynamically : BMI .no_space2
LDA.b #$04 : STA.w SprAction, Y ; Set action for detached mask
.prepare_mask
JSL Sprite_SetSpawnedCoordinates
LDA.b #$10 : STA.w SprHealth, Y
LDA.b #$00 : STA.w SprMiscB, Y
LDA.b #$80 : STA.w SprTimerA, Y
LDA.b #$01 : STA.w SprNbrOAM, Y
LDA.w .speed_x, X : STA.w SprXSpeed, Y
LDA.w .speed_y, X : STA.w SprYSpeed, Y
.no_space2
PLX
RTS
.speed_x
db 16, -11, -16, 11
.speed_y
db 0, 11, 0, -11
}
```
### 2.6. `Sprite_CheckForHookshot`
This routine checks if a hookshot is currently active and interacting with the Chuchu. It iterates through ancilla slots to find a hookshot (`$1F`) and returns with the carry flag set if found.
```asm
Sprite_CheckForHookshot:
{
PHX
LDX.b #$0A
.next_ancilla
LDA.w $0C4A, X : CMP.b #$1F : BNE .not_hooker ; Check ancilla type (assuming $1F is hookshot)
PLX
SEC ; Carry set if hookshot found
RTS
.not_hooker
DEX
BPL .next_ancilla
PLX
CLC ; Carry clear if no hookshot found
RTS
}
```
### 2.7. `Sprite_HelmetChuchu_Draw` (Drawing Routine)
This routine is responsible for rendering Helmet Chuchu's graphics. It uses a custom OAM allocation and manipulation logic to handle its multi-tile appearance and animation, dynamically adjusting based on its current state (helmet/mask, color, animation frame).
```asm
Sprite_HelmetChuchu_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
; =======================================================
; chr prop
; Mask $04 $37
; Helmet $08 $3B
.start_index
db $00, $02, $03, $06, $08, $0A, $0C, $0E, $0F, $10
.nbr_of_tiles
db 1, 0, 2, 1, 1, 1, 1, 0, 0, 0
.y_offsets
dw 0, -8
dw 0
dw 0, -8, -8
dw 0, -4
dw 0, -8
dw 0, -4
dw 0, -8
dw 0
dw 0
dw 0
.chr
; No Helmet Green
db $26, $16
db $24
; Mask Red
db $26, $16, $04
db $24, $04
; Helmet Green
db $26, $08
db $24, $08
; No Helmet Red
db $26, $16
db $24
; Mask
db $04
; Helmet
db $08
.properties
db $2B, $2B
db $2B
db $25, $25, $27
db $25, $27
db $2B, $29
db $2B, $29
db $25, $25
db $25
; mask
db $27
; helmet
db $29
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Appearance and State:** Helmet Chuchu is a highly dynamic sprite that changes its appearance and behavior based on whether it has a helmet/mask and its color (green/red). This is managed through its `SprAction` and `SprFrame` values.
* **Conditional Damage Handling:** The Chuchu's vulnerability to damage is tied to the presence of its helmet or mask. When hit by a hookshot, the helmet/mask detaches, making the Chuchu vulnerable.
* **Hookshot Interaction:** Special logic (`Sprite_CheckForHookshot`) is implemented to detect interaction with Link's hookshot, which triggers the detachment of the helmet/mask.
* **Detached Helmet/Mask as Separate Sprites:** When the helmet or mask is detached, it is spawned as an independent sprite (`HelmetSubtype` or `MaskSubtype`) with its own movement (`Sprite_Move`), collision (`ThrownSprite_TileAndSpriteInteraction_long`), and interaction logic. This demonstrates a sophisticated use of child sprites.
* **Movement Patterns:** The Chuchu moves by bouncing towards (`BounceTowardPlayer`) and recoiling from (`RecoilFromPlayer`) the player, with randomness introduced in speed and height. This creates a distinct and challenging movement pattern.
* **Custom OAM Drawing:** The `Sprite_HelmetChuchu_Draw` routine is a complex example of custom OAM manipulation. It dynamically selects tiles and properties based on the Chuchu's current state, allowing for seamless transitions between helmeted, masked, and vulnerable forms.
* **`SprMiscB` Usage:** This variable controls the Chuchu's movement sub-states (`BounceTowardPlayer` and `RecoilFromPlayer`). It also plays a role in the detached helmet/mask sprites.
* **`SprMiscD` Usage:** This variable acts as a flag to ensure that the `HelmetChuchu_SpawnHookshotDrag` routine is called only once when the helmet/mask is detached.
* **`SprTimerB` Usage:** Used to control the duration of the recoil state.

View File

@@ -0,0 +1,293 @@
# Keese
## Overview
The Keese sprite (`!SPRID = $11`) is a versatile enemy that encompasses multiple variations: Ice Keese, Fire Keese, and Vampire Bat. Its behavior is dynamically determined by its `SprSubtype`.
## Subtypes
* `00` - Ice Keese
* `01` - Fire Keese
* `02` - Vampire Bat
## Sprite Properties
* **`!SPRID`**: `$11` (Vanilla sprite ID for Keese/Vampire Bat)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `00`
* **`!HVelocity`**: `00`
* **`!Health`**: `00` (Dynamically set in `_Prep` based on subtype)
* **`!Damage`**: `00` (Damage is handled by projectiles or specific attack logic)
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00` (Dynamically set in `_Prep` based on subtype)
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Keese_Long`)
This routine dispatches to different drawing and main logic routines based on the sprite's `SprSubtype`.
```asm
Sprite_Keese_Long:
{
PHB : PHK : PLB
LDA.w SprSubtype, X : CMP.b #$02 : BEQ +
JSR Sprite_Keese_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Keese_Main
.SpriteIsNotActive
JMP ++
+
JSR Sprite_VampireBat_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC ++
JSR Sprite_VampireBat_Main
++
PLB
RTL
}
```
## Initialization (`Sprite_Keese_Prep`)
This routine initializes sprite properties upon spawning, including health and prize, based on its subtype.
```asm
Sprite_Keese_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.b #$30 : STA.w SprTimerC, X
LDA.w SprSubtype, X : CMP.b #$02 : BNE +
LDA.b #$20 : STA.w SprHealth, X
BRA ++
+
LDA.b #$03 : STA.w SprNbrOAM, X
LDA.b #$03 : STA.w SprPrize, X
++
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Keese_Main`)
The Keese's behavior is managed by a state machine with `Keese_Idle` and `Keese_FlyAround` states.
* **`Keese_Idle`**: The sprite remains stationary until Link is within a certain distance, then transitions to `Keese_FlyAround`.
* **`Keese_FlyAround`**: The Keese flies around, plays an animation, checks for collisions with Link and tiles, and can initiate an attack. It uses `GetRandomInt` for varied movement and `Sprite_ProjectSpeedTowardsPlayer` to move towards Link.
```asm
Sprite_Keese_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw Keese_Idle
dw Keese_FlyAround
Keese_Idle:
{
STZ.w SprFrame, X
; Wait til the player is nearby then fly around
LDA.w SprTimerC, X : BEQ .move
JSL GetDistance8bit_Long : CMP.b #$20 : BCS +
.move
INC.w SprAction, X
JSL GetRandomInt
STA.w SprTimerA, X
+
RTS
}
Keese_FlyAround:
{
%PlayAnimation(0,5,8)
JSL Sprite_CheckDamageToPlayer
JSL Sprite_CheckDamageFromPlayer : BCC +
JSL ForcePrizeDrop_long
+
JSL Sprite_DamageFlash_Long
JSL Sprite_BounceFromTileCollision
JSL GetRandomInt : AND.b #$3F : BNE +
LDA.b #$10 : STA.w SprTimerC, X
+
JSR Sprite_Keese_Attack
LDA.w SprTimerA, X : AND.b #$10 : BNE +
LDA.b #$40
JSL Sprite_ProjectSpeedTowardsPlayer
+
JSL Sprite_SelectNewDirection
JSL Sprite_Move
LDA.w SprTimerA, X : BNE +
STZ.w SprAction, X
+
RTS
}
}
```
## Attack Logic (`Sprite_Keese_Attack`)
This routine handles the Keese's attack, which varies by subtype:
* **Ice Keese (`SprSubtype = 0`)**: Spawns sparkle garnish and a blind laser trail.
* **Fire Keese (`SprSubtype = 1`)**: Utilizes `Sprite_Twinrova_FireAttack`.
```asm
Sprite_Keese_Attack:
{
LDA.w SprTimerC, X : BEQ +
LDA.w SprSubtype, X : BEQ ++
JSL Sprite_Twinrova_FireAttack
JMP +
++
JSL Sprite_SpawnSparkleGarnish
JSL BlindLaser_SpawnTrailGarnish
+
RTS
}
```
## Drawing (`Sprite_Keese_Draw`)
The drawing routine handles OAM allocation, animation, and palette adjustments based on the sprite's subtype. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_Keese_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
LDA.w SprMiscB, X : STA $09
LDA.w SprSubtype, X : CMP.b #$01 : BNE +
LDA.b #$0A : EOR $08 : STA $08
+
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
; If SprMiscA != 0, then use 4th sheet
LDA.b $09 : BEQ +
LDA .chr_2, X : STA ($90), Y
JMP ++
+
LDA .chr, X : STA ($90), Y
++
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $03, $04, $06, $08
.nbr_of_tiles
db 0, 1, 0, 1, 1, 0
.x_offsets
dw 0
dw -4, 4
dw 0
dw -4, 4
dw -4, 4
dw 0
.y_offsets
dw 0
dw 0, 0
dw 0
dw 0, 0
dw 0, 0
dw 0
.chr
db $80
db $A2, $A2
db $82
db $84, $84
db $A4, $A4
db $A0
.chr_2
db $C0
db $E2, $E2
db $C2
db $C4, $C4
db $E4, $E4
db $E0
.properties
db $35
db $35, $75
db $35
db $35, $75
db $35, $75
db $35
.sizes
db $02
db $02, $02
db $02
db $02, $02
db $02, $02
db $02
}
```
## Design Patterns
* **Subtype-based Behavior**: The sprite uses `SprSubtype` to implement distinct behaviors and appearances for Ice Keese, Fire Keese, and Vampire Bat, all under a single `!SPRID`.
* **Dynamic Property Initialization**: Health and prize values are set dynamically during the `_Prep` routine based on the sprite's subtype.
* **Conditional Drawing and Palette**: The drawing routine adjusts the sprite's palette and potentially its graphics based on its subtype, allowing for visual differentiation.
* **Randomized Movement**: Utilizes `GetRandomInt` to introduce variability in movement patterns, making the enemy less predictable.
* **Projectile Attacks**: Implements different projectile attacks based on subtype, showcasing varied offensive capabilities.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, which is crucial for accurate sprite rendering.

View File

@@ -0,0 +1,242 @@
# Leever
## Overview
The Leever sprite is a custom implementation that overrides the vanilla Leever behavior (`Sprite_71_Leever`). It features distinct states for being underground, emerging, attacking, and digging back down, with randomized timers controlling its transitions.
## Vanilla Override
This custom Leever implementation hooks into the vanilla sprite ID $71. It uses a custom flag at `$0FFF` to determine whether to execute its custom logic (`Sprite_Leever_Long`) or fall back to the original vanilla Leever behavior (`Sprite_71_Leever`).
```asm
pushpc
Sprite_71_Leever = $06CBA2
org $069365 : dw Sprite_71_Leever_Alt
Sprite_71_Leever_Alt:
{
LDA.w $0FFF : BEQ +
JSL Sprite_Leever_Long
JMP ++
+
JSR Sprite_71_Leever
++
RTS
}
assert pc() <= $06A5C0
pullpc
```
## Sprite Properties
Explicit sprite properties (`!SPRID`, `!Health`, etc.) are not defined within this file, suggesting it either inherits vanilla properties for sprite ID $71 or these are defined in a separate configuration file.
## Main Structure (`Sprite_Leever_Long`)
This routine is the main entry point for the custom Leever logic, executed every frame. It handles bank setup, conditional drawing (skipping drawing when underground), and dispatches to the main logic if the sprite is active.
```asm
Sprite_Leever_Long:
{
PHB : PHK : PLB
LDA.w SprAction, X : BEQ +
JSR Sprite_Leever_Draw
+
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Leever_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Movement Routine (`Sprite_Leever_Move`)
A shared routine for handling the Leever's movement, including applying speed towards the player, moving the sprite, and bouncing off tiles.
```asm
Sprite_Leever_Move:
{
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
RTS
}
```
## Main Logic & State Machine (`Sprite_Leever_Main`)
The Leever's core behavior is managed by a state machine with four distinct states:
* **`Leever_Underground`**: The Leever moves underground. After a timer (`SprTimerA`) expires, it transitions to `Leever_Emerge`.
* **`Leever_Emerge`**: The Leever plays a backwards animation as it emerges. After a randomized timer, it transitions to `Leever_Attack`.
* **`Leever_Attack`**: The Leever plays an attack animation, checks for damage to/from Link, and moves. After a timer, it transitions to `Leever_Dig`.
* **`Leever_Dig`**: The Leever plays an animation as it digs back into the ground. After a randomized timer, it transitions back to `Leever_Underground`.
```asm
Sprite_Leever_Main:
{
JSL Sprite_DamageFlash_Long
LDA.w SprAction, X
JSL JumpTableLocal
dw Leever_Underground
dw Leever_Emerge
dw Leever_Attack
dw Leever_Dig
Leever_Underground:
{
LDA.w SprTimerA, X : BNE +
LDA.b #$40 : STA.w SprTimerA, X
INC.w SprAction, X
+
LDA.b #$10
JSR Sprite_Leever_Move
RTS
}
Leever_Emerge:
{
%PlayAnimBackwards(3, 2, 10)
LDA.w SprTimerA, X : BNE +
JSL GetRandomInt
AND.b #$3F
ADC.b #$A0
STA.w $0DF0,X
INC.w SprAction, X
STZ.w SprXSpeed, X : STZ.w SprYSpeed, X
+
RTS
}
Leever_Attack:
{
%PlayAnimation(0, 1, 10)
LDA.w SprTimerA, X : BNE +
LDA.b #$7F : STA.w SprTimerA, X
INC.w SprAction, X
+
PHX
JSL Sprite_CheckIfRecoiling
JSL Sprite_CheckDamageToPlayerSameLayer
JSL Sprite_CheckDamageFromPlayer
PLX
LDA.b #$0C
JSR Sprite_Leever_Move
RTS
}
Leever_Dig:
{
%PlayAnimation(2, 3, 10)
LDA.w SprTimerA, X : BNE +
JSL GetRandomInt
AND.b #$1F
ADC.b #$40
STA.w $0DF0,X
STZ.w SprAction, X
+
LDA.b #$08
JSR Sprite_Leever_Move
RTS
}
}
```
## Drawing (`Sprite_Leever_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_Leever_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $02, $03
.nbr_of_tiles
db 0, 0, 0, 0
.x_offsets
dw 0
dw 0
dw 0
dw 0
.y_offsets
dw 0
dw 0
dw 0
dw 0
.chr
db $C4
db $C6
db $C2
db $C0
.properties
db $33
db $33
db $33
db $33
.sizes
db $02
db $02
db $02
db $02
}
```
## Design Patterns
* **Vanilla Override**: Explicitly overrides a vanilla sprite's behavior, demonstrating how to replace existing game logic with custom implementations.
* **Conditional Logic**: Uses a custom flag (`$0FFF`) to dynamically switch between vanilla and custom behaviors, offering flexibility in game design.
* **Emerging/Digging State Machine**: Implements a robust state machine to manage the Leever's characteristic emerging from and digging back into the ground, with randomized timers for unpredictable transitions.
* **Animation Control**: Utilizes `%PlayAnimBackwards` for specific animation effects, such as the Leever emerging from the ground.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, essential for accurate sprite rendering.

View File

@@ -0,0 +1,79 @@
# Octoboss Sprite Analysis
## Overview
The `octoboss` sprite (ID: `Sprite_Octoboss`, which is `$3C`) is a multi-phase boss, likely an octopus-like creature. It features a unique mechanic involving a "brother" Octoboss, and can summon stalfos offspring. The fight progresses through distinct phases including emergence, movement, taunting, ascending, submerging, and a surrender sequence.
## Key Properties:
* **Sprite ID:** `Sprite_Octoboss` (`$3C`)
* **Description:** A multi-phase boss with a "brother" Octoboss, capable of summoning stalfos and engaging in various movement and attack patterns.
* **Number of Tiles:** 11
* **Health:** `00` (Health is managed by `ReturnTotalHealth` and `CheckForNextPhase`, combining the health of both Octobosses.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks or spawned offspring.)
* **Special Properties:**
* `!Boss = $01` (Correctly identified as a boss.)
* `!Shadow = 01` (Draws a shadow.)
* `!Hitbox = 03`
## Custom Variables:
* `!ConsecutiveHits = $AC`: Tracks consecutive hits on the boss.
* `!KydrogPhase = $7A`: Tracks the current phase of the boss fight. (Note: This variable name is `KydrogPhase`, suggesting shared logic or a copy-paste from the Kydrog boss.)
* `!WalkSpeed = 10`: Defines the boss's walking speed.
* `BrotherSpr = $0EB0`: Stores the sprite index of the "brother" Octoboss.
## Main Logic Flow (`Sprite_Octoboss_Main` and `Sprite_Octoboss_Secondary`):
The Octoboss has two primary main routines, `Sprite_Octoboss_Main` and `Sprite_Octoboss_Secondary`, which are called based on `SprMiscF, X`. This suggests different forms or behaviors for the two Octobosses.
**`Sprite_Octoboss_Main` Jump Table (for the primary Octoboss):**
* **`WaitForPlayerToApproach` (0x00):** Waits for Link to reach a specific Y-coordinate (`$08C8`) to trigger activation.
* **`Emerge` (0x01):** Emerges from the water, preventing Link's movement.
* **`EmergedShowMessage` (0x02):** Displays an introductory message.
* **`SpawnAndAwakeHisBrother` (0x03):** Spawns a "brother" Octoboss (`Sprite_Octoboss` with `SprMiscF = $01`) and stores its ID in `BrotherSpr`.
* **`WaitForBrotherEmerge` (0x04):** Waits for the brother to emerge and displays a message.
* **`SpawnPirateHats` (0x05):** Spawns "boss poof" effects for both Octobosses, changes their frames, and spawns walls using `Overworld_DrawMap16_Persist` macros.
* **`IdlePhase` (0x06):** Idles, can spawn fireballs, and checks total health (`ReturnTotalHealth`) to potentially trigger surrender.
* **`PickDirection` (0x07):** Picks a random direction and speed for movement.
* **`Moving` (0x08):** Moves around, handles boundary checks, spawns splash effects, and checks total health to potentially trigger surrender.
* **`WaitMessageBeforeSurrender` (0x09):** Displays a surrender message (`$004A`), sets the brother's action, and transitions to `RemoveHat`.
* **`RemoveHat` (0x0A):** Removes hats from both Octobosses with "boss poof" effects, displays a message (`$004B`), and transitions to `Submerge`.
* **`Submerge` (0x0B):** Submerges, playing an animation and spawning a splash effect.
* **`SubmergeWaitWall` (0x0C):** Submerges further, drawing walls using `Overworld_DrawMap16_Persist` macros.
* **`EmergeWaitGiveItem` (0x0D):** Emerges, spawns a medallion (`SpawnMedallion`), and sets an SRAM flag.
* **`SubmergeForeverKill` (0x0E):** Submerges completely, despawns, and allows Link to move again.
**`Sprite_Octoboss_Secondary` Jump Table (for the secondary/brother Octoboss, when `SprMiscF, X` is set):**
This routine largely mirrors `Sprite_Octoboss_Main` but includes specific states like `WaitDialog` and `Moving2`, suggesting slight behavioral differences.
## Initialization (`Sprite_Octoboss_Long` and `Sprite_Octoboss_Prep`):
* **`Sprite_Octoboss_Long`:** Main entry point. Handles sprite initialization, including setting OAM properties, bulletproofing, frame, and palette values. It also checks for boss defeat and medallion spawning.
* **`Sprite_Octoboss_Prep`:** Initializes `!KydrogPhase` to `00`, sets initial health (`$A0`), configures deflection, hitbox, bump damage, and calls `JSR KydrogBoss_Set_Damage` to set up the damage table. Sets initial sprite speeds and an intro timer.
## Health Management (`Sprite_Octoboss_CheckIfDead`, `ReturnTotalHealth`, `CheckForNextPhase`):
* **`Sprite_Octoboss_CheckIfDead`:** Monitors `SprHealth, X`. If health is zero or negative, it triggers the boss's death sequence.
* **`ReturnTotalHealth`:** Calculates the combined health of both Octobosses (`SprHealth, X` and `SprHealth, Y` of `BrotherSpr`).
* **`CheckForNextPhase`:** Manages the boss's phases based on health thresholds, similar to the Kydrog boss.
## Offspring Spawning (`RandomStalfosOffspring`, `Sprite_Offspring_Spawn`, `Sprite_Offspring_SpawnHead`):
* These routines are identical to those found in `kydrog_boss.asm`, spawning stalfos offspring.
## Attacks (`Chuchu_SpawnBlast`, `Mothula_SpawnBeams`, `Kydrog_ThrowBoneAtPlayer`):
* **`Chuchu_SpawnBlast`:** Spawns a Chuchu blast projectile.
* **`Mothula_SpawnBeams`:** Spawns beam projectiles.
* **`Kydrog_ThrowBoneAtPlayer`:** Spawns a bone projectile (reused from Kydrog).
## Drawing (`Sprite_Octoboss_Draw`, `Sprite_Octoboss_Draw2`):
* **`Sprite_Octoboss_Draw`:** Draws the primary Octoboss.
* **`Sprite_Octoboss_Draw2`:** Draws the secondary/brother Octoboss.
* Both use standard OAM allocation routines and handle complex animation frames, offsets, character data, properties, and sizes.
## Other Routines:
* **`SpawnSplash`:** Spawns a splash effect.
* **`SpawnBossPoof`:** Spawns a boss poof effect.
* **`HandleMovingSplash`:** Handles splash effects during movement.
* **`SpawnMedallion` / `SpawnMedallionAlt`:** Spawns a medallion.
## Discrepancies/Notes:
* **Shared Variables/Code with Kydrog:** The extensive use of `!KydrogPhase`, `KydrogBoss_Set_Damage`, and `Kydrog_ThrowBoneAtPlayer` suggests significant code reuse or copy-pasting from the Kydrog boss. This could lead to unexpected interactions or make maintenance challenging if changes are made to one boss but not the other. Refactoring shared logic into common functions or macros would be beneficial.
* **`Sprite_Octoboss_Secondary`:** The existence of a separate main routine for the "brother" Octoboss indicates that the two Octobosses might have slightly different behaviors or phases.
## Hardcoded Activation Trigger:
* As noted by the user, the activation trigger for Octoboss is hardcoded. In the `WaitForPlayerToApproach` routine, the boss checks `LDA.b $20 : CMP #$08C8`. `$20` represents Link's Y position, and `$08C8` is a hardcoded Y-coordinate. This means the boss will only activate when Link reaches this specific Y-coordinate, making it difficult to relocate the boss to other overworld maps without modifying this value. This hardcoded dependency needs to be addressed for improved reusability.

View File

@@ -0,0 +1,547 @@
# Octorok
## Overview
The Octorok sprite (`!SPRID = $08`) is a complex enemy implementation that supports both land-based and water-based variations. It features dynamic behavior, including transformation between forms, distinct movement patterns, and projectile attacks.
## Sprite Properties
* **`!SPRID`**: `$08` (Vanilla sprite ID for Octorok)
* **`!NbrTiles`**: `05`
* **`!Harmless`**: `00`
* **`!HVelocity`**: `00`
* **`!Health`**: `00` (Health is likely set dynamically or is vanilla)
* **`!Damage`**: `00` (Damage is likely from projectiles)
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00` (Shadow is drawn conditionally in `_Long`)
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Octorok_Long`)
This routine acts as a dispatcher, determining whether to execute Land Octorok or Water Octorok logic based on `SprSubtype`.
```asm
Sprite_Octorok_Long:
{
PHB : PHK : PLB
JSR Sprite_Octorok_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
LDA.w SprSubtype, X : BEQ +
JSL Sprite_DrawWaterRipple
JSR Sprite_WaterOctorok_Main
JMP ++
+
JSL Sprite_DrawShadow
JSR Sprite_Octorok_Main
++
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Octorok_Prep`)
This routine is currently empty, indicating that initial setup is minimal or handled by vanilla routines.
## Land Octorok Main Logic (`Sprite_Octorok_Main`)
This routine handles the behavior of a land-based Octorok, including movement and potential transformation into a Water Octorok.
* **Movement**: Calls `Sprite_Octorok_Move` for general movement.
* **Transformation**: Checks the tile type the Octorok is on. If it's a water tile, the Octorok transforms into a Water Octorok by setting `SprSubtype, X` to `01`.
* **Directional States**: Uses a jump table to manage animations for moving in different directions (Down, Up, Left, Right).
```asm
Sprite_Octorok_Main:
{
JSR Sprite_Octorok_Move
; TILETYPE 08
LDA.l $7FF9C2,X : CMP.b #$08 : BEQ .water_tile
; TILETYPE 09
CMP.b #$09 : BNE .not_water_tile
.water_tile
LDA.b #$01 : STA.w SprSubtype, X
STZ.w SprAction, X
STZ.w SprMiscG, X
RTS
.not_water_tile
LDA.w SprAction, X
JSL JumpTableLocal
dw Octorok_MoveDown
dw Octorok_MoveUp
dw Octorok_MoveLeft
dw Octorok_MoveRight
Octorok_MoveDown:
{
%PlayAnimation(0,1,10)
RTS
}
Octorok_MoveUp:
{
%StartOnFrame(2)
%PlayAnimation(2,3,10)
RTS
}
Octorok_MoveLeft:
{
%StartOnFrame(4)
%PlayAnimation(4,5,10)
RTS
}
Octorok_MoveRight:
{
%StartOnFrame(6)
%PlayAnimation(6,7,10)
RTS
}
}
```
## Octorok Movement (`Sprite_Octorok_Move`)
This shared routine handles the Octorok's general movement, damage reactions, and tile collision.
* **Damage & Collision**: Handles damage flash (`Sprite_DamageFlash_Long`), movement (`Sprite_Move`), and checks for damage to/from Link.
* **Directional Logic**: Sets the sprite's action based on its direction (`SprMiscC, X`).
* **Tile Collision**: Detects tile collisions and changes the Octorok's direction accordingly.
* **Barrage Logic**: Contains logic related to a potential projectile barrage (`octorok_used_barrage`).
```asm
Sprite_Octorok_Move:
{
JSL Sprite_DamageFlash_Long
JSL Sprite_Move
JSL Sprite_CheckDamageFromPlayer
JSL Sprite_CheckDamageToPlayer
; Set the SprAction based on the direction
LDA.w SprMiscC, X : AND.b #$03 : TAY
LDA.w .direction, Y : STA.w SprAction, X
LDA.w SprMiscF, X : AND.b #$01 : BNE .octorok_used_barrage
LDA.w SprMiscC, X : AND.b #$02 : ASL A : STA.b $00
INC.w SprDelay, X
LDA.w SprDelay, X
LSR A
LSR A
LSR A
AND.b #$03
ORA.b $00
STA.w SprGfx, X
LDA.w SprTimerA, X : BNE .wait
INC.w SprMiscF,X
LDY.w SprType,X
LDA.w .timer-8,Y : STA.w SprTimerA,X
RTS
.wait
LDY.w SprMiscC, X
LDA.w .speed_x, Y : STA.w SprXSpeed, X
LDA.w .speed_y, Y : STA.w SprYSpeed, X
JSL Sprite_CheckTileCollision
LDA.w $0E70, X : BEQ .no_collision
LDA.w SprMiscC,X : EOR.b #$01 : STA.w SprMiscC,X
BRA .exit
.no_collision
RTS
.octorok_used_barrage
STZ.w SprXSpeed, X : STZ.w SprYSpeed,X
LDA.w SprTimerA, X : BNE Octorock_ShootEmUp
INC.w SprMiscF, X
LDA.w SprMiscC, X
PHA
JSL GetRandomInt : AND.b #$3F : ADC.b #$30 : STA.w SprTimerA, X
AND.b #$03 : STA.w SprMiscC, X
PLA
CMP.w SprMiscC, X : BEQ .exit
EOR.w SprMiscC, X : BNE .exit
LDA.b #$08 : STA.w SprTimerB,X
.exit
RTS
.direction
db 3, 2, 0, 1
.speed_x
db 24, -24, 0, 0
.speed_y
db 0, 0, 24, -24
.timer
db 60, 128, 160, 128
}
```
## Octorok Projectile Logic (`Octorock_ShootEmUp`)
This routine determines the Octorok's shooting behavior, allowing for both single-shot and four-way attacks.
```asm
Octorock_ShootEmUp:
{
; Use SprMiscD as a flag to shoot 4 ways for awhile before going back to single shot
LDA.w SprMiscD, X : BEQ .continue
LDA.w SprTimerD, X : BNE .four_ways
LDA.b #$01 : STA.w SprMiscD, X
.continue
JSL GetRandomInt : AND.b #$1F : BNE .single_shot
.four_ways
LDA.b #$01 : STA.w SprMiscD, X
LDA.b #$20 : STA.w SprTimerD, X
JSR Octorok_Shoot4Ways
RTS
.single_shot
JSR Octorok_ShootSingle
RTS
}
```
## Water Octorok Main Logic (`Sprite_WaterOctorok_Main`)
This routine governs the behavior of a water-based Octorok, including its attack patterns and states.
* **Attack**: Calls `Sprite_WaterOctorok_Attack`.
* **Facing Directions**: Uses a jump table to manage animations for facing different directions (Down, Up, Left, Right) and a hidden state.
```asm
Sprite_WaterOctorok_Main:
{
JSR Sprite_WaterOctorok_Attack
LDA.w SprAction, X
JSL JumpTableLocal
dw WaterOctorok_FaceDown
dw WaterOctorok_FaceUp
dw WaterOctorok_FaceLeft
dw WaterOctorok_FaceRight
dw WaterOctorok_FaceHidden
WaterOctorok_FaceDown:
{
%PlayAnimation(0,1,10)
RTS
}
WaterOctorok_FaceUp:
{
%StartOnFrame(2)
%PlayAnimation(2,3,10)
RTS
}
WaterOctorok_FaceLeft:
{
%StartOnFrame(4)
%PlayAnimation(4,5,10)
RTS
}
WaterOctorok_FaceRight:
{
%StartOnFrame(6)
%PlayAnimation(6,7,10)
RTS
}
WaterOctorok_FaceHidden:
{
%StartOnFrame(8)
%PlayAnimation(8,8,10)
RTS
}
}
```
## Water Octorok Attack Logic (`Sprite_WaterOctorok_Attack`)
This routine manages the Water Octorok's attack states, including hiding, emerging, attacking, and re-hiding.
* **States**: Uses `SprMiscG, X` as a state machine for `WaterOctorok_Hidden`, `WaterOctorok_PoppingUp`, `WaterOctorok_Attacking`, and `WaterOctorok_Hiding`.
* **`WaterOctorok_Hidden`**: Remains hidden until Link is within a certain distance, then transitions to `WaterOctorok_PoppingUp`.
* **`WaterOctorok_PoppingUp`**: Emerges from the water, faces Link, and then transitions to `WaterOctorok_Attacking`.
* **`WaterOctorok_Attacking`**: Shoots a single projectile (`Octorok_ShootSingle`) after a timer, then transitions to `WaterOctorok_Hiding`.
* **`WaterOctorok_Hiding`**: Hides back in the water and transitions to `WaterOctorok_Hidden`.
```asm
Sprite_WaterOctorok_Attack:
{
JSL Sprite_DamageFlash_Long
JSL Sprite_CheckDamageToPlayer
LDA.w SprMiscG, X
JSL JumpTableLocal
dw WaterOctorok_Hidden
dw WaterOctorok_PoppingUp
dw WaterOctorok_Attacking
dw WaterOctorok_Hiding
WaterOctorok_Hidden:
{
LDA.w SprTimerA, X : BEQ +
RTS
+
JSL GetDistance8bit_Long
CMP.b #$40 : BCC .not_close_enough ; LD < 64
INC.w SprMiscG, X
%SetTimerA($10)
.not_close_enough
RTS
}
WaterOctorok_PoppingUp:
{
JSL Sprite_CheckDamageFromPlayer
LDA.w SprTimerA, X : BNE +
INC.w SprMiscG, X
%SetTimerA($20)
JSL Sprite_DirectionToFacePlayer
; LDA.w SprMiscC, X : AND.b #$03 : TAY
; LDA.w Sprite_Octorok_Move_direction, Y : STA.w SprAction, X
+
RTS
}
WaterOctorok_Attacking:
{
JSL Sprite_CheckDamageFromPlayer
LDA.w SprTimerA, X : BNE +
INC.w SprMiscG, X
%SetTimerA($10)
RTS
+
JSR Octorok_ShootSingle
RTS
}
WaterOctorok_Hiding:
{
LDA.w SprTimerA, X : BNE +
LDA.b #$04 : STA.w SprAction, X
STZ.w SprMiscG, X
%SetTimerA($40)
+
RTS
}
}
```
## Projectile Spawning (`Octorok_ShootSingle`, `Octorok_Shoot4Ways`, `Octorok_SpawnRock`)
These routines handle the spawning and animation of Octorok projectiles.
* **`Octorok_ShootSingle`**: Manages the animation and timing for shooting a single rock projectile.
* **`Octorok_Shoot4Ways`**: Manages the animation, timing, and direction changes for shooting rock projectiles in four cardinal directions.
* **`Octorok_SpawnRock`**: Spawns a rock projectile (sprite ID `$0C`) with specific initial offsets and speeds based on the Octorok's current direction.
```asm
Octorok_ShootSingle:
{
LDA.w SprTimerA, X : CMP.b #$1C : BNE .bide_time
PHA
JSR Octorok_SpawnRock
PLA
.bide_time
LSR #3
TAY
LDA.w .mouth_anim_step, Y : STA.w SprMiscB, X
RTS
.mouth_anim_step
db $00, $02, $02, $02
db $01, $01, $01, $00
db $00, $00, $00, $00
db $02, $02, $02, $02
db $02, $01, $01, $00
}
Octorok_Shoot4Ways:
{
LDA.w SprTimerA, X
PHA
CMP.b #$80 : BCS .animate
AND.b #$0F : BNE .delay_turn
PHA
LDY.w SprMiscC, X
LDA.w .next_direction, Y : STA.w SprMiscC, X
PLA
.delay_turn
CMP.b #$08 : BNE .animate
JSR Octorok_SpawnRock
.animate
PLA
LSR #4
TAY
LDA.w .mouth_anim_step, Y : STA.w SprMiscB, X
RTS
.next_direction
db $02, $03, $01, $00
.mouth_anim_step
db $02, $02, $02, $02
db $02, $02, $02, $02
db $01, $00
}
Octorok_SpawnRock:
{
LDA.b #$07 : JSL SpriteSFX_QueueSFX2WithPan
LDA.b #$0C : JSL Sprite_SpawnDynamically : BMI .fired_a_blank
PHX
LDA.w SprMiscC,X
TAX
LDA.b $00 : CLC : ADC.w .offset_x_low,X : STA.w SprX,Y
LDA.b $01 : ADC.w .offset_x_high,X : STA.w SprXH,Y
LDA.b $02 : CLC : ADC.w .offset_y_low,X : STA.w SprY,Y
LDA.b $03 : ADC.w .offset_y_high,X : STA.w SprYH,Y
LDA.w SprMiscC,Y
TAX
LDA.w .rock_speed_x,X : STA.w SprXSpeed,Y
LDA.w .rock_speed_y,X : STA.w SprYSpeed,Y
PLX
.fired_a_blank
RTS
.offset_x_low
db 12, -12, 0, 0
.offset_x_high
db 0, -1, 0, 0
.offset_y_low
db 4, 4, 12, -12
.offset_y_high
db 0, 0, 0, -1
.rock_speed_x
db 44, -44, 0, 0
.rock_speed_y
db 0, 0, 44, -44
}
```
## Drawing (`Sprite_Octorok_Draw`)
The drawing routine handles OAM allocation, animation, and palette adjustments. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_Octorok_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
; =========================================================
.start_index
db $00, $01, $02, $03, $04, $05, $06, $07, $08
.nbr_of_tiles
db 0, 0, 0, 0, 0, 0, 0, 0, 0
.chr
db $80
db $80
db $82
db $82
db $A0
db $A2
db $A0
db $A2
db $AA ; Water Octorok
.properties
db $0D
db $4D
db $0D
db $4D
db $0D
db $0D
db $4D
db $4D
db $3D ; Water Octorok
}
```
## Design Patterns
* **Subtype-based Behavior**: The Octorok utilizes `SprSubtype` to implement distinct behaviors for Land and Water Octoroks, including different main logic routines and conditional drawing (shadow vs. water ripple).
* **Dynamic Transformation**: A Land Octorok can dynamically transform into a Water Octorok if it moves onto a water tile, showcasing a unique environmental interaction.
* **Complex State Machines**: Both Land and Water Octoroks employ intricate state machines to manage their movement, attack patterns, and emerging/hiding behaviors, making them engaging enemies.
* **Projectile Attacks**: The Octorok can perform both single-shot and four-way projectile attacks, adding variety to its offensive capabilities.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering and positioning.

View File

@@ -0,0 +1,221 @@
# Pols Voice Sprite Analysis
This document provides a detailed analysis of the `pols_voice.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Pols Voice's fundamental characteristics:
```asm
!SPRID = Sprite_PolsVoice
!NbrTiles = 02 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 10 ; Number of Health the sprite have
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is set to `10` and is not dynamically determined by Link's sword level.
## 2. Core Routines
### 2.1. `Sprite_PolsVoice_Long` (Main Loop)
This is the primary entry point for Pols Voice's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_PolsVoice_Long:
{
PHB : PHK : PLB
JSR Sprite_PolsVoice_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_PolsVoice_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_PolsVoice_Prep` (Initialization)
This routine is executed once when Pols Voice is first spawned. It initializes `SprTimerA` to `$80` and clears `SprDefl` and `SprTileDie`.
```asm
Sprite_PolsVoice_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprTimerA, X
STZ.w SprDefl, X
STZ.w SprTileDie, X
PLB
RTL
}
```
### 2.3. `Sprite_PolsVoice_Main` (Behavioral State Machine)
This routine manages Pols Voice's AI through a state machine, using `SprAction, X` to determine its current behavior. It includes states for moving around and hopping around, with a unique interaction based on the flute song.
```asm
Sprite_PolsVoice_Main:
{
JSR PolsVoice_CheckForFluteSong ; Check for flute song interaction
%SpriteJumpTable(PolsVoice_MoveAround,
PolsVoice_HopAround)
PolsVoice_MoveAround:
{
%StartOnFrame(0)
%PlayAnimation(0,3,10)
;$09 = speed, $08 = max height
LDA #$05 : STA $09
LDA #$02 : STA $08
JSL Sprite_BounceTowardPlayer
JSL Sprite_BounceFromTileCollision
JSL Sprite_DamageFlash_Long
%DoDamageToPlayerSameLayerOnContact()
JSL GetRandomInt : AND #$3F : BNE .not_done ; Random chance to change state
LDA #$04 : STA.w SprTimerA, X
%GotoAction(1) ; Transition to PolsVoice_HopAround
.not_done
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage ; Check if Link damages Pols Voice
JSL Sprite_DirectionToFacePlayer
; Apply the speed positive or negative speed
LDA $0E : BPL .not_up
LDA #$20 : STA.w SprYSpeed, X
BRA .not_down
.not_up
LDA #$E0 : STA.w SprYSpeed, X
.not_down
LDA $0F : BPL .not_right
LDA #$20 : STA.w SprXSpeed, X
BRA .not_left
.not_right
LDA #$E0 : STA.w SprXSpeed, X
.not_left
LDA #$04 : STA.w SprTimerA, X
%GotoAction(1) ; Transition to PolsVoice_HopAround
.no_damage
RTS
}
PolsVoice_HopAround:
{
%StartOnFrame(4)
%PlayAnimation(4,4,10)
JSL Sprite_MoveXyz
JSL Sprite_BounceFromTileCollision
JSL Sprite_DamageFlash_Long
%DoDamageToPlayerSameLayerOnContact()
LDA.w SprTimerA, X : BNE .not_done ; If timer A is not 0
%GotoAction(0) ; Transition back to PolsVoice_MoveAround
.not_done
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage ; Check if Link damages Pols Voice
JSL Sprite_InvertSpeed_XY ; Invert speed
.no_damage
RTS
}
}
```
### 2.4. `PolsVoice_CheckForFluteSong`
This routine checks if the player is currently playing the flute (`SongFlag`). If the flute is being played, Pols Voice despawns (`STZ.w SprState, X`) and forces a prize drop.
```asm
PolsVoice_CheckForFluteSong:
{
; If the player plays the flute
LDA.b SongFlag : BEQ + ; Check SongFlag
LDA.b #$03 : STA.w SprState, X ; Set sprite state to despawn
JSL ForcePrizeDrop_long ; Force prize drop
+
RTS
}
```
### 2.5. `Sprite_PolsVoice_Draw` (Drawing Routine)
This routine is responsible for rendering Pols Voice's graphics. It uses the `%DrawSprite()` macro, which reads from a set of data tables to handle its appearance and animation.
```asm
Sprite_PolsVoice_Draw:
{
%DrawSprite()
.start_index
db $00, $01, $02, $03, $04
.nbr_of_tiles
db 0, 0, 0, 0, 1
.x_offsets
dw 0
dw 0
dw 0
dw 0
dw 0, 0
.y_offsets
dw 0
dw 0
dw 0
dw 0
dw -4, -20
.chr
db $6C
db $6A
db $6C
db $6A
db $6E, $4E
.properties
db $3B
db $3B
db $3B
db $7B
db $3B, $3B
.sizes
db $02
db $02
db $02
db $02
db $02, $02
}
```
## 3. Key Behaviors and Implementation Details
* **Fixed Health:** Unlike many other sprites, Pols Voice has a fixed health of `10` and its health is not dynamically scaled based on Link's sword level.
* **State Management:** Pols Voice uses `SprAction, X` and `%SpriteJumpTable` to manage its `PolsVoice_MoveAround` and `PolsVoice_HopAround` states. Transitions between these states are triggered by timers or random chance.
* **Movement Patterns:** Pols Voice moves by bouncing towards the player (`Sprite_BounceTowardPlayer`) and also has a hopping movement (`PolsVoice_HopAround`). It reacts to tile collisions by bouncing (`Sprite_BounceFromTileCollision`).
* **Flute Song Interaction:** A unique and defining characteristic of Pols Voice is its vulnerability to the flute song. When Link plays the flute (`SongFlag` is set), Pols Voice immediately despawns and drops a prize (`ForcePrizeDrop_long`). This is a classic Zelda enemy mechanic.
* **Damage Reaction:** When damaged by Link, Pols Voice inverts its speed (`Sprite_InvertSpeed_XY`) and transitions to the `PolsVoice_HopAround` state, providing a temporary reprieve or change in behavior.
* **Custom OAM Drawing:** Pols Voice uses the `%DrawSprite()` macro with OAM data tables to render its appearance and animations.
* **`SprTimerA` Usage:** This timer controls the duration of the `PolsVoice_HopAround` state before transitioning back to `PolsVoice_MoveAround`.

View File

@@ -0,0 +1,233 @@
# Poltergeist Sprite Analysis
This document provides a detailed analysis of the `poltergeist.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Poltergeist's fundamental characteristics:
```asm
!SPRID = Sprite_PolsVoice
!NbrTiles = 02 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 10 ; Number of Health the sprite have
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is set to `10` and is dynamically determined during initialization based on Link's sword level.
## 2. Core Routines
### 2.1. `Sprite_Poltergeist_Long` (Main Loop)
This is the primary entry point for Poltergeist's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_Poltergeist_Long:
{
PHB : PHK : PLB
JSR Sprite_Poltergeist_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Poltergeist_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_Poltergeist_Prep` (Initialization)
This routine is executed once when Poltergeist is first spawned. It sets its health based on Link's sword level and initializes `SprTimerA` and `SprTimerB`.
```asm
Sprite_Poltergeist_Prep:
{
PHB : PHK : PLB
LDA.l Sword : DEC A : TAY
LDA.w .health, Y : STA.w SprHealth, X
LDA.b #$80 : STA.w SprTimerA, X
LDA.b #$80 : STA.w SprTimerB, X
PLB
RTL
.health
db $06, $0A, $0C, $10
}
```
### 2.3. `Sprite_Poltergeist_Main` (Behavioral State Machine)
This routine manages Poltergeist's AI through a state machine, using `SprAction, X` to determine its current behavior. It includes states for moving, attacking, and being stunned.
```asm
Sprite_Poltergeist_Main:
{
JSL Sprite_DamageFlash_Long
%SpriteJumpTable(Poltergeist_Move,
Poltergeist_Attack,
Poltergeist_Stunned)
Poltergeist_Move:
{
%PlayAnimation(0, 1, 16)
JSR Sprite_Poltergeist_Move
RTS
}
Poltergeist_Attack:
{
%PlayAnimation(2, 3, 16)
JSL Sprite_Move
JSL Sprite_CheckDamageToPlayer
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
%GotoAction(0) ; Transition back to Poltergeist_Move
+
RTS
}
Poltergeist_Stunned:
{
%PlayAnimation(4, 5, 16)
JSL Sprite_Move
JSL Sprite_CheckDamageToPlayer
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
%GotoAction(0) ; Transition back to Poltergeist_Move
+
RTS
}
}
```
### 2.4. `Sprite_Poltergeist_Move` (Movement Logic)
This routine handles Poltergeist's movement patterns, including moving towards Link, bouncing from tile collisions, and changing direction randomly.
```asm
Sprite_Poltergeist_Move:
{
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
JSL Sprite_PlayerCantPassThrough
JSL Sprite_CheckIfRecoiling
LDA.w SprTimerC, X : BNE ++ ; Check timer C
JSL GetRandomInt : AND #$3F : BNE ++ ; Random chance to change direction
LDA.b #$40 : STA.w SprTimerC, X
JSL Sprite_SelectNewDirection
++
LDA.w SprTimerA, X : BNE + ; Check timer A
JSL Sprite_IsToRightOfPlayer : CPY.b #$01 : BNE .ToRight
%GotoAction(1) ; Transition to Poltergeist_Attack
JMP .Continue
.ToRight
%GotoAction(1) ; Transition to Poltergeist_Attack
LDA.b #$20 : STA.w SprTimerA, X
JMP .Continue
+
%GotoAction(0) ; Transition to Poltergeist_Move
.Continue
LDA.w SprMiscB, X
JSL JumpTableLocal
dw PoltergeistMove
PoltergeistMove:
{
JSL GetRandomInt : AND.b #$03
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_CheckTileCollision
JSL Sprite_CheckDamageFromPlayer
JSL Sprite_CheckDamageToPlayer
RTS
}
}
```
### 2.5. `Sprite_Poltergeist_Draw` (Drawing Routine)
This routine is responsible for rendering Poltergeist's graphics. It uses the `%DrawSprite()` macro, which reads from a set of data tables to handle its multi-tile appearance and animation.
```asm
Sprite_Poltergeist_Draw:
{
%DrawSprite()
.start_index
db $00, $03, $06, $09, $0C, $0F
.nbr_of_tiles
db 2, 2, 2, 2, 2, 2
.x_offsets
dw 0, 0, 8
dw 8, 0, 0
dw 0, 0, 8
dw 0, 0, 8
dw 0, 8, 0
dw 0, 8, 0
.y_offsets
dw -8, 0, -8
dw -8, 0, -8
dw 0, -8, -8
dw 0, -8, -8
dw 0, -8, -8
dw 0, -8, -8
.chr
db $3A, $02, $3B
db $3A, $02, $3B
db $20, $00, $01
db $22, $10, $11
db $20, $00, $01
db $22, $10, $11
.properties
db $2B, $2B, $2B
db $6B, $6B, $6B
db $2B, $2B, $2B
db $2B, $2B, $2B
db $6B, $6B, $6B
db $6B, $6B, $6B
.sizes
db $00, $02, $00
db $00, $02, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Health:** Poltergeist's health is determined at spawn time based on Link's current sword level, allowing for dynamic difficulty scaling.
* **State Management:** Poltergeist uses `SprAction, X` and `%SpriteJumpTable` to manage its `Poltergeist_Move`, `Poltergeist_Attack`, and `Poltergeist_Stunned` states. Transitions between these states are triggered by timers and player proximity.
* **Movement Patterns:** Poltergeist moves towards Link (`Sprite_ApplySpeedTowardsPlayer`) with random direction changes (`Sprite_SelectNewDirection`). It also handles bouncing from tile collisions and cannot be passed through by Link.
* **Attack Behavior:** Poltergeist transitions to an `Poltergeist_Attack` state, which likely involves a direct contact attack or a projectile, and then returns to its movement state after a timer.
* **Stunned State:** When damaged, Poltergeist enters a `Poltergeist_Stunned` state, during which it is temporarily incapacitated. It recovers from this state after a timer.
* **Conditional Invulnerability:** The sprite properties indicate `!ImpervSwordHammer = 00`, but the code does not explicitly set it to `01` when stunned. This might be an oversight or handled by a global routine. However, the presence of `SprDefl` in `_Prep` suggests some form of deflection is intended.
* **Custom OAM Drawing:** Poltergeist uses the `%DrawSprite()` macro with detailed OAM data tables to render its multi-tile appearance and animations across its different states.
* **`SprTimerA`, `SprTimerB`, `SprTimerC` Usage:** These timers control the duration of attack and stunned states, and the frequency of direction changes.

View File

@@ -0,0 +1,287 @@
# Puffstool Sprite Analysis
This document provides a detailed analysis of the `puffstool.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Puffstool's fundamental characteristics:
```asm
!SPRID = Sprite_Puffstool
!NbrTiles = 02 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 0 ; Number of Health the sprite have (dynamically set in _Prep)
!Damage = 0 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 0 ; Unused in this template (can be 0 to 7)
!Hitbox = 0 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 0 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health`, `!Damage`, `!Hitbox`, and `!Prize` are initially set to `0` but are dynamically determined during initialization.
## 2. Core Routines
### 2.1. `Sprite_Puffstool_Long` (Main Loop)
This is the primary entry point for Puffstool's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_Puffstool_Long:
{
PHB : PHK : PLB
JSR Sprite_Puffstool_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Puffstool_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_Puffstool_Prep` (Initialization)
This routine is executed once when Puffstool is first spawned. It sets its health based on Link's sword level and initializes `SprDefl`.
```asm
Sprite_Puffstool_Prep:
{
PHB : PHK : PLB
LDA.l $7EF359 : TAY
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
LDA.b #$80 : STA.w SprDefl, X
PLB
RTL
.health
db $04, $08, $0A, $10 ; Health values for each sword level
}
```
### 2.3. `Sprite_Puffstool_Main` (Behavioral State Machine)
This routine manages Puffstool's AI through a state machine, using `SprAction, X` to determine its current behavior. It includes states for walking, being stunned, and spawning spores.
```asm
Sprite_Puffstool_Main:
{
%SpriteJumpTable(Puffstool_Walking,
Puffstool_Stunned,
Puffstool_Spores)
Puffstool_Walking:
{
%PlayAnimation(0,6,10)
JSL Sprite_PlayerCantPassThrough
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
JSL Sprite_SelectNewDirection ; Select a new direction
+
JSL Sprite_MoveXyz
JSL Sprite_BounceFromTileCollision
JSL Sprite_DamageFlash_Long
JSL ThrownSprite_TileAndSpriteInteraction_long ; Interact with thrown objects
JSL Sprite_CheckIfRecoiling
JSL Sprite_CheckDamageFromPlayer : BCC .no_dano ; Check if Link damages Puffstool
%GotoAction(1) ; Transition to Puffstool_Stunned
%SetTimerA($60)
%SetTimerF($20)
.no_dano
RTS
}
Puffstool_Stunned:
{
%PlayAnimation(7,7,10)
JSL Sprite_CheckIfLifted
JSL Sprite_DamageFlash_Long
JSL ThrownSprite_TileAndSpriteInteraction_long
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
%GotoAction(0) ; Transition back to Puffstool_Walking
JSL GetRandomInt : AND.b #$1F : BEQ .bomb ; Random chance to spawn bomb
JSR Puffstool_SpawnSpores ; Spawn spores
RTS
.bomb
LDA.b #$4A ; SPRITE 4A (Bomb sprite ID)
LDY.b #$0B
JSL Sprite_SpawnDynamically : BMI .no_space
JSL Sprite_SetSpawnedCoordinates
JSL Sprite_TransmuteToBomb ; Transform into a bomb
.no_space
+
RTS
}
Puffstool_Spores:
{
%StartOnFrame(8)
%PlayAnimation(8,11,10)
JSL Sprite_MoveXyz
JSL Sprite_CheckDamageToPlayerSameLayer
LDA.w SprTimerC, X : BNE + ; If timer C is not 0
JSL ForcePrizeDrop_long ; Force prize drop
STZ.w SprState, X ; Clear sprite state (despawn?)
+
RTS
}
}
```
### 2.4. `Puffstool_SpawnSpores`
This routine is responsible for spawning spore projectiles. It plays a sound effect and then spawns multiple spore sprites, setting their initial properties like speed, altitude, and timers.
```asm
Puffstool_SpawnSpores:
{
LDA.b #$0C ; SFX2.0C
JSL $0DBB7C ; SpriteSFX_QueueSFX2WithPan
LDA.b #$03 : STA.b $0D ; Number of spores to spawn
.nth_child
LDA.b #$B1 ; Spore sprite ID (assuming $B1 is the spore sprite ID)
JSL Sprite_SpawnDynamically : BMI .no_space
JSL Sprite_SetSpawnedCoordinates
PHX
LDX.b $0D
LDA.w .speed_x, X : STA.w SprXSpeed, Y
LDA.w .speed_y, X : STA.w SprYSpeed, Y
LDA.b #$20 : STA.w $0F80, Y ; Altitude
LDA.b #$FF : STA.w $0E80, Y ; Gravity
LDA.b #$40 : STA.w SprTimerC, Y
LDA.b #$01 : STA.w SprSubtype, Y
LDA.b #$02 : STA.w SprAction, Y
PLX
.no_space
DEC.b $0D
BPL .nth_child
RTS
.speed_x
db 11, -11, -11, 11
.speed_y
db 0, 11, 0, -11
}
```
### 2.5. `Sprite_Puffstool_Draw` (Drawing Routine)
This routine is responsible for rendering Puffstool's graphics. It uses the `%DrawSprite()` macro, which reads from a set of data tables to handle its multi-tile appearance and animation.
```asm
Sprite_Puffstool_Draw:
{
%DrawSprite()
.start_index
db $00, $02, $04, $06, $08, $0A, $0C, $0E, $0F, $10, $11, $12
.nbr_of_tiles
db 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
.x_offsets
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0
dw 0
dw 0
dw 0
dw 4
.y_offsets
dw -8, 0
dw 0, -8
dw 0, -8
dw 0, -8
dw 0, -8
dw 0, -8
dw 0, -8
dw 0
dw 0
dw 0
dw 0
dw 4
.chr
db $C0, $D0
db $D2, $C2
db $D4, $C4
db $D2, $C2
db $D0, $C0
db $D2, $C2
db $D4, $C4
db $D6
db $EA
db $C8
db $E8
db $F7
.properties
db $33, $33
db $33, $33
db $33, $33
db $33, $33
db $33, $33
db $73, $73
db $73, $73
db $3D
db $33
db $33
db $33
db $33
.sizes
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02
db $02
db $02
db $02
db $00
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Health:** Puffstool's health is determined at spawn time based on Link's current sword level, allowing for dynamic difficulty scaling.
* **State Management:** Puffstool uses `SprAction, X` and `%SpriteJumpTable` to manage its `Puffstool_Walking`, `Puffstool_Stunned`, and `Puffstool_Spores` states.
* **Movement Patterns:** In its walking state, Puffstool moves with random direction changes (`Sprite_SelectNewDirection`) and interacts with the environment (`Sprite_MoveXyz`, `Sprite_BounceFromTileCollision`).
* **Stunned State and Counter-Attack:** When damaged, Puffstool enters a `Puffstool_Stunned` state. After a timer, it either spawns multiple spores (`Puffstool_SpawnSpores`) or, with a random chance, transforms into a bomb (`Sprite_TransmuteToBomb`). This provides a unique counter-attack mechanism.
* **Spore Attack:** Puffstool can spawn multiple spore projectiles (`Puffstool_SpawnSpores`) that have their own movement and interaction logic. These spores are spawned with initial speed, altitude, and gravity.
* **Bomb Spawning/Transformation:** A unique behavior where Puffstool can transform into a bomb (`Sprite_TransmuteToBomb`) when stunned, adding an element of surprise and danger.
* **Interaction with Thrown Objects:** The use of `ThrownSprite_TileAndSpriteInteraction_long` suggests Puffstool can be lifted and thrown by Link, or interacts with other thrown objects.
* **Custom OAM Drawing:** Puffstool uses the `%DrawSprite()` macro with detailed OAM data tables to render its multi-tile appearance and animations across its different states.
* **`SprTimerA`, `SprTimerF`, `SprTimerC` Usage:** These timers control the duration of the stunned state, the delay before spawning spores/bombs, and the lifespan of the spawned spores.

View File

@@ -0,0 +1,221 @@
# Sea Urchin Sprite Analysis
This document provides a detailed analysis of the `sea_urchin.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Sea Urchin's fundamental characteristics:
```asm
!SPRID = Sprite_SeaUrchin
!NbrTiles = 04 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 06 ; Number of Health the sprite have
!Damage = 04 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 01 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 01 ; 01 = can be blocked by link's shield?
!Prize = 03 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is fixed at `06` and `!Damage` is `04` (half a heart).
## 2. Core Routines
### 2.1. `Sprite_SeaUrchin_Long` (Main Loop)
This is the primary entry point for Sea Urchin's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_SeaUrchin_Long:
{
PHB : PHK : PLB
JSR Sprite_SeaUrchin_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_SeaUrchin_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_SeaUrchin_Prep` (Initialization)
This routine is executed once when Sea Urchin is first spawned. It sets the initial prize and conditionally modifies its imperviousness and prize based on the `WORLDFLAG` (likely for different game states or areas, such as the Eon Sea).
```asm
Sprite_SeaUrchin_Prep:
{
PHB : PHK : PLB
LDA #$01 : STA.w SprPrize, X ; Default prize
LDA.w WORLDFLAG : BEQ + ; Check WORLDFLAG
; Eon Sea Urchin impervious to sword
LDA.b #%10000100 : STA.w SprDefl, X ; Set imperviousness flags
LDA.b #$07 : STA.w SprPrize, X ; Change prize for Eon Sea
+
PLB
RTL
}
```
### 2.3. `Sprite_SeaUrchin_Main` (Behavioral State Machine)
This routine manages Sea Urchin's AI through a simple state machine, using `SprAction, X` to determine its current behavior. It includes `Idle` and `Death` states.
```asm
Sprite_SeaUrchin_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw Idle
dw Death
Idle:
{
%PlayAnimation(0,3,8)
%PlayerCantPassThrough()
%DoDamageToPlayerSameLayerOnContact()
JSL Sprite_CheckDamageFromPlayer : BCC .NoDamage
%GotoAction(1) ; Transition to Death state if damaged
.NoDamage
RTS
}
Death:
{
LDA.b #$06 : STA.w SprState, X ; Set sprite state to despawn
LDA.b #$0A : STA.w SprTimerA, X
STZ.w SprPrize,X
JSL ForcePrizeDrop_long ; Force prize drop
LDA.b #$09 : JSL SpriteSFX_QueueSFX3WithPan ; Play sound effect
RTS
}
}
```
### 2.4. `Sprite_SeaUrchin_Draw` (Drawing Routine)
This routine is responsible for rendering Sea Urchin's graphics. It uses a custom OAM allocation and manipulation logic to handle its multi-tile appearance and animation.
```asm
Sprite_SeaUrchin_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $02, $03, $04, $05, $06, $07
.nbr_of_tiles
db 0, 0, 0, 0, 0, 0, 0, 0
.x_offsets
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
.y_offsets
dw 0
dw -1
dw 0
dw -1
dw 0
dw -1
dw 0
dw -1
.chr
db $EA
db $EC
db $EA
db $EC
db $EA
db $EC
db $EA
db $EC
.properties
db $29
db $29
db $69
db $69
db $29
db $29
db $69
db $69
}
```
## 3. Key Behaviors and Implementation Details
* **Fixed Health:** Sea Urchin has a fixed health of `06` and its health is not dynamically scaled based on Link's sword level.
* **Dynamic Prize Drop and Imperviousness:** A notable feature is its conditional behavior based on the `WORLDFLAG`. If this flag is set (e.g., indicating a specific game area like the Eon Sea), the Sea Urchin becomes impervious to sword attacks (`SprDefl`) and drops a different prize. This demonstrates how global game state variables can influence individual sprite properties.
* **State Management:** Sea Urchin uses a simple state machine with `Idle` and `Death` states, managed by `SprAction, X` and `JumpTableLocal`.
* **Movement Patterns:** The Sea Urchin has a simple idle animation (`%PlayAnimation(0,3,8)`) and does not exhibit complex movement behaviors. It remains stationary but can be pushed by Link (`%PlayerCantPassThrough()`).
* **Damage Handling:** Upon taking damage from Link (`Sprite_CheckDamageFromPlayer`), the Sea Urchin transitions to its `Death` state. In this state, it despawns (`STZ.w SprState, X`), forces a prize drop (`ForcePrizeDrop_long`), and plays a sound effect (`SpriteSFX_QueueSFX3WithPan`).
* **Custom OAM Drawing:** Sea Urchin utilizes a custom OAM drawing routine to render its multi-tile appearance and animation. The drawing logic includes coordinate calculations with `REP`/`SEP` for 16-bit operations.

View File

@@ -0,0 +1,313 @@
# Thunder Ghost Sprite Analysis
This document provides a detailed analysis of the `thunder_ghost.asm` sprite, outlining its properties, core routines, and behavioral patterns.
## 1. Sprite Properties
The following `!SPRID` constants define Thunder Ghost's fundamental characteristics:
```asm
!SPRID = Sprite_ThunderGhost
!NbrTiles = 03 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = 10 ; Number of Health the sprite have (dynamically set in _Prep)
!Damage = 00 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 09 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
```
**Note:** `!Health` is initially set to `10` but is dynamically determined during initialization based on Link's sword level.
## 2. Core Routines
### 2.1. `Sprite_ThunderGhost_Long` (Main Loop)
This is the primary entry point for Thunder Ghost's per-frame execution. It handles drawing, shadow rendering (conditionally), and then dispatches to the main logic routine if the sprite is active.
```asm
Sprite_ThunderGhost_Long:
{
PHB : PHK : PLB
JSR Sprite_ThunderGhost_Draw
LDA.w SprAction, X : CMP.b #$03 : BCS + ; Don't draw shadow if casting thunder
JSL Sprite_DrawShadow
+
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_ThunderGhost_Main
.SpriteIsNotActive
PLB
RTL
}
```
### 2.2. `Sprite_ThunderGhost_Prep` (Initialization)
This routine is executed once when Thunder Ghost is first spawned. It sets its health based on Link's sword level and initializes `SprTimerA` and `SprTimerB`.
```asm
Sprite_ThunderGhost_Prep:
{
PHB : PHK : PLB
LDA.l Sword : DEC A : TAY
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
LDA.b #$08 : STA.w SprTimerB, X
LDA.b #$08 : STA.w SprTimerA, X
PLB
RTL
.health
db $06, $0A, $0C, $10 ; Health values for each sword level
}
```
### 2.3. `Sprite_ThunderGhost_Main` (Behavioral State Machine)
This routine manages Thunder Ghost's AI through a state machine, using `SprAction, X` to determine its current behavior. It includes states for facing forward, left, and right, as well as states for casting thunder in different directions.
```asm
Sprite_ThunderGhost_Main:
{
%SpriteJumpTable(ThunderGhostFaceForward,
ThunderGhostLeft,
ThunderGhostRight,
CastThunderLeft,
CastThunderRight)
ThunderGhostFaceForward:
{
%PlayAnimation(0, 1, 16)
JSR Sprite_ThunderGhost_Move
RTS
}
ThunderGhostLeft:
{
%PlayAnimation(2, 3, 16)
JSR Sprite_ThunderGhost_Move
RTS
}
ThunderGhostRight:
{
%PlayAnimation(4, 5, 16)
JSR Sprite_ThunderGhost_Move
RTS
}
CastThunderLeft:
{
%StartOnFrame(6)
%PlayAnimation(6, 6, 16)
JSL Sprite_CheckDamageToPlayer
JSL Sprite_MoveLong
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
STZ.w SprState, X ; Clear sprite state (despawn?)
+
RTS
}
CastThunderRight:
{
%StartOnFrame(6)
%PlayAnimation(7, 7, 16)
JSL Sprite_CheckDamageToPlayer
JSL Sprite_MoveLong
LDA.w SprTimerA, X : BNE + ; If timer A is not 0
STZ.w SprState, X ; Clear sprite state (despawn?)
+
RTS
}
}
```
### 2.4. `Sprite_ThunderGhost_Move` (Movement and Interaction Logic)
This routine handles Thunder Ghost's movement, collision, and interaction with the player. It also includes logic for randomly triggering lightning attacks and changing its facing direction.
```asm
Sprite_ThunderGhost_Move:
{
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
JSL Sprite_PlayerCantPassThrough
JSL Sprite_DamageFlash_Long
JSL Sprite_CheckIfRecoiling
LDA.w SprTimerC, X : BNE ++ ; Check timer C
JSL GetRandomInt : AND #$3F : BNE ++ ; Random chance to spawn lightning
LDA.b #$40 : STA.w SprTimerC, X ; Set timer C
JSR SpawnLightningAttack ; Spawn lightning attack
++
LDA.w SprTimerA, X : BNE + ; Check timer A
JSL Sprite_IsToRightOfPlayer : CPY.b #$01 : BNE .ToRight ; Determine if to the right of Link
%GotoAction(1) ; Transition to ThunderGhostLeft
JMP .Continue
.ToRight
%GotoAction(2) ; Transition to ThunderGhostRight
LDA.b #$20 : STA.w SprTimerA, X ; Set timer A
JMP .Continue
+
%GotoAction(0) ; Transition to ThunderGhostFaceForward
.Continue
LDA.w SprMiscB, X
JSL JumpTableLocal
dw ThunderGhostMove
ThunderGhostMove:
{
JSL GetRandomInt : AND.b #$03
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_CheckTileCollision
JSL Sprite_CheckDamageFromPlayer
JSL Sprite_CheckDamageToPlayer
RTS
}
}
```
### 2.5. `SpawnLightningAttack`
This routine is responsible for spawning the lightning attack sprite. It sets up the lightning's initial properties, including its `SprSubtype`, action, position, and speed, based on Thunder Ghost's position relative to Link.
```asm
SpawnLightningAttack:
{
PHX
LDA.b #$CD ; Sprite ID for lightning (assuming $CD is the lightning sprite ID)
JSL Sprite_SpawnDynamically : BMI .no_space
; Use SprXSpeed, SprYSpeed, SprXRound, SprYRound
; SprX, SprY, SprXH, SprY, to cast the lightning spell
; and make it move off to the bottom left or bottom right
; Y is the ID of the new attack sprite
; X is the ID of the current source sprite
; Left 0 or Right 1
PHY
JSL Sprite_IsToRightOfPlayer : TAY : CMP.b #$01 : BEQ + ; Determine if to the right of Link
LDA.b #$00
JMP .Continue
+
LDA.b #$01
.Continue
CLC : ADC.b #$03
PLY
STA.w SprSubtype, Y ; Set SprSubtype for lightning
STA.w SprAction, Y ; Set action for lightning
LDA.w SprX, X : STA.w SprX, Y
LDA.w SprY, X : STA.w SprY, Y
LDA.w SprXH, X : STA.w SprXH, Y
LDA.w SprYH, X : STA.w SprYH, Y
LDA.w SprXSpeed, X : STA.w SprXSpeed, Y
LDA.w SprYSpeed, X : STA.w SprYSpeed, Y
LDA.b #$02 : STA.w SprXRound, Y
LDA.b #$02 : STA.w SprYRound, Y
LDA.b #$30 : STA.w SprTimerA, Y
LDA.b #$30 : STA.w SprTimerB, Y
.no_space
PLX
RTS
}
```
### 2.6. `Sprite_ThunderGhost_Draw` (Drawing Routine)
This routine is responsible for rendering Thunder Ghost's graphics. It uses the `%DrawSprite()` macro, which reads from a set of data tables to handle its multi-tile appearance and animation.
```asm
Sprite_ThunderGhost_Draw:
{
%DrawSprite()
.start_index
db $00, $03, $06, $09, $0C, $0F, $12, $15
.nbr_of_tiles
db 2, 2, 2, 2, 2, 2, 2, 2
.x_offsets
dw 0, 0, 8
dw 8, 0, 0
dw 0, 0, 8
dw 0, 0, 8
dw 0, 8, 0
dw 0, 8, 0
dw -12, -8, -16
dw 12, 16, 20
.y_offsets
dw -8, 0, -8
dw -8, 0, -8
dw 0, -8, -8
dw 0, -8, -8
dw 0, -8, -8
dw 0, -8, -8
dw 12, 24, 20
dw 12, 24, 12
.chr
db $3A, $02, $3B
db $3A, $02, $3B
db $20, $00, $01
db $22, $10, $11
db $20, $00, $01
db $22, $10, $11
db $28, $2A, $2B
db $28, $2A, $2B
.properties
db $2B, $2B, $2B
db $6B, $6B, $6B
db $2B, $2B, $2B
db $2B, $2B, $2B
db $6B, $6B, $6B
db $6B, $6B, $6B
db $2B, $2B, $2B
db $6B, $2B, $2B
.sizes
db $00, $02, $00
db $00, $02, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
db $02, $00, $00
}
```
## 3. Key Behaviors and Implementation Details
* **Dynamic Health:** Thunder Ghost's health is determined at spawn time based on Link's current sword level, allowing for dynamic difficulty scaling.
* **Conditional Shadow Drawing:** The shadow is not drawn when Thunder Ghost is in its `CastThunderLeft` or `CastThunderRight` states, suggesting a visual distinction during its attack.
* **Lightning Attack:** Thunder Ghost has a random chance to spawn a lightning attack (`SpawnLightningAttack`) at regular intervals, which then becomes an independent sprite with its own movement and interaction logic.
* **State Management:** Thunder Ghost uses `SprAction, X` and `%SpriteJumpTable` to manage its facing direction (forward, left, right) and its thunder-casting states.
* **Movement Patterns:** Thunder Ghost moves randomly and applies speed towards the player, while also bouncing from tile collisions and being unable to be passed through by Link.
* **Projectile Spawning with Directional Logic:** The `SpawnLightningAttack` routine demonstrates how to spawn a projectile (`$CD`) and initialize its properties, including its `SprSubtype` and `SprAction`, based on Thunder Ghost's position relative to Link.
* **`SprTimerA`, `SprTimerB`, `SprTimerC` Usage:** These timers are used to control the frequency of lightning attacks and the duration of facing/movement states.
* **`Sprite_MoveLong`:** Used in the `CastThunderLeft` and `CastThunderRight` states, suggesting a specific movement behavior during the attack animation.

View File

@@ -0,0 +1,80 @@
# Twinrova Boss Sprite Analysis
## Overview
The `twinrova` sprite (ID: `Sprite_Twinrova`, which is `$CE`) is a complex, multi-phase boss designed to override the vanilla Blind and Blind Maiden sprites. It features a dramatic transformation from Blind Maiden into Twinrova, followed by alternating phases where Twinrova switches between Koume (fire) and Kotake (ice) forms, each possessing distinct attacks and environmental interactions.
## Key Properties:
* **Sprite ID:** `Sprite_Twinrova` (`$CE`)
* **Description:** A multi-phase boss that transforms from Blind Maiden, then alternates between fire (Koume) and ice (Kotake) forms.
* **Number of Tiles:** 6
* **Health:** `00` (Health is managed by `Sprite_Twinrova_CheckIfDead` and phase transitions.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks.)
* **Special Properties:**
* `!Boss = 01` (Correctly identified as a boss.)
* `!Shadow = 01` (Draws a shadow.)
* `!Hitbox = 03`
* `!CollisionLayer = 01` (Checks both layers for collision.)
## Custom Variables/Macros:
* `!AnimSpeed = 8`: Defines the animation speed for various states.
* `Twinrova_Front()`, `Twinrova_Back()`, `Twinrova_Ready()`, `Twinrova_Attack()`, `Show_Koume()`, `Show_Kotake()`, `Twinrova_Hurt()`: Macros for playing specific animations, enhancing code readability.
* `$AC`: A RAM address used to store the current attack type (Fire or Ice).
## Main Logic Flow (`Sprite_Twinrova_Main`):
The boss's behavior is governed by a detailed state machine:
* **`Twinrova_Init` (0x00):** Initial state. Displays an introductory message and transitions to `Twinrova_MoveState`.
* **`Twinrova_MoveState` (0x01):** The core movement and phase management state. It checks `SprHealth, X` to determine if Twinrova is in Phase 1 (single entity) or Phase 2 (alternating forms).
* **Phase 1:** Twinrova moves around, randomly spawning Fire/Ice Keese, or preparing Fire/Ice attacks.
* **Phase 2:** Twinrova alternates between `Twinrova_KoumeMode` (fire) and `Twinrova_KotakeMode` (ice) forms.
* **`Twinrova_MoveForwards` (0x02), `Twinrova_MoveBackwards` (0x03):** Handles movement using `Sprite_FloatTowardPlayer` and `Sprite_CheckTileCollision`.
* **`Twinrova_PrepareAttack` (0x04):** Prepares either a Fire or Ice attack based on the value in `$AC`.
* **`Twinrova_FireAttack` (0x05):** Executes a Fire attack. Restores floor tiles, uses `JSL Sprite_Twinrova_FireAttack` (a shared function for the actual attack), and randomly releases fireballs (`ReleaseFireballs`).
* **`Twinrova_IceAttack` (0x06):** Executes an Ice attack using `JSL Sprite_Twinrova_IceAttack` (a shared function).
* **`Twinrova_Hurt` (0x07):** Manages Twinrova taking damage. Plays a hurt animation and, after a timer, determines whether to dodge or retaliate with a fire or ice attack.
* **`Twinrova_KoumeMode` (0x08):** Koume (fire) form. Spawns pit hazards (`AddPitHazard`), falling tiles (`Ganon_SpawnFallingTilesOverlord`), and fireballs (`Sprite_SpawnFireball`). Uses `RageModeMove` for dynamic movement.
* **`Twinrova_KotakeMode` (0x09):** Kotake (ice) form. Can spawn lightning (`JSL $1DE612`) and uses `RageModeMove` for dynamic movement.
* **`Twinrova_Dead` (0x0A):** Handles Twinrova's death sequence, killing all spawned friends and playing a hurt animation.
## Initialization (`Sprite_Twinrova_Prep`):
* Checks for the presence of the Blind Maiden (`$7EF3CC = $06`). If the Maiden is present, Twinrova is killed, indicating that Twinrova spawns *from* the Blind Maiden.
* Sets initial health to `$5A` (90 decimal).
* Configures deflection (`SprDefl = $80`), bump damage (`SprBump = $04`), and ensures Twinrova is not invincible.
* Configures Blind Boss startup parameters and initializes various timers and `SprMisc` variables.
## Death Check (`Sprite_Twinrova_CheckIfDead`):
* Monitors `SprHealth, X`. If health is zero or negative, it triggers the boss's death sequence, setting `SprState = $04` (kill sprite boss style) and `SprAction = $0A` (Twinrova_Dead stage).
## Movement (`RageModeMove`, `DoRandomStrafe`, `VelocityOffsets`):
* **`RageModeMove`:** A sophisticated routine for dynamic, floaty movement. It randomly determines a movement mode (predictive movement towards player, random strafe, random dodge, stay in place) based on timers and probabilities. It also handles evasive actions.
* **`DoRandomStrafe`:** Generates random strafing movement.
* **`VelocityOffsets`:** A table defining X and Y speed offsets for movement.
## Environmental Interactions (`Twinrova_RestoreFloorTile`, `RestoreFloorTile`, `AddPitHazard`, `Ganon_SpawnFallingTilesOverlord`):
* **`Twinrova_RestoreFloorTile` / `RestoreFloorTile`:** Restores floor tiles, likely after they have been modified by an attack.
* **`AddPitHazard`:** Adds a pit hazard to the floor.
* **`Ganon_SpawnFallingTilesOverlord`:** Spawns falling tiles (reused from Ganon's mechanics).
## Drawing (`Sprite_Twinrova_Draw`):
* Uses standard OAM allocation routines.
* Handles complex animation frames, x/y offsets, character data, properties, and sizes for drawing Twinrova.
* Utilizes 16-bit operations for precise drawing calculations.
## Graphics Transfer (`ApplyTwinrovaGraphics`):
* Handles DMA transfer of graphics data (`twinrova.bin`) to VRAM.
## Attack Spawning (`Fireball_Configure`, `ReleaseFireballs`, `Sprite_SpawnFireKeese`, `Sprite_SpawnIceKeese`, `JSL Sprite_SpawnFireball`, `JSL $1DE612` (Sprite_SpawnLightning)):
* Twinrova can spawn various projectiles and enemies, including fireballs, Fire Keese, Ice Keese, and lightning.
## Blind Maiden Integration:
Twinrova's fight is deeply integrated with the Blind Maiden mechanics:
* **`Follower_BasicMover`:** This routine is hooked to check if the follower is the Blind Maiden, triggering the transformation to Twinrova.
* **`Follower_CheckBlindTrigger`:** Checks if the Blind Maiden follower is within a specific trigger area.
* **`Blind_SpawnFromMaiden`:** This is the core routine for the transformation. It applies Twinrova graphics, sets Twinrova's initial state and position based on the Maiden's, and sets various timers and properties.
* **`SpritePrep_Blind_PrepareBattle`:** This routine is overridden to handle Twinrova's prep or to despawn if a room flag is set.
## Discrepancies/Notes:
* **Health Management:** The `!Health` property is `00`. The boss's health is managed by `Sprite_Twinrova_CheckIfDead` and phase transitions.
* **Code Reuse:** There is extensive code reuse from other sprites/bosses (e.g., `Sprite_Twinrova_FireAttack` is also used by KydreeokHead, `Ganon_SpawnFallingTilesOverlord` in Koume mode, `Sprite_SpawnFireKeese`/`Sprite_SpawnIceKeese` in MoveState). This is an efficient practice but requires careful management to ensure thematic consistency and avoid unintended side effects.
* **Hardcoded Addresses:** Several `JSL` calls are to hardcoded addresses (e.g., `JSL $1DE612` for lightning). These should ideally be replaced with named labels for better maintainability.
* **Blind Maiden Overrides:** The boss heavily relies on overriding vanilla Blind Maiden behavior, which is a common ROM hacking technique but requires careful understanding of the original game's code.
* **`TargetPositions`:** This table is defined but appears unused in the provided code.

View File

@@ -0,0 +1,46 @@
# Vampire Bat Mini-Boss Sprite Analysis
## Overview
The `vampire_bat` sprite is a mini-boss, a specialized enemy that utilizes the generic Keese sprite ID (`$11`) but differentiates its behavior through `SprSubtype = 02`. It features more complex movement patterns and attacks compared to a standard Keese, including ascending, flying around, descending, and spawning other Keese.
## Key Properties:
* **Sprite ID:** `0x11` (Custom Keese Subtype 02)
* **Description:** A mini-boss variant of the Keese, with enhanced movement and attack capabilities.
* **Number of Tiles:** 8 (Inherited from the base Keese sprite.)
* **Health:** `32` (decimal, set in `Sprite_Keese_Prep` based on subtype.)
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks.)
* **Special Properties:**
* `!Boss = 00` (Not marked as a boss, but functions as a mini-boss/special enemy.)
* `!Shadow = 01` (Draws a shadow.)
## Main Logic Flow (`Sprite_VampireBat_Main`):
The Vampire Bat's behavior is governed by a state machine:
* **`VampireBat_Idle` (0x00):** Waits for Link to approach within a specified distance (`$24`). Transitions to `VampireBat_Ascend`.
* **`VampireBat_Ascend` (0x01):** Plays an ascending animation, increases its `SprHeight` to `$50`, and randomly spawns a Fire Keese (`Sprite_SpawnFireKeese`). Transitions to `VampireBat_FlyAround`.
* **`VampireBat_FlyAround` (0x02):** Plays a flying animation, moves towards Link (`Sprite_ProjectSpeedTowardsPlayer`), and randomly selects new directions (`Sprite_SelectNewDirection`). Transitions to `VampireBat_Descend` after a timer.
* **`VampireBat_Descend` (0x03):** Plays a descending animation, decreases its `SprHeight` until it's on the ground, and randomly uses `Sprite_Twinrova_FireAttack`. Transitions back to `VampireBat_Idle` after a timer.
## Initialization (from `Sprite_Keese_Prep` in `keese.asm`):
The Vampire Bat does not have its own `_Prep` routine and relies on the generic `Sprite_Keese_Prep` routine in `keese.asm`. When `SprSubtype = 02`:
* `SprHealth` is set to `$20` (32 decimal).
* `SprDefl` is set to `$80`.
* `SprTimerC` is set to `$30`.
## Drawing (`Sprite_VampireBat_Draw`):
* This routine is called from `Sprite_Keese_Long` in `keese.asm` when `SprSubtype = 02`.
* Uses standard OAM allocation routines.
* Handles animation frames, x/y offsets, character data, properties, and sizes specific to the Vampire Bat's appearance.
## Attack Spawning (`Sprite_SpawnFireKeese`, `Sprite_SpawnIceKeese`):
* **`Sprite_SpawnFireKeese`:** Spawns a Keese sprite (`$11`) with `SprSubtype = $01` (Fire Keese).
* **`Sprite_SpawnIceKeese`:** Spawns a Keese sprite (`$11`) with `SprSubtype = $00` (Ice Keese).
## Interactions:
* **Damage:** Responds to damage from Link, including flashing and bouncing from tile collisions.
* **Attacks:** Can spawn Fire Keese and utilize `Sprite_Twinrova_FireAttack` (a shared attack function).
## Discrepancies/Notes:
* **Shared Sprite ID:** The Vampire Bat efficiently reuses the generic Keese sprite ID (`$11`), with `SprSubtype = 02` serving as the primary differentiator for its unique behavior.
* **Health Management:** Its health is configured within the generic `Sprite_Keese_Prep` routine based on its subtype.
* **Code Reuse:** It reuses `Sprite_Twinrova_FireAttack`, demonstrating efficient code sharing across different boss/mini-boss sprites.
* **Hardcoded Values:** Many numerical values for timers, speeds, and offsets are hardcoded. Replacing these with named constants would improve readability and maintainability.

View File

@@ -0,0 +1,62 @@
# Wolfos Mini-Boss Sprite Analysis
## Overview
The `wolfos` sprite (ID: `Sprite_Wolfos`, which is `$A9`) functions as a mini-boss or special enemy. It engages Link in combat with various movement and attack patterns. A key aspect of this sprite is its integration into a mask quest, where it can be subdued and, under specific conditions, grants Link the Wolf Mask.
## Key Properties:
* **Sprite ID:** `Sprite_Wolfos` (`$A9`)
* **Description:** A mini-boss/special enemy that fights Link and is part of a mask quest.
* **Number of Tiles:** 4
* **Health:** `30` (decimal)
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks.)
* **Special Properties:**
* `!Boss = 00` (Not marked as a boss, but functions as a mini-boss/special enemy.)
* `!ImperviousArrow = 01` (Impervious to arrows.)
## Custom Variables/Macros:
* `WolfosDialogue = SprMiscD`: Stores a flag to control Wolfos dialogue.
* `Wolfos_AnimateAction = SprMiscE`: Stores the current animation action.
* `AttackForward()`, `AttackBack()`, `WalkRight()`, `WalkLeft()`, `AttackRight()`, `AttackLeft()`, `Subdued()`, `GrantMask()`, `Dismiss()`: Macros for setting `SprAction` and `Wolfos_AnimateAction`, improving code clarity.
* `!NormalSpeed = $08`, `!AttackSpeed = $0F`: Constants for movement speeds.
## Main Logic Flow (`Sprite_Wolfos_Main`):
The Wolfos's behavior is governed by a state machine:
* **`Wolfos_AttackForward` (0x00), `Wolfos_AttackBack` (0x01), `Wolfos_WalkRight` (0x02), `Wolfos_WalkLeft` (0x03), `Wolfos_AttackRight` (0x04), `Wolfos_AttackLeft` (0x05):** These states manage the Wolfos's movement and attacks. They call `Wolfos_Move` and can randomly trigger attack actions with increased speed and temporary imperviousness.
* **`Wolfos_Subdued` (0x06):** In this state, the Wolfos stops moving, displays dialogue (`$23`), and waits for Link to play the Song of Healing (`SongFlag = $01`). If the song is played, it transitions to `Wolfos_GrantMask`.
* **`Wolfos_GrantMask` (0x07):** Displays the Wolfos mask graphic, shows a message (`$10F`), grants Link the `WolfMask` item, and transitions to `Wolfos_Dismiss`.
* **`Wolfos_Dismiss` (0x08):** Stops moving, kills the sprite, and clears Link's `BRANDISH` flag.
## Initialization (`Sprite_Wolfos_Prep`):
* Checks if Link is outdoors (`$1B`). If so, it further checks if the Wolfos has already been defeated (`$7EF303 = $01`). If defeated, the sprite is killed to prevent respawning.
* Sets initial timers (`SprTimerA = $40`, `SprTimerC = $40`).
* Configures deflection properties (`SprDefl = $82`, making it impervious to arrows).
* Sets `SprNbrOAM = $08` and initializes `SprMiscG, X` and `SprMiscE, X` to `0`.
## Defeat Check (`Sprite_Wolfos_CheckIfDefeated`):
* Checks if Link is outdoors. If `SprHealth, X` drops below `$04`, the Wolfos is considered "defeated."
* Upon defeat, it sets `SprAction = $06` (Wolfos_Subdued), `SprState = $09` (normal state, avoiding a full death animation), refills its health to `$40`, and clears `WolfosDialogue`. This indicates pacification rather than outright killing.
## Movement (`Wolfos_Move`, `Wolfos_DecideAction`, `Wolfos_MoveAction_Basic`, `Wolfos_MoveAction_CirclePlayer`, `Wolfos_MoveAction_Dodge`):
* **`Wolfos_Move`:** Handles damage flash, checks damage from player, prevents player from passing through, bounces from tile collision, checks for recoiling, moves the sprite, and calls `Wolfos_DecideAction`.
* **`Wolfos_DecideAction`:** Determines the Wolfos's next movement action based on timers and random chance. It uses a jump table to select between `Wolfos_MoveAction_Basic`, `Wolfos_MoveAction_CirclePlayer`, and `Wolfos_MoveAction_Dodge`.
* **`Wolfos_MoveAction_Basic`:** Basic movement towards or away from Link based on distance.
* **`Wolfos_MoveAction_CirclePlayer`:** Attempts to circle the player.
* **`Wolfos_MoveAction_Dodge`:** Dodges by applying speed towards the player.
## Animation (`Sprite_Wolfos_Animate`):
* This routine is called from `Sprite_Wolfos_Main`.
* It uses `Wolfos_AnimateAction` (stored in `SprMiscE, X`) to determine which animation to play.
* It has separate animation routines for `AttackForward`, `AttackBack`, `WalkRight`, `WalkLeft`, `AttackRight`, `AttackLeft`, and `Subdued`.
* It also spawns sparkle garnishes (`JSL Sprite_SpawnSparkleGarnish`).
## Drawing (`Sprite_Wolfos_Draw`):
* Uses standard OAM allocation routines.
* Handles animation frames, x/y offsets, character data, properties, and sizes for drawing the Wolfos.
* Includes a special frame for the Wolf Mask (`$CC`) when granting the item.
## Discrepancies/Notes:
* **Mask Quest Integration:** The Wolfos is directly integrated into a mask quest, where playing the Song of Healing subdues it and leads to receiving the Wolf Mask.
* **Health Refill on Defeat:** When defeated, its health is refilled to `$40`, and its state is set to `Wolfos_Subdued`, indicating it's not truly killed but rather pacified.
* **Hardcoded Values:** Many numerical values for timers, speeds, and offsets are hardcoded. Replacing these with named constants would improve readability and maintainability.
* **`JSL Link_ReceiveItem`:** This is a standard function for giving items to Link.
* **`JSL Sprite_SpawnSparkleGarnish`:** This is a generic garnish spawning function.

90
Docs/Sprites/NPCs.md Normal file
View File

@@ -0,0 +1,90 @@
# NPCs Analysis
This document provides an analysis of the Non-Player Character (NPC) sprites found in the `Sprites/NPCs/` directory.
## File Overview
| Filename | Sprite ID(s) | Description |
|---|---|---|
| `bean_vendor.asm` | `Sprite_BeanVendor` | Handles the logic for the bean vendor who sells Magic Beans to the player. |
| `bottle_vendor.asm` | (Vanilla Hook) | Modifies the vanilla bottle vendor to handle selling milk. |
| `bug_net_kid.asm` | (Vanilla Hook) | Modifies the Sick Kid to grant the Pegasus Boots after playing the Song of Healing. |
| `deku_scrub.asm` | `Sprite_DekuScrubNPCs` | Manages various Deku Scrub NPCs, including one who gives the Deku Mask. |
| `eon_owl.asm` | `Sprite_EonOwl` | The owl that guides Link. Includes logic for both the Eon Owl and Kaepora Gaebora. |
| `eon_zora.asm` | (Part of `zora.asm`) | A friendly Zora NPC found in the Eon Abyss. |
| `eon_zora_elder.asm`| (Part of `zora.asm`) | The elder Zora in the Eon Abyss. |
| `farore.asm` | `Sprite_Farore` | The Oracle Farore, who appears in cutscenes and guides the player. |
| `followers.asm` | (Vanilla Hooks) | Contains logic for various follower characters like the Zora Baby and the Old Man. |
| `fortune_teller.asm`| (Vanilla Hook) | Modifies the fortune teller's dialogue to provide hints relevant to the hack's progression. |
| `goron.asm` | `Sprite_Goron` | Handles both the Kalyxo Goron who opens the mines and the Eon Gorons. |
| `hyrule_dream.asm` | (Part of `farore.asm`) | Logic for NPCs appearing in Link's dream sequences (Zelda, King, Soldier). |
| `impa.asm` | (Vanilla Hook) | Modifies Impa's behavior, particularly in setting spawn points. |
| `korok.asm` | `Sprite_Korok` | A friendly Korok NPC. |
| `maku_tree.asm` | `Sprite_MakuTree` | The Maku Tree, a key story NPC who provides a Heart Container. |
| `maple.asm` | (Part of `mermaid.asm`)| Maple the witch, who can send Link to dream worlds. |
| `mask_salesman.asm` | `Sprite_MaskSalesman` | The Happy Mask Salesman, who sells the Bunny Hood and Stone Mask. |
| `mermaid.asm` | `Sprite_Mermaid` | A friendly mermaid NPC. Also contains logic for Maple and the Librarian. |
| `piratian.asm` | `$0E` | A friendly pirate-like NPC that becomes aggressive if attacked. |
| `ranch_girl.asm` | (Vanilla Hook) | Modifies the chicken lady at the ranch to give the Ocarina. |
| `tingle.asm` | `$22` | Tingle, who sells dungeon maps to the player. |
| `vasu.asm` | `Sprite_Vasu` | Vasu, the jeweler who appraises magic rings. Also includes logic for Error. |
| `village_dog.asm` | `Sprite_VillageDog` | A friendly dog that interacts with the player. Includes logic for the Eon Dog. |
| `village_elder.asm` | (Part of `bean_vendor.asm`)| The village elder NPC. |
| `zora_princess.asm` | `Sprite_ZoraPrincess` | The Zora Princess, who grants the Zora Mask. |
| `zora.asm` | `Sprite_Zora` | A friendly Zora NPC. Also contains logic for the Zora Princess and Eon Zoras. |
## Detailed NPC Analysis
### `bean_vendor.asm` / `village_elder.asm`
- **Sprite ID:** `Sprite_BeanVendor`
- **Summary:** This file contains the logic for two NPCs. The primary is the Bean Vendor, who sells Magic Beans for 100 rupees. The second is the Village Elder.
- **Key Logic:**
- **BeanVendor:** Initiates a dialogue on contact. If the player agrees to buy, it checks for sufficient rupees, deducts the cost, and spawns a collectible Magic Bean sprite.
- **VillageElder:** Engages in dialogue and sets a progress flag (`OOSPROG`) after the first interaction.
### `bug_net_kid.asm`
- **Sprite ID:** (Hooks `SpritePrep_SickKid`)
- **Summary:** This modifies the vanilla "Sick Kid" NPC. Instead of giving the Bug Net, he gives the player the Pegasus Boots.
- **Key Logic:** The `SickKid_CheckForSongOfHealing` routine checks if the `SongFlag` is set. If it is, the `BugNetKid_GrantBugNet` routine is called, which uses `Link_ReceiveItem` to give the boots (`ITEMGET` ID `$4B`).
### `deku_scrub.asm`
- **Sprite ID:** `Sprite_DekuScrubNPCs`
- **Summary:** Manages several Deku Scrub NPCs, including the Deku Butler and Deku Princess. A key interaction involves a withered Deku Scrub who, after being healed with the Song of Healing, gives the player the Deku Mask.
- **Key Logic:**
- The main state machine checks for the `SongFlag`.
- If the song is played, it transitions through a dialogue sequence (`QuiereCuracion`, `DarMascara`).
- Finally, in the `Regalo` state, it calls `Link_ReceiveItem` with item ID `$11` (Deku Mask) and sets a progress flag (`$7EF301`).
### `eon_owl.asm`
- **Sprite ID:** `Sprite_EonOwl`
- **Summary:** This is the guide owl, appearing in both the overworld (as Eon Owl) and the Hall of Secrets (as Kaepora Gaebora).
- **Key Logic:**
- **Eon Owl:** In the overworld, it triggers introductory dialogue when the player gets close and then flies away.
- **Kaepora Gaebora:** In the Hall of Secrets, it appears only after all 7 crystals are collected and before the player has the Song of Soaring. It offers to teach the player the song.
### `farore.asm` / `hyrule_dream.asm`
- **Sprite ID:** `Sprite_Farore`
- **Summary:** Handles the Oracle Farore and NPCs that appear in dream sequences.
- **Key Logic:**
- **Farore:** Manages the introductory cutscene where she follows Link, sets the main story state (`$B6`), and changes the game state to post-pendants (`$7EF3C5 = 2`).
- **Dream NPCs:** Contains simple display logic for Zelda, the King, and a soldier during the `MakuTree_HasMetLink` dream sequence.
### `followers.asm`
- **Sprite ID:** (Hooks vanilla follower system)
- **Summary:** Contains significant custom logic for follower characters, most notably the Zora Baby (Locksmith) and the Old Man.
- **Key Logic:**
- **Zora Baby:**
- Replaces the Locksmith sprite (`$39`).
- Can be picked up and carried by Link.
- When placed on a water gate switch, it triggers the switch.
- Transitions from a follower to a standard sprite when on a star tile in a dungeon.
- **Old Man:** Logic is modified to grant the Goldstar (Hookshot Lv2 upgrade) instead of the Magic Mirror.
### `vasu.asm`
- **Sprite ID:** `Sprite_Vasu`
- **Summary:** This is the ring jeweler, Vasu. He can appraise rings the player has found. The file also contains logic for the "I am Error" NPC.
- **Key Logic:**
- Vasu's main loop presents a choice: "Appraise" or "Explain".
- If "Appraise" is chosen, it checks if the player has any unappraised rings (`FOUNDRINGS`).
- It charges 20 rupees (the first one is free) and transfers the bits from `FOUNDRINGS` to `MAGICRINGS`, making them usable.
- The Error NPC appears as a subtype and gives the player a random ring when spoken to.

View File

@@ -0,0 +1,225 @@
# Bean Vendor
## Overview
The Bean Vendor is an NPC (Non-Player Character) sprite designed for player interaction, primarily through dialogue. It features a simple state machine to manage its idle and talking behaviors.
## Sprite Properties
* **`!SPRID`**: `$00` (Vanilla sprite ID, likely overridden)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `01` (Indicates the sprite is harmless to Link)
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Indicates the sprite is impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_BeanVendor_Long`)
This routine is the main entry point for the Bean Vendor, executed every frame. It handles drawing, shadow rendering, and dispatches to the main logic if the sprite is active.
```asm
Sprite_BeanVendor_Long:
{
PHB : PHK : PLB
JSR Sprite_BeanVendor_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_BeanVendor_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_BeanVendor_Prep`)
This routine runs once when the Bean Vendor is spawned. It initializes `SprDefl, X`, `SprTimerC, X`, `SprNbrOAM, X`, and `SprPrize, X`.
```asm
Sprite_BeanVendor_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.b #$30 : STA.w SprTimerC, X
LDA.b #$03 : STA.w SprNbrOAM, X
LDA.b #$03 : STA.w SprPrize, X
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_BeanVendor_Main`)
The Bean Vendor's core behavior is managed by a state machine with `BeanVendor_Idle` and `BeanVendor_Talk` states.
* **`BeanVendor_Idle`**: The vendor plays an idle animation. When Link is nearby (`GetDistance8bit_Long`), it transitions to the `BeanVendor_Talk` state.
* **`BeanVendor_Talk`**: The vendor plays a talking animation and displays a message using `JSL Interface_PrepAndDisplayMessage`. Once the message is dismissed, it transitions back to the `BeanVendor_Idle` state.
```asm
Sprite_BeanVendor_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw BeanVendor_Idle
dw BeanVendor_Talk
BeanVendor_Idle:
{
%PlayAnimation(0,1,15)
JSL GetDistance8bit_Long : CMP.b #$20 : BCS +
INC.w SprAction, X
+
RTS
}
BeanVendor_Talk:
{
%PlayAnimation(2,3,8)
JSL Interface_PrepAndDisplayMessage : BCC +
STZ.w SprAction, X
+
RTS
}
}
```
## Drawing (`Sprite_BeanVendor_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_BeanVendor_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
LDA.w SprMiscB, X : STA $09
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
; If SprMiscA != 0, then use 4th sheet
LDA.b $09 : BEQ +
LDA .chr_2, X : STA ($90), Y
JMP ++
+
LDA .chr, X : STA ($90), Y
++
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $03, $04, $06, $08
.nbr_of_tiles
db 0, 1, 0, 1, 1, 0
.x_offsets
dw 0
dw -4, 4
dw 0
dw -4, 4
dw -4, 4
dw 0
.y_offsets
dw 0
dw 0, 0
dw 0
dw 0, 0
dw 0, 0
dw 0
.chr
db $80
db $A2, $A2
db $82
db $84, $84
db $A4, $A4
db $A0
.chr_2
db $C0
db $E2, $E2
db $C2
db $C4, $C4
db $E4, $E4
db $E0
.properties
db $35
db $35, $75
db $35
db $35, $75
db $35, $75
db $35
.sizes
db $02
db $02, $02
db $02
db $02, $02
db $02, $02
db $02
}
```
## Design Patterns
* **NPC Interaction**: The sprite is designed to engage with the player through dialogue, triggered by proximity.
* **State Machine**: Employs a simple state machine to manage its `Idle` and `Talk` behaviors, ensuring appropriate animations and actions based on player interaction.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,225 @@
# Bottle Vendor
## Overview
The Bottle Vendor is an NPC (Non-Player Character) sprite designed for player interaction, primarily through dialogue. It features a simple state machine to manage its idle and talking behaviors, very similar in structure to the Bean Vendor.
## Sprite Properties
* **`!SPRID`**: `$00` (Vanilla sprite ID, likely overridden)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `01` (Indicates the sprite is harmless to Link)
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Indicates the sprite is impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_BottleVendor_Long`)
This routine is the main entry point for the Bottle Vendor, executed every frame. It handles drawing, shadow rendering, and dispatches to the main logic if the sprite is active.
```asm
Sprite_BottleVendor_Long:
{
PHB : PHK : PLB
JSR Sprite_BottleVendor_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_BottleVendor_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_BottleVendor_Prep`)
This routine runs once when the Bottle Vendor is spawned. It initializes `SprDefl, X`, `SprTimerC, X`, `SprNbrOAM, X`, and `SprPrize, X`.
```asm
Sprite_BottleVendor_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.b #$30 : STA.w SprTimerC, X
LDA.b #$03 : STA.w SprNbrOAM, X
LDA.b #$03 : STA.w SprPrize, X
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_BottleVendor_Main`)
The Bottle Vendor's core behavior is managed by a state machine with `BottleVendor_Idle` and `BottleVendor_Talk` states.
* **`BottleVendor_Idle`**: The vendor plays an idle animation. When Link is nearby (`GetDistance8bit_Long`), it transitions to the `BottleVendor_Talk` state.
* **`BottleVendor_Talk`**: The vendor plays a talking animation and displays a message using `JSL Interface_PrepAndDisplayMessage`. Once the message is dismissed, it transitions back to the `BottleVendor_Idle` state.
```asm
Sprite_BottleVendor_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw BottleVendor_Idle
dw BottleVendor_Talk
BottleVendor_Idle:
{
%PlayAnimation(0,1,15)
JSL GetDistance8bit_Long : CMP.b #$20 : BCS +
INC.w SprAction, X
+
RTS
}
BottleVendor_Talk:
{
%PlayAnimation(2,3,8)
JSL Interface_PrepAndDisplayMessage : BCC +
STZ.w SprAction, X
+
RTS
}
}
```
## Drawing (`Sprite_BottleVendor_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_BottleVendor_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
LDA.w SprMiscB, X : STA $09
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
; If SprMiscA != 0, then use 4th sheet
LDA.b $09 : BEQ +
LDA .chr_2, X : STA ($90), Y
JMP ++
+
LDA .chr, X : STA ($90), Y
++
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $03, $04, $06, $08
.nbr_of_tiles
db 0, 1, 0, 1, 1, 0
.x_offsets
dw 0
dw -4, 4
dw 0
dw -4, 4
dw -4, 4
dw 0
.y_offsets
dw 0
dw 0, 0
dw 0
dw 0, 0
dw 0, 0
dw 0
.chr
db $80
db $A2, $A2
db $82
db $84, $84
db $A4, $A4
db $A0
.chr_2
db $C0
db $E2, $E2
db $C2
db $C4, $C4
db $E4, $E4
db $E0
.properties
db $35
db $35, $75
db $35
db $35, $75
db $35, $75
db $35
.sizes
db $02
db $02, $02
db $02
db $02, $02
db $02, $02
db $02
}
```
## Design Patterns
* **NPC Interaction**: The sprite is designed to engage with the player through dialogue, triggered by proximity.
* **State Machine**: Employs a simple state machine to manage its `Idle` and `Talk` behaviors, ensuring appropriate animations and actions based on player interaction.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,86 @@
# Bug Net Kid (Sick Kid)
## Overview
The Bug Net Kid, also referred to as the Sick Kid, is an NPC sprite that plays a role in a quest involving the "Song of Healing" and the acquisition of the Boots (referred to as Bug Net in the comments). This sprite is implemented by overriding vanilla game code to introduce custom interactions and progression.
## Vanilla Overrides
This sprite extensively uses `pushpc`/`pullpc` blocks and `org` directives to inject custom logic into existing vanilla routines. This approach allows for modifying the behavior of a vanilla NPC without creating a new sprite ID.
* **`org $068D7F`**: Overrides the vanilla `SpritePrep_SickKid` routine.
* **`org $06B962`**: Overrides a routine related to the kid's resting state (`BugNetKid_Resting`).
* **`org $06B9C6`**: Overrides a routine responsible for granting the item (`BugNetKid_GrantBugNet`).
## `SickKid_CheckForSongOfHealing`
This routine is a core component of the Bug Net Kid's logic. It checks if the "Song of Healing" has been played by examining a `SongFlag` (likely a WRAM address like `$7E001F`). If the song has been played, it updates internal sprite state variables (`$0D80, X`, `$02E4`) and clears the `SongFlag`.
```asm
SickKid_CheckForSongOfHealing:
{
LDA.b SongFlag : CMP.b #$01 : BNE .no_song
INC $0D80, X
INC $02E4
STZ.b SongFlag
.no_song
RTL
}
```
## `SpritePrep_SickKid` (Initialization)
This routine is executed when the Sick Kid sprite is initialized. It checks an SRAM flag (`$7EF355`) to determine if Link has already obtained the Boots. If so, it sets `$0D80, X` to `$03`. It also increments `SprBulletproof, X`, making the kid invulnerable to attacks.
```asm
SpritePrep_SickKid:
{
LDA.l $7EF355 : BEQ .no_boots
LDA.b #$03 : STA $0D80, X
.no_boots
INC.w SprBulletproof, X
RTS
}
```
## `BugNetKid_Resting` (Main Logic)
This routine controls the kid's behavior when not actively granting an item. It checks for player preoccupation and damage, and crucially, calls `SickKid_CheckForSongOfHealing`. If Link has not yet received the Boots, it displays a solicited message to the player.
```asm
BugNetKid_Resting:
{
JSL Sprite_CheckIfPlayerPreoccupied : BCS .dont_awaken
JSR Sprite_CheckDamageToPlayer_same_layer : BCC .dont_awaken
JSL SickKid_CheckForSongOfHealing
LDA.l $7EF355
CMP.b #$01 : BCC .no_boots
.dont_awaken
RTS
.no_boots
LDA.b #$04
LDY.b #$01
JSL Sprite_ShowSolicitedMessageIfPlayerFacing
RTS
}
```
## `BugNetKid_GrantBugNet` (Item Granting)
This routine is responsible for giving Link the Boots. It sets the item ID (`LDY.b #$4B`), clears a flag (`$02E9`), calls `JSL Link_ReceiveItem` to add the item to Link's inventory, and updates internal sprite state variables (`$0D80, X`, `$02E4`).
```asm
BugNetKid_GrantBugNet:
{
; Give Link the Boots
LDY.b #$4B
STZ $02E9
PHX
JSL Link_ReceiveItem
PLX
INC $0D80, X
STZ $02E4
RTS
}
```
## Design Patterns
* **Vanilla Override**: This sprite is a prime example of overriding vanilla game code to introduce new NPC interactions and quest elements without creating entirely new sprite definitions.
* **Quest/Item Gating**: The sprite's behavior and the ability to receive the Boots are directly tied to specific game progression flags, such as the `SongFlag` and the SRAM flag for the Boots (`$7EF355`).
* **NPC Interaction**: The sprite interacts with the player by displaying messages and granting a key item, driving forward a specific questline.
* **Global Flags and SRAM Usage**: Utilizes global WRAM flags (`$02E4`, `SongFlag`) and SRAM (`$7EF355`) to maintain and track the state of the quest across game sessions.

View File

@@ -0,0 +1,307 @@
# Deku Scrub
## Overview
The Deku Scrub sprite is a highly versatile NPC implementation capable of representing multiple distinct characters, including a Withered Deku Scrub, Deku Butler, and Deku Princess. Its behavior is intricately tied to game progression, player actions, and specific in-game locations.
## Sprite Properties
* **`!SPRID`**: `Sprite_DekuScrubNPCs` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `06`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `03`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_DekuScrub_Long`)
This routine is the main entry point for the Deku Scrub, executed every frame. It handles drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_DekuScrub_Long:
{
PHB : PHK : PLB
JSR Sprite_DekuScrub_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_DekuScrub_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_DekuScrub_Prep`)
This routine runs once when the Deku Scrub is spawned. It sets `SprDefl, X` and then determines the initial `SprAction, X` based on the current `AreaIndex`, `SprSubtype, X`, and whether the Deku Mask has been obtained (`$7EF301`). It also checks if Tail Palace is cleared (`Crystals`) to potentially set `SprState, X` to `0`.
```asm
Sprite_DekuScrub_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
; Peacetime Deku Scrub NPCs
LDA.b AreaIndex : CMP.b #$2E : BNE .check_next
; Deku Butler
LDA.b #$07 : STA.w SprAction, X
JMP +
.check_next
CMP.b #$2F : BNE .continue
LDA.b #$08 : STA.w SprAction, X
JMP +
.continue
LDA.w SprSubtype, X : CMP.b #$01 : BEQ .DekuButler
CMP.b #$02 : BEQ .DekuPrincess
LDA.l $7EF301 : BEQ +
LDA.b #$04 : STA.w SprAction, X
JMP +
.DekuButler
LDA.b #$05 : STA.w SprAction, X
JMP ++
.DekuPrincess
LDA.b #$06 : STA.w SprAction, X
++
; Check if tail palace is cleared
LDA.l Crystals : AND #$10 : BEQ +
STZ.w SprState, X
+
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_DekuScrub_Main`)
The Deku Scrub's core behavior is managed by a complex state machine with several states, many of which are named in Spanish:
* **`EstadoInactivo` (Inactive State)**: The scrub plays an idle animation, prevents player passage, and transitions to `QuiereCuracion` upon player interaction.
* **`QuiereCuracion` (Wants Healing)**: Plays an animation and checks if the "Song of Healing" (`SongFlag`) has been played. If so, it clears the flag, sets a timer, and transitions to `DarMascara`.
* **`DarMascara` (Give Mask)**: Plays an animation, displays a message after a timer, and then transitions to `Regalo`.
* **`Regalo` (Gift)**: After a timer, grants Link the Deku Mask (`$11`) and updates the Deku Mask flag (`$7EF301`), then transitions to `Withered`.
* **`Withered`**: Plays a withered animation.
* **`DekuButler`**: Plays a specific animation, prevents player passage, and displays a message.
* **`DekuPrincess`**: Plays a specific animation, prevents player passage, and displays a message.
* **`DekuButler_Peacetime`**: Plays a specific animation, prevents player passage, and displays a message. If the message is dismissed, it sets `MapIcon` to `$02`.
* **`DekuPrinces_Peacetime`**: Plays a specific animation, prevents player passage, and displays a message. If the message is dismissed, it sets `MapIcon` to `$02`.
```asm
Sprite_DekuScrub_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw EstadoInactivo
dw QuiereCuracion
dw DarMascara
dw Regalo
dw Withered
dw DekuButler
dw DekuPrincess
dw DekuButler_Peacetime
dw DekuPrinces_Peacetime
EstadoInactivo:
{
%PlayAnimation(0, 1, 16)
JSL Sprite_PlayerCantPassThrough
%ShowSolicitedMessage($140) : BCC .no_hablaba
%GotoAction(1)
.no_hablaba
RTS
}
QuiereCuracion:
{
%PlayAnimation(0, 1, 16)
LDA.b SongFlag : CMP.b #$01 : BNE .ninguna_cancion
STZ.b SongFlag
LDA.b #$C0 : STA.w SprTimerD, X
%GotoAction(2)
.ninguna_cancion
RTS
}
DarMascara:
{
%PlayAnimation(0, 1, 16)
LDA.w SprTimerD, X : BNE +
%ShowUnconditionalMessage($141)
LDA.b #$C0 : STA.w SprTimerD, X
%GotoAction(3)
+
RTS
}
Regalo:
{
LDA.w SprTimerD, X : BNE +
LDY #$11 : STZ $02E9 ; Give the Deku Mask
JSL Link_ReceiveItem
LDA.b #$01 : STA.l $7EF301
%GotoAction(4)
+
RTS
}
Withered:
{
%PlayAnimation(2, 2, 10)
RTS
}
DekuButler:
{
%PlayAnimation(3, 3, 10)
JSL Sprite_PlayerCantPassThrough
%ShowSolicitedMessage($080)
RTS
}
DekuPrincess:
{
%PlayAnimation(4, 4, 10)
JSL Sprite_PlayerCantPassThrough
%ShowSolicitedMessage($0C3)
RTS
}
DekuButler_Peacetime:
{
%StartOnFrame(3)
%PlayAnimation(3, 3, 10)
JSL Sprite_PlayerCantPassThrough
%ShowSolicitedMessage($1B9) : BCC +
LDA.b #$02 : STA.l MapIcon
+
RTS
}
DekuPrinces_Peacetime:
{
%StartOnFrame(4)
%PlayAnimation(4, 4, 10)
JSL Sprite_PlayerCantPassThrough
%ShowSolicitedMessage($1BA) : BCC +
LDA.b #$02 : STA.l MapIcon
+
RTS
}
}
```
## Drawing (`Sprite_DekuScrub_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_DekuScrub_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $04, $08, $0C, $10
.nbr_of_tiles
db 3, 3, 3, 3, 3
.x_offsets
dw 4, 4, -4, -4
dw 4, -4, -4, 4
dw -8, -8, 8, 8
dw -4, 4, -4, 4
dw -4, -4, 4, 4
.y_offsets
dw 4, -4, -4, 4
dw 4, 4, -4, -4
dw 4, -12, -12, 4
dw -12, -12, 4, 4
dw 4, -12, 4, -12
.chr
db $2E, $0E, $0E, $2E
db $2C, $2C, $0C, $0C
db $20, $00, $02, $22
db $04, $05, $24, $25
db $27, $07, $27, $07
.properties
db $3B, $7B, $3B, $7B
db $3B, $7B, $3B, $7B
db $3B, $3B, $3B, $3B
db $3B, $3B, $3B, $3B
db $3B, $3B, $7B, $7B
.sizes
db $02, $02, $02, $02
db $02, $02, $02, $02
db $02, $02, $02, $02
db $02, $02, $02, $02
db $02, $02, $02, $02
}
```
## Design Patterns
* **Multi-Character NPC**: A single sprite definition is used to represent multiple distinct NPC characters (Withered Deku Scrub, Deku Butler, Deku Princess), with their specific roles determined by `SprSubtype` and `AreaIndex`.
* **Quest Progression Integration**: The sprite's behavior is deeply integrated with various quest elements, checking for specific items (Deku Mask), songs (Song of Healing), and cleared dungeons (Tail Palace) to determine its current state and interactions.
* **Conditional Behavior**: Extensive use of conditional logic based on `AreaIndex`, `SprSubtype`, and global game state flags allows for dynamic changes in the NPC's role, dialogue, and actions.
* **NPC Interaction**: Provides rich interaction with the player through dialogue (`%ShowSolicitedMessage`, `%ShowUnconditionalMessage`) and the granting of key items (`Link_ReceiveItem`).
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make the NPC a solid object that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, essential for accurate sprite rendering.

204
Docs/Sprites/NPCs/EonOwl.md Normal file
View File

@@ -0,0 +1,204 @@
# Eon Owl / Kaepora Gaebora
## Overview
This sprite is a sophisticated NPC implementation that serves as both the "Eon Owl" and "Kaepora Gaebora" (a character from The Legend of Zelda: Ocarina of Time). Its appearance, behavior, and interactions are highly conditional, depending on the player's location and various game progression flags.
## Sprite Properties
* **`!SPRID`**: `Sprite_EonOwl` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `03`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `01` (Deflects all projectiles)
* **`!ImperviousArrow`**: `01` (Impervious to arrows)
* **`!ImpervSwordHammer`**: `01` (Impervious to sword and hammer attacks)
* **`!Boss`**: `00`
## Main Structure (`Sprite_EonOwl_Long`)
This routine serves as a dispatcher for the Eon Owl and Kaepora Gaebora, and includes logic for conditional despawning based on game state.
* **Kaepora Gaebora Logic**: If the `AreaIndex` is `$0E` (Hall of Secrets map) and certain conditions regarding collected crystals (`$7EF37A`) and the player's possession of the "Song of Soaring" (`$7EF34C`) are met, the sprite is identified as Kaepora Gaebora (`SprSubtype, X` set to `01`) and `Sprite_KaeporaGaebora_Draw` is called.
* **Eon Owl Logic**: Otherwise, `Sprite_EonOwl_Draw` is called.
* **Despawning**: If conditions for either character are not met, the sprite despawns (`STZ.w SprState, X`).
```asm
Sprite_EonOwl_Long:
{
PHB : PHK : PLB
; If it is not the Hall of Secrets map
LDA.b $8A : CMP.b #$0E : BNE .NotGaebora
; If the map doesn't have the 6 crystals
LDA.l $7EF37A : CMP.b #$77 : BNE .Despawn
; If the player has the Song of Soaring, despawn
LDA.l $7EF34C : CMP.b #$03 : BCS .Despawn
LDA.b #$01 : STA.w SprSubtype, X
JSR Sprite_KaeporaGaebora_Draw
JMP .HandleSprite
.NotGaebora
JSR Sprite_EonOwl_Draw
.HandleSprite
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_EonOwl_Main
.SpriteIsNotActive
PLB
RTL
.Despawn
STZ.w SprState, X
PLB
RTL
}
```
## Initialization (`Sprite_EonOwl_Prep`)
This routine initializes the sprite upon spawning, including setting its hitbox and handling conditional despawning for the intro sequence.
* **Hitbox**: `SprHitbox, X` is set to `0`.
* **Kaepora Gaebora Initialization**: If `AreaIndex` is `$0E`, `SprTimerA, X` is set to `$20` and `SprAction, X` to `$03`.
* **Intro Despawn**: If `AreaIndex` is `$50` (Intro Map) and Link already has the Sword, the sprite despawns.
```asm
Sprite_EonOwl_Prep:
{
PHB : PHK : PLB
STZ.w SprHitbox, X
LDA.b $8A : CMP.b #$0E : BNE .NotGaebora
LDA.b #$20 : STA.w SprTimerA, X
LDA.b #$03 : STA.w SprAction, X
.NotGaebora
LDA.w AreaIndex : CMP.b #$50 : BNE .not_intro
; If Map 0x50, don't spawn after getting sword
LDA.l Sword : CMP.b #$01 : BCC .continue
STZ.w SprState, X
.continue
.not_intro
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_EonOwl_Main`)
This routine manages the various states and behaviors of both the Eon Owl and Kaepora Gaebora.
* **`EonOwl_Idle`**: The Eon Owl plays an idle animation and transitions to `EonOwl_IntroDialogue` when Link is nearby.
* **`EonOwl_IntroDialogue`**: Displays an introductory message and then transitions to `EonOwl_FlyingAway`.
* **`EonOwl_FlyingAway`**: The Eon Owl plays a flying animation, moves upwards, and despawns after a timer.
* **`KaeporaGaebora`**: Kaepora Gaebora plays an idle animation and, if Link is at a certain distance and a timer allows, displays a message and transitions to `KaeporaGaebora_Respond`.
* **`KaeporaGaebora_Respond`**: Processes the player's dialogue choice. If the player declines, it transitions back to `KaeporaGaebora`. If the player accepts, it transitions to `KaeporaGaebora_FlyAway` and grants the "Song of Soaring" (`$7EF34C`).
* **`KaeporaGaebora_FlyAway`**: Kaepora Gaebora flies upwards and despawns after a timer.
```asm
Sprite_EonOwl_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw EonOwl_Idle
dw EonOwl_IntroDialogue
dw EonOwl_FlyingAway
dw KaeporaGaebora
dw KaeporaGaebora_Respond
dw KaeporaGaebora_FlyAway
EonOwl_Idle:
{
%PlayAnimation(0,1,16)
JSL GetDistance8bit_Long : CMP #$28 : BCS .not_too_close
%GotoAction(1)
.not_too_close
RTS
}
EonOwl_IntroDialogue:
{
%PlayAnimation(0,1,16)
%ShowUnconditionalMessage($00E6)
LDA.b #$C0 : STA.w SprTimerA, X
%GotoAction(2)
RTS
}
EonOwl_FlyingAway:
{
%PlayAnimation(2,3,10)
LDA.b #$F8 : STA.w SprYSpeed, X
JSL Sprite_Move
LDA.w SprTimerA, X : CMP.b #$80 : BNE +
LDA.b #$40 : STA.w SprXSpeed, X
+
LDA.w SprTimerA, X : BNE .not_done
STZ.w SprState, X
.not_done
RTS
}
; 0x03 - Kaepora Gaebora
KaeporaGaebora:
{
%PlayAnimation(0,0,1)
JSL GetDistance8bit_Long : CMP.b #$50 : BCC .not_ready
LDA.w SprTimerA, X : BNE .not_ready
%ShowUnconditionalMessage($146)
%GotoAction(4)
.not_ready
RTS
}
KaeporaGaebora_Respond:
{
LDA $1CE8 : BNE .player_said_no
%GotoAction(3)
RTS
.player_said_no
%GotoAction(5)
LDA.b #$60 : STA.w SprTimerA, X
LDA.b #$03 : STA.l $7EF34C
RTS
}
FlyAwaySpeed = 10
KaeporaGaebora_FlyAway:
{
LDA.b #-FlyAwaySpeed : STA.w SprYSpeed, X
JSL Sprite_Move
LDA.w SprTimerA, X : BNE .not_ready
STZ.w SprState, X
.not_ready
RTS
}
}
```
## Drawing (`Sprite_EonOwl_Draw` and `Sprite_KaeporaGaebora_Draw`)
Both drawing routines handle OAM allocation and animation, using `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each has its own specific OAM data for rendering the respective character.
## Design Patterns
* **Multi-Character NPC**: A single sprite definition dynamically represents two distinct NPCs (Eon Owl and Kaepora Gaebora) based on `AreaIndex` and game state, showcasing efficient sprite reuse.
* **Conditional Spawning/Despawning**: The sprite's visibility and existence are tightly controlled by game progression, including collected items (crystals, sword) and player inventory (Song of Soaring), making it appear only when relevant to the narrative.
* **Quest Progression Integration**: The sprite's dialogue and actions are directly linked to specific quest milestones, guiding the player through the game's story.
* **NPC Interaction with Dialogue Choices**: Kaepora Gaebora presents the player with dialogue options, and the player's choice influences game outcomes, such as receiving the "Song of Soaring."
* **Flying Behavior**: Implements realistic flying animations and movement, including flying away sequences with controlled speed and timers.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering and positioning.

View File

@@ -0,0 +1,214 @@
# Eon Zora
## Overview
The Eon Zora is an NPC (Non-Player Character) sprite found in the Eon Abyss. Its behavior is characterized by random movement and context-sensitive dialogue that changes based on Link's current location within the game world.
## Sprite Properties
Explicit sprite properties (`!SPRID`, `!NbrTiles`, etc.) are not defined within this file. It is assumed that these properties are either inherited from a vanilla sprite ID or defined in a separate configuration file, as this file focuses on the sprite's behavior and drawing.
## Main Logic (`Sprite_EonZora_Main`)
This routine is the main entry point for the Eon Zora, executed every frame. It orchestrates the Zora's dialogue, movement, and animation.
* **Dialogue**: Calls `EonZora_HandleDialogue` to manage interactions with the player.
* **Movement**: Calls `EonZora_Walk` for random movement, followed by `JSL Sprite_Move` and `JSL Sprite_BounceFromTileCollision` for physical movement and collision handling.
* **Directional Animations**: Uses a jump table to play specific animations based on the Zora's current direction (Forward, Left, Right, Back).
```asm
Sprite_EonZora_Main:
{
JSR EonZora_HandleDialogue
JSR EonZora_Walk
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
LDA.w SprAction, X
JSL JumpTableLocal
dw EonZora_Forward
dw EonZora_Left
dw EonZora_Right
dw EonZora_Back
EonZora_Forward:
%PlayAnimation(0,1,10)
RTS
EonZora_Left:
%PlayAnimation(2,3,10)
RTS
EonZora_Right:
%PlayAnimation(4,5,10)
RTS
EonZora_Back:
%PlayAnimation(6,7,10)
RTS
}
```
## Movement Routine (`EonZora_Walk`)
This routine controls the Eon Zora's random walking behavior. It uses a timer (`SprTimerA, X`) to periodically select a new random direction and update the sprite's `SprXSpeed, X` and `SprYSpeed, X`.
```asm
EonZora_Walk:
{
LDA.w SprTimerA, X : BNE +
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X : TAY
LDA.w .speed_x, Y : STA.w SprXSpeed, X
LDA.w .speed_y, Y : STA.w SprYSpeed, X
LDA.b #$6A : STA.w SprTimerA, X
+
RTS
.speed_x
db 0, -4, 4, 0
.speed_y
db 4, 0, 0, -4
}
```
## Dialogue Handling (`EonZora_HandleDialogue`)
This routine manages the Eon Zora's dialogue, which is context-sensitive based on Link's current `AreaIndex`. It checks for specific `AreaIndex` values to display tailored messages. If no specific area matches, a default message is displayed, and interacting with it can randomly set the `FOUNDRINGS` global variable.
```asm
EonZora_HandleDialogue:
{
LDA.w AreaIndex : CMP.b #$63 : BNE .not_wisdom
%ShowSolicitedMessage($01AC)
JMP ++
.not_wisdom
CMP.b #$5B : BNE .not_power
%ShowSolicitedMessage($01AB)
JMP ++
.not_power
CMP.b #$40 : BNE .not_pyramid
%ShowSolicitedMessage($01AA)
JMP ++
.not_pyramid
CMP.b #$70 : BNE .not_underwater
%ShowSolicitedMessage($01AD)
JMP ++
.not_underwater
CMP.b #$42 : BNE .not_portal
%ShowSolicitedMessage($01AF)
JMP ++
.not_portal
%ShowSolicitedMessage($01AE) : BCC .no_talk
JSL GetRandomInt : AND.b #$06 : STA.l FOUNDRINGS
.no_talk
++
RTS
}
```
## Drawing (`Sprite_EonZora_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_EonZora_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $02, $04, $06, $08, $0A, $0C, $0D
.nbr_of_tiles
db 1, 1, 1, 1, 1, 1, 0, 0
.x_offsets
dw 0, 16
dw 0, -16
dw 0, 8
dw 0, 8
dw 0, -8
dw 0, -8
dw 0
dw 0
.y_offsets
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0
dw 0
.chr
db $60, $62
db $60, $62
db $40, $41
db $43, $44
db $40, $41
db $43, $44
db $64
db $64
.properties
db $39, $39
db $79, $79
db $39, $39
db $39, $39
db $79, $79
db $79, $79
db $39
db $79
.sizes
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02
db $02
}
```
## Design Patterns
* **Context-Sensitive Dialogue**: The NPC's dialogue dynamically changes based on Link's current `AreaIndex`, providing a rich and immersive storytelling experience tailored to the player's location.
* **Random Movement**: The Zora exhibits random walking behavior, contributing to the environmental ambiance and making the world feel more alive.
* **NPC Interaction**: Provides dialogue and has the potential to grant items (randomly setting `FOUNDRINGS`), adding an element of surprise and reward to player interactions.
* **Animation-Driven Movement**: The sprite's movement states are directly tied to specific animations for each direction, ensuring visual consistency between its actions and appearance.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,127 @@
# Eon Zora Elder
## Overview
The Eon Zora Elder is an NPC (Non-Player Character) sprite primarily characterized by its animation-driven states. Its main function is to visually convey different moods or actions through distinct animations, such as idle, surprised, or holding a rod.
## Sprite Properties
Explicit sprite properties (`!SPRID`, `!NbrTiles`, etc.) are not defined within this file. It is assumed that these properties are either inherited from a vanilla sprite ID or defined in a separate configuration file, as this file focuses on the sprite's behavior and drawing.
## Main Logic & State Machine (`Sprite_EonZoraElder_Main`)
The Eon Zora Elder's core behavior is managed by a simple state machine that primarily controls its animations:
* **`EonZoraElder_Idle`**: Plays an idle animation (`%PlayAnimation(0,1,10)`).
* **`EonZoraElder_Surprised`**: Plays a surprised animation (`%PlayAnimation(2,3,10)`).
* **`EonZoraElder_WithRod`**: Plays an animation depicting the elder holding a rod (`%PlayAnimation(4,4,10)`).
```asm
Sprite_EonZoraElder_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw EonZoraElder_Idle
dw EonZoraElder_Surprised
dw EonZoraElder_WithRod
EonZoraElder_Idle:
%PlayAnimation(0,1,10)
RTS
EonZoraElder_Surprised:
%PlayAnimation(2,3,10)
RTS
EonZoraElder_WithRod:
%PlayAnimation(4,4,10)
RTS
}
```
## Drawing (`Sprite_EonZoraElder_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_EonZoraElder_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $02, $04, $06
.nbr_of_tiles
db 1, 1, 1, 2
.x_offsets
dw 0, 8
dw 0, 8
dw 0, 8
dw 0, 8, -4
.y_offsets
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0, 0
.chr
db $46, $47
db $49, $4A
db $66, $67
db $69, $6A, $6C
.properties
db $39, $39
db $39, $39
db $39, $39
db $39, $39, $39
.sizes
db $02, $02
db $02, $02
db $02, $02
db $02, $02, $02
}
```
## Design Patterns
* **Animation-Driven States**: The sprite's states are primarily used to control which animation is currently playing, allowing for visual feedback to the player (e.g., idle, surprised, holding a rod).
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

333
Docs/Sprites/NPCs/Farore.md Normal file
View File

@@ -0,0 +1,333 @@
# Farore
## Overview
Farore, the Oracle of Secrets, is a pivotal NPC sprite deeply integrated into the game's narrative and cutscene system. Her behavior is highly dynamic, adapting to the player's location (indoors/outdoors) and various game progression flags. She plays a crucial role in guiding the player and controlling cinematic sequences.
## Sprite Properties
* **`!SPRID`**: `Sprite_Farore` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `2`
* **`!Harmless`**: `00` (Unusual for an NPC, might indicate specific interaction or placeholder)
* **`!HVelocity`**: `00`
* **`!Health`**: `0`
* **`!Damage`**: `0`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `01`
* **`!Shadow`**: `01`
* **`!Palette`**: `0`
* **`!Hitbox`**: `0`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `0`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Farore_Long`)
This routine acts as a dispatcher, conditionally calling different drawing and main logic routines based on whether Link is `INDOORS`. This indicates that the `Farore` sprite ID is reused for a different entity (likely "Hyrule Dream") when indoors.
```asm
Sprite_Farore_Long:
{
PHB : PHK : PLB
LDA.b INDOORS : BEQ .outdoors
JSR Sprite_HyruleDream_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_HyruleDream_Main
JMP .SpriteIsNotActive
.outdoors
JSR Sprite_Farore_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Farore_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Farore_Prep`)
This routine initializes Farore upon spawning. It sets `SprDefl, X` to `$80` to prevent despawning off-screen. It also includes conditional initialization based on `INDOORS` and a check for `$7EF300` (likely a flag for Farore's presence) to potentially despawn the sprite.
```asm
Sprite_Farore_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X ; Don't kill Farore when she goes off screen
LDA.b INDOORS : BEQ .outdoors
JSR Sprite_HyruleDream_Prep
JMP .PlayIntro
.outdoors
LDA.l $7EF300 : BEQ .PlayIntro
STZ.w SprState, X ; Kill the sprite
.PlayIntro
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Farore_Main`)
Farore's core behavior is managed by a complex state machine heavily involved in cutscenes and quest progression:
* **`IntroStart`**: Initiates a cutscene (`InCutScene = 01`) and transitions to different states based on `STORY_STATE` (`$B6`).
* **`MoveUpTowardsFarore`**: Controls Link's movement during a cutscene, slowing him down and moving him north. Transitions to `MoveLeftTowardsFarore` when Link reaches a certain Y-position.
* **`MoveLeftTowardsFarore`**: Continues Link's controlled movement, moving him west. Stops auto-movement, sets a timer, and transitions to `WaitAndMessage`.
* **`WaitAndMessage`**: Displays a message after a timer, applies speed towards the player, and transitions to `Farore_ProceedWithCutscene`.
* **`Farore_ProceedWithCutscene`**: A transitional state that leads to `FaroreFollowPlayer` after a timer.
* **`FaroreFollowPlayer`**: Farore follows Link, controlling his movement and updating various game state flags (`GAMESTATE`, `STORY_STATE`, rain sound). Transitions to `MakuArea_FaroreFollowPlayer`.
* **`MakuArea_FaroreFollowPlayer`**: Farore continues to follow Link in the Maku Area.
* **`MakuArea_FaroreWaitForKydrog`**: Farore waits in the Maku Area.
```asm
Sprite_Farore_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw IntroStart
dw MoveUpTowardsFarore
dw MoveLeftTowardsFarore
dw WaitAndMessage
dw Farore_ProceedWithCutscene
dw FaroreFollowPlayer
dw MakuArea_FaroreFollowPlayer
dw MakuArea_FaroreWaitForKydrog
; 00
IntroStart:
{
LDA #$01 : STA InCutScene
LDA $B6 : CMP.b #$01 : BEQ .maku_area
CMP.b #$02 : BEQ .waiting
%GotoAction(1)
RTS
.maku_area
%GotoAction(6)
RTS
.waiting
%GotoAction(7)
RTS
}
; 01
MoveUpTowardsFarore:
{
LDA.w WALKSPEED : STA.b $57 ; Slow Link down for the cutscene
LDA.b #$08 : STA.b $49 ; Auto-movement north
; Link's Y Position - Y = 6C
LDA.b $20 : CMP.b #$9C : BCC .linkistoofar
%GotoAction(2)
.linkistoofar
%PlayAnimation(6, 6, 8) ; Farore look towards Link
RTS
}
; 02
MoveLeftTowardsFarore:
{
; Move Link Left
LDA.w WALKSPEED : STA.b $57 ; Slow Link down for the cutscene
LDA.b #$02 : STA.b $49
; Link's X position
LDA.b $22 : CMP.b #$1A : BCS .linkistoofar
STZ.b $49 ; kill automove
LDA.b #$20
STA.w SprTimerA, X ; set timer A to 0x10
%PlayAnimation(0, 0, 8)
%GotoAction(3)
.linkistoofar
RTS
}
; 03
WaitAndMessage:
{
%PlayAnimation(1, 2, 8)
LDA.b #$15
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_MoveVert
LDA.w SprTimerA, X : BNE +
STZ $2F
LDA #$00 : STA InCutScene
; "I am Farore, the Oracle of Secrets."
%ShowUnconditionalMessage($0E)
%GotoAction(4)
+
RTS
}
; 04
Farore_ProceedWithCutscene:
{
LDA.w SprTimerA, X : BNE ++
%GotoAction(5)
++
RTS
}
; 05
FaroreFollowPlayer:
{
LDA #$01 : STA InCutScene
LDA.w WALKSPEED : STA.b $57 ; Slow Link down for the cutscene
LDA.b #$08 : STA.b $49 ; Auto-movement north
%PlayAnimation(3, 4, 8)
LDA.b #$15
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_MoveVert
LDA #$02 : STA $7EF3C5 ; (0 - intro, 1 - pendants, 2 - crystals)
LDA #$05 : STA $012D ; turn off rain sound
LDA #$01 : STA $B6 ; Set Story State
JSL Sprite_LoadGfxProperties
%GotoAction(6)
RTS
}
; 06
MakuArea_FaroreFollowPlayer:
{
%PlayAnimation(3, 4, 8)
LDA.b #$15
JSL Sprite_ApplySpeedTowardsPlayer
JSL Sprite_MoveVert
%GotoAction(6)
RTS
}
; 07
MakuArea_FaroreWaitForKydrog:
{
%PlayAnimation(5, 5, 8)
RTS
}
}
```
## Drawing (`Sprite_Farore_Draw`)
This routine handles OAM allocation and animation for Farore. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
```asm
Sprite_Farore_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $02, $04, $06, $08, $0A, $0C
.nbr_of_tiles
db 1, 1, 1, 1, 1, 1, 1
.x_offsets
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, 0
dw 0, -1
.y_offsets
dw -8, 4
dw -8, 4
dw 4, -8
dw -8, 4
dw 4, -7
dw -8, 4
dw 4, -7
.chr
db $A8, $AA
db $A8, $88
db $AA, $A8
db $8A, $8C
db $8C, $8A
db $8A, $AC
db $AA, $86
.properties
db $3B, $3B
db $3B, $7B
db $3B, $3B
db $3B, $3B
db $7B, $3B
db $3B, $3B
db $3B, $7B
.sizes
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
db $02, $02
}
```
## Design Patterns
* **Multi-Character Sprite (Conditional Drawing/Logic)**: The sprite ID is reused for "Hyrule Dream" when indoors, demonstrating a powerful technique for resource optimization and context-sensitive character representation.
* **Cutscene Control**: Farore's logic is heavily integrated with cutscenes, controlling Link's movement, displaying messages, and managing game state transitions to create cinematic sequences.
* **Quest Progression Integration**: The sprite's appearance and behavior are tied to `STORY_STATE` and other game flags, indicating its crucial role in advancing the narrative.
* **Player Movement Manipulation**: During cutscenes, Farore's script directly controls Link's speed and auto-movement, ensuring precise choreography for story events.
* **Global State Management**: Modifies `InCutScene`, `GAMESTATE`, `STORY_STATE`, and other global variables to reflect and control the current game context.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,94 @@
# Followers
## Overview
The `followers.asm` file is a comprehensive collection of routines and data structures that implement a sophisticated follower system within Oracle of Secrets. It manages various NPC types, including the Zora Baby, Old Man, Kiki, and a Minecart, each with unique behaviors, interactions, and integration into the game world. This file heavily utilizes vanilla overrides to inject custom logic and expand upon existing game mechanics.
## Follower Data Memory Locations
This section defines various WRAM addresses used to store and cache follower-related data, enabling complex interactions and animations:
* **`FollowerYL`, `FollowerYH`, `FollowerXL`, `FollowerXH`, `FollowerZ`, `FollowerLayer`**: Stores position (Y, X, Z coordinates) and layer information for followers, with a cache for 20 steps of animation and movement.
* **`FollowerHeadOffset`, `FollowerHeadOffsetH`, `FollowerBodyOffset`, `FollowerBodyOffsetH`**: Stores offsets for follower head and body graphics, used to adjust their appearance based on direction (e.g., facing Link).
* **`Flwhgfxt`, `Flwhgfxth`, `Flwhgfxb`, `Flwhgfxbh`, `Flwbgfxt`, `Flwbgfxth`, `Flwbgfxb`, `Flwbgfxbh`**: Graphics data for follower head and body.
* **`Flwanimir`**: Index for reading follower animation steps.
* **`FollowerHook`**: Flag indicating when a follower is being used with the Hookshot.
* **`FollowerHookI`**: Caches `FLWANIMIW` when Hookshotting is finished.
* **`FLWGRABTIME`**: Countdown timer preventing followers from being immediately regrabbed after being dropped.
* **`FLWANIMIW`**: Index for writing follower animation steps.
* **`FollowCacheYL`, `FollowCacheYH`, `FollowCacheXL`, `FollowCacheXH`**: Cache of follower properties in SRAM.
## `Follower_WatchLink`
This routine adjusts a follower's head and body graphics offsets to make them turn and face Link, providing a more interactive and responsive NPC presence.
## Zora Baby Follower
The Zora Baby follower is a key NPC involved in specific puzzles and interactions, particularly with water switches.
* **`ZoraBaby_RevertToSprite`**: This routine spawns a `Sprite 0x39 Locksmith` (which is the Zora Baby sprite) and initializes its properties based on the follower's cached data. It sets `SprBulletproof`, `SprAction`, and `SprTimerB`, and clears relevant follower flags.
* **`CheckForZoraBabyTransitionToSprite`**: Checks if the Zora Baby is currently a follower (`$7EF3CC = $09`). If Link is standing on a star tile (`$0114 = $3B`), it calls `ZoraBaby_RevertToSprite` to transition the follower back into a regular sprite. If Link is outdoors, it clears the follower flag.
* **`CheckForZoraBabyFollower`**: A utility routine to check if the Zora Baby is currently a follower.
* **`UploadZoraBabyGraphicsPrep`**: Prepares the graphics for the Zora Baby, setting `$7EF3CC` to `$09` and calling `LoadFollowerGraphics`.
* **`ZoraBaby_CheckForWaterSwitchSprite`**: Checks for the presence of a `Sprite 0x21` (Water Gate Switch) and determines if the Zora Baby is positioned on top of it.
* **`ZoraBaby_CheckForWaterGateSwitch`**: Checks for a `Sprite 0x04` (Water Gate Switch) and performs a precise coordinate check to see if the Zora Baby is on top of it.
* **`ZoraBaby_GlobalBehavior`**: This is the main behavior routine for the Zora Baby. It makes the Zora Baby act as a barrier (`Sprite_BehaveAsBarrier`), makes it watch Link (`Follower_WatchLink`), and handles interactions like being lifted (`Sprite_CheckIfLifted`) and thrown (`ThrownSprite_TileAndSpriteInteraction_long`). Crucially, it detects if the Zora Baby is on a water switch and triggers the `ZoraBaby_PullSwitch` state.
### Zora Baby Vanilla Overrides
* **`org $09AA5E`**: Injects `JSL CheckForZoraBabyFollower` to enable the Zora Baby's swaying animation.
* **`org $09A19C`**: Injects `JSL CheckForZoraBabyTransitionToSprite` for follower basic movement.
* **`org $09A902`**: Sets the Zora Baby follower's palette to blue.
* **`org $09A8CF`**: Sets the Zora Baby character data offset.
* **`org $06BD9C`**: Defines the Zora Baby Sprite Idle OAM data.
* **`org $068D59` (`SpritePrep_Locksmith`)**: Overrides the `SpritePrep_Locksmith` routine. It makes the Zora Baby bulletproof, prevents spawning if already following, and calls `UploadZoraBabyGraphicsPrep`.
* **`org $06BCAC` (`Sprite_39_ZoraBaby`)**: Overrides `Sprite_39_Locksmith`. This is the main state machine for the Zora Baby, including states like `LockSmith_Chillin` (idle), `ZoraBaby_FollowLink`, `ZoraBaby_OfferService`, `ZoraBaby_RespondToAnswer`, `ZoraBaby_AgreeToWait`, `ZoraBaby_PullSwitch`, and `ZoraBaby_PostSwitch`. These states manage dialogue, following behavior, and interaction with switches.
## Old Man Follower
This section includes logic for the Old Man follower, particularly concerning his spawning conditions and item interactions.
* **`OldMan_ExpandedPrep`**: Prevents the Old Man sprite from spawning in his home room if Link already has him as a follower.
### Old Man Vanilla Overrides
* **`org $1EE9FF`**: Modifies the item given by the Old Man to be the Goldstar Hookshot upgrade.
* **`org $1BBD3C`**: Modifies `FindEntrance` for the Old Man.
* **`org $02D98B`**: Modifies `Underworld_LoadEntrance` for the Old Man.
* **`org $1EE8F1` (`SpritePrep_OldMan`)**: Overrides `SpritePrep_OldMan`. It makes the Old Man bulletproof, uses `OldMan_ExpandedPrep`, checks for the Lv2 Hookshot, and sets `$7EF3CC` to `$04` (Old Man follower) before calling `LoadFollowerGraphics`.
* **`org $09A4C8` (`Follower_HandleTriggerData`)**: This is a large data block defining trigger coordinates and messages for various followers, including the Old Man, Zelda, and Blind Maiden.
## Kiki Follower
This section contains logic for the Kiki follower, focusing on her reaction to Link's health.
* **`Kiki_CheckIfScared`**: If Link's health is low and Kiki is flashing, she will run away from him.
### Kiki Vanilla Overrides
* **`org $09A1C6`**: Injects `JSL Kiki_CheckIfScared` to implement Kiki's fear behavior.
* **`org $1EE2E9` (`Kiki_WalkOnRoof`)**: Defines speed data for Kiki walking on a roof.
* **`org $1EE576` (`Kiki_HopToSpot`)**: Defines target coordinates for Kiki to hop to a spot.
* **`org $1EE5E9` (`Kiki_WalkOnRoof_Ext`)**: Defines step and timer data for Kiki's extended roof walk.
## Minecart Follower
This section details the implementation of the Minecart follower, including its drawing, transition, and Link's interaction with it.
* **`FollowerDraw_CalculateOAMCoords`**: A helper routine to calculate OAM coordinates for followers.
* **`MinecartFollower_Top` / `MinecartFollower_Bottom`**: Drawing routines for the top and bottom halves of the Minecart follower.
* **`Minecart_AnimDirection`**: Data for Minecart animation direction.
* **`MinecartFollower_TransitionToSprite`**: Transitions the Minecart follower back into a regular sprite.
* **`DrawMinecartFollower`**: The main drawing routine for the Minecart follower, which also handles its transition to a sprite if Link is in the cart and not in a submodule.
* **`FollowerDraw_CachePosition`**: Caches the follower's position for drawing, adjusting coordinates relative to Link.
* **`CheckForMinecartFollowerDraw`**: Checks if the Minecart follower should be drawn.
* **`CheckForFollowerInterroomTransition` / `CheckForFollowerIntraroomTransition`**: Handles transitions for followers between rooms and within rooms.
* **`LinkState_Minecart`**: Defines Link's behavior when he is in a Minecart, including movement, collision, and animation.
* **`TileBehavior_TL_Long` / `TileBehavior_StopLeft_Long`**: Tile behaviors for Minecart tracks.
### Minecart Vanilla Overrides
* **`org $07A5F7`**: Injects `JSL LinkState_Minecart` to control Link's state when in a Minecart.
* **`org $07D938`**: Defines Minecart Track tile types.
* **`org $09A41F`**: Injects `JSL CheckForMinecartFollowerDraw`.
* **`org $028A5B`**: Injects `JSL CheckForFollowerInterroomTransition`.
* **`org $0289BF`**: Injects `JSL CheckForFollowerIntraroomTransition`.
## Design Patterns
* **Multi-Purpose File**: This file serves as a central repository for various follower-related logic, demonstrating how to manage diverse NPC behaviors within a single module.
* **Follower System**: Implements a robust and flexible follower system with features like position caching, animation, and complex interaction logic.
* **Vanilla Overrides**: Extensive use of `org` directives to modify vanilla sprite behaviors and integrate custom follower logic, showcasing advanced ROM hacking techniques.
* **Context-Sensitive Behavior**: Follower behavior dynamically changes based on game state, player actions, and environmental factors (e.g., Zora Baby on water switch, Old Man's spawning conditions, Kiki's fear of low-health Link).
* **Cutscene Integration**: Some followers (like the Zora Baby) are involved in cutscene-like sequences, demonstrating how to choreograph NPC actions within narrative events.
* **Item Gating/Progression**: The Old Man's appearance and item offerings are tied to the player's possession of specific items (e.g., Lv2 Hookshot), integrating followers into the game's progression system.
* **Player State Manipulation**: Routines like `LinkState_Minecart` directly control Link's movement and animation when interacting with followers, providing a seamless player experience.
* **16-bit OAM Calculations**: Explicitly uses `REP #$20` and `SEP #$20` for precise 16-bit OAM calculations in drawing routines, ensuring accurate sprite rendering.

View File

@@ -0,0 +1,88 @@
# Fortune Teller
## Overview
The `fortune_teller.asm` file is not a complete sprite definition but rather a set of routines and data that override and extend the behavior of the vanilla Fortune Teller NPC. Its primary function is to provide highly context-sensitive messages to Link, offering guidance or commentary based on his current inventory, collected items, and overall game progression.
## Vanilla Overrides
This file directly modifies existing vanilla code related to the Fortune Teller:
* **`org $0DC829`**: Overrides the `FortuneTellerMessage` data table, which contains the message IDs that the Fortune Teller can display.
* **`org $0DC849`**: Overrides the `FortuneTeller_PerformPseudoScience` routine, which is the core logic for determining and displaying messages.
## `FortuneTellerMessage` Data Table
This table stores a sequence of byte values, each representing a message ID. These IDs correspond to specific dialogue options that the Fortune Teller can present to Link.
```asm
org $0DC829
FortuneTellerMessage:
.low
#_0DC829: db $EA ; MESSAGE 00EA
#_0DC82A: db $EB ; MESSAGE 00EB
#_0DC82B: db $EC ; MESSAGE 00EC
#_0DC82C: db $ED ; MESSAGE 00ED
#_0DC82D: db $EE ; MESSAGE 00EE
#_0DC82E: db $EF ; MESSAGE 00EF
#_0DC82F: db $F0 ; MESSAGE 00F0
#_0DC830: db $F1 ; MESSAGE 00F1
#_0DC831: db $F6 ; MESSAGE 00F6
#_0DC832: db $F7 ; MESSAGE 00F7
#_0DC833: db $F8 ; MESSAGE 00F8
#_0DC834: db $F9 ; MESSAGE 00F9
#_0DC835: db $FA ; MESSAGE 00FA
#_0DC836: db $FB ; MESSAGE 00FB
#_0DC837: db $FC ; MESSAGE 00FC
#_0DC838: db $FD ; MESSAGE 00FD
.high
#_0DC839: db $00
; ... (rest of the table)
```
## `FortuneTeller_PerformPseudoScience` Routine
This routine is the central logic for the custom Fortune Teller. It dynamically selects which message to display to Link based on a series of checks against his inventory and various game progression flags stored in SRAM.
* **Initializations**: Performs some initial state manipulations (`STZ.w $0DC0,X`, `INC.w $0D80,X`, `STZ.b $03`).
* **Progression Check (`$7EF3D6`)**: Determines a base message category based on a custom progression flag.
* **Extensive Item and Game State Checks**: The routine then proceeds through a series of conditional checks, each corresponding to a specific item or game event. For example, it checks for:
* `$7EF344` (Mushroom/Powder)
* `$7EF37A` (Crystals, specifically if Tail Palace is beaten)
* `$7EF355` (Boots)
* `$7EF356` (Flippers)
* `$7EF345` (Fire Rod)
* `$7EF37B` (Magic Upgrade)
* `$7EF354` (Glove)
* `$7EF358` (Wolf Mask)
* `$7EF3C9` (Smithy Rescued flag)
* `$7EF352` (Cape)
* `$7EF354` (Titans Mitt)
* `$7EF359` (Sword level)
* **Message Display**: Based on these checks, it calls `FortuneTeller_PrepareNextMessage` with the appropriate message index and then `FortuneTeller_DisplayMessage` to show the message to the player.
```asm
FortuneTeller_PerformPseudoScience:
#_0DC849: STZ.w $0DC0,X
#_0DC84C: INC.w $0D80,X
#_0DC84F: STZ.b $03
#_0DC851: LDA.l $7EF3D6
#_0DC855: CMP.b #$02
#_0DC857: BCS .map_icon_past_pendants
#_0DC859: STZ.b $00
#_0DC85B: STZ.b $01
#_0DC85D: JMP.w FortuneTeller_DisplayMessage
.map_icon_past_pendants
#_0DC860: LDA.l $7EF344
#_0DC864: BNE .have_shroom_or_powder
#_0DC866: LDA.b #$02
#_0DC868: JSR FortuneTeller_PrepareNextMessage
#_0DC86B: BCC .have_shroom_or_powder
#_0DC86D: JMP.w FortuneTeller_DisplayMessage
; ... (rest of the conditional item checks)
```
## Design Patterns
* **Vanilla Override**: This file exemplifies how to directly modify and extend the behavior of existing vanilla NPCs through targeted code injection.
* **Context-Sensitive Dialogue**: The Fortune Teller's messages are highly dynamic and personalized, adapting to Link's current inventory and game progression. This creates a more engaging and responsive NPC interaction.
* **Quest Progression Tracking**: The routine extensively utilizes SRAM flags and item possession checks to track Link's progress through various quests and milestones, influencing the dialogue provided.
* **Modular Message System**: The use of `FortuneTeller_PrepareNextMessage` and `FortuneTeller_DisplayMessage` allows for a structured and modular approach to managing and displaying NPC dialogue.

179
Docs/Sprites/NPCs/Goron.md Normal file
View File

@@ -0,0 +1,179 @@
# Goron
## Overview
The Goron sprite (`!SPRID = $F2`) is a versatile NPC implementation that can represent two distinct Goron characters: the "Kalyxo Goron" and the "Eon Goron." Their specific behaviors and appearances are determined by the global `WORLDFLAG` and the current `AreaIndex`. These Gorons primarily serve as interactive NPCs, engaging Link through dialogue and potentially triggering game events.
## Sprite Properties
* **`!SPRID`**: `$F2` (Vanilla sprite ID, likely for a generic NPC)
* **`!NbrTiles`**: `04`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `02`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Goron_Long`)
This routine acts as a dispatcher, selecting the appropriate drawing routine based on the `WORLDFLAG` (Kalyxo Goron if `0`, Eon Goron otherwise). It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_Goron_Long:
{
PHB : PHK : PLB
LDA.w WORLDFLAG : BEQ .kalyxo
JSR Sprite_EonGoron_Draw
JMP +
.kalyxo
JSR Sprite_KalyxoGoron_Draw
+
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Goron_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Goron_Prep`)
This routine initializes the Goron upon spawning. It sets `SprDefl, X` to `$80`. The initial `SprAction, X` is determined by `WORLDFLAG` and `AreaIndex`. For Eon Gorons, it can randomly set their initial action to `EonGoron_Main`, `EonGoron_Sing`, or `EonGoron_Punch`. For Kalyxo Gorons, it checks a specific flag (`$7EF280, X`) to set their initial action to `KalyxoGoron_Main` or `KalyxoGoron_MinesOpened`.
```asm
Sprite_Goron_Prep:
{
PHB : PHK : PLB
LDA.w WORLDFLAG : BEQ +
LDA.w AreaIndex : CMP.b #$55 : BNE .not_sing
LDA.b #$04 : STA.w SprAction, X
.not_sing
JSL GetRandomInt : AND.b #$01 : BEQ .rand
LDA.b #$05 : STA.w SprAction, X
JMP ++
.rand
LDA.b #$03 : STA.w SprAction, X
JMP ++
+
PHX
LDX $8A
LDA.l $7EF280, X : CMP.b #$20 : BEQ +++
PLX
STZ.w SprAction, X
++
PLB
RTL
+++
PLX
LDA.b #$02 : STA.w SprAction, X
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Goron_Main`)
This routine manages the various states and behaviors of both Kalyxo and Eon Gorons.
* **Player Collision**: Prevents Link from passing through the Goron (`Sprite_PlayerCantPassThrough`).
* **`KalyxoGoron_Main`**: Displays messages (`%ShowSolicitedMessage`) based on the `RockMeat` item count. Can transition to `KalyxoGoron_OpenMines` under certain conditions.
* **`KalyxoGoron_OpenMines`**: Plays an animation, sets a flag (`$04C6`) to open mines, and transitions to `KalyxoGoron_MinesOpened`.
* **`KalyxoGoron_MinesOpened`**: Plays an animation.
* **`EonGoron_Main`**: Plays an animation and displays a message.
* **`EonGoron_Sing`**: Plays a singing animation and displays a message.
* **`EonGoron_Punch`**: Plays a punching animation and displays a message.
```asm
Sprite_Goron_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw KalyxoGoron_Main
dw KalyxoGoron_OpenMines
dw KalyxoGoron_MinesOpened
dw EonGoron_Main
dw EonGoron_Sing
dw EonGoron_Punch
KalyxoGoron_Main:
{
LDA.l RockMeat : BEQ +
CMP.b #$05 : BCC ++
%ShowSolicitedMessage($01A9) : BCC +++
INC.w SprAction, X
+++
RTS
+
%ShowSolicitedMessage($01A7)
RTS
++
%ShowSolicitedMessage($01A8)
RTS
}
KalyxoGoron_OpenMines:
{
%PlayAnimation(1,1,10)
LDA.b #$04 : STA $04C6
INC.w SprAction, X
RTS
}
KalyxoGoron_MinesOpened:
{
%PlayAnimation(1,1,10)
RTS
}
EonGoron_Main:
{
%PlayAnimation(0, 1, 10)
%ShowSolicitedMessage($01B0)
RTS
}
EonGoron_Sing:
{
%PlayAnimation(2, 3, 10)
%ShowSolicitedMessage($01B2)
RTS
}
EonGoron_Punch:
{
%PlayAnimation(4, 5, 10)
%ShowSolicitedMessage($01B1)
RTS
}
}
```
## Drawing (`Sprite_KalyxoGoron_Draw` and `Sprite_EonGoron_Draw`)
Both drawing routines handle OAM allocation and animation for their respective Goron types. They explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
## Design Patterns
* **Multi-Character NPC (Conditional Drawing/Logic)**: A single sprite definition is used to represent two distinct Goron characters (Kalyxo and Eon) based on `WORLDFLAG`, demonstrating efficient resource utilization and context-sensitive character representation.
* **Quest Progression Integration**: The Gorons' dialogue and actions are tied to game state (e.g., `RockMeat` item count, `AreaIndex`), indicating their role in advancing the narrative and triggering specific events like opening mines.
* **Conditional Behavior**: Extensive use of conditional logic based on `WORLDFLAG` and `AreaIndex` allows for dynamic changes in the Goron's role, dialogue, and actions.
* **NPC Interaction**: Provides rich interaction with the player through dialogue (`%ShowSolicitedMessage`) and can trigger game events.
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make the NPC a solid object that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,152 @@
# Hyrule Dream
## Overview
The Hyrule Dream sprite represents a special NPC that appears indoors and plays a role in a specific questline. It interacts with Link through dialogue and grants a unique "Dream" item, with its presence and actions tied to game progression.
## Sprite Properties
Explicit sprite properties (`!SPRID`, `!NbrTiles`, etc.) are not defined within this file. It is assumed that these properties are either inherited from a vanilla sprite ID or defined in a separate configuration file, as this file focuses on the sprite's behavior and drawing.
## Main Logic (`Sprite_HyruleDream_Main`)
This routine manages the Hyrule Dream's behavior through a state machine:
* **`HyruleDream_Idle`**: The sprite plays an idle animation. When Link is within a certain proximity (`GetDistance8bit_Long`), it transitions to the `HyruleDream_Talk` state.
* **`HyruleDream_Talk`**: The sprite continues its idle animation and displays a solicited message (`%ShowSolicitedMessage($01B3)`). Upon completion of the message, it transitions to `HyruleDream_GiveItem`.
* **`HyruleDream_GiveItem`**: The sprite maintains its idle animation. After a timer (`SprTimerA, X`) expires, it grants Link the "Dream" item (`LDY #$12`, `JSL Link_ReceiveItem`), sets a flag (`$7EF410`) indicating the Dream has been obtained, and then despawns itself (`STZ.w SprState, X`).
```asm
Sprite_HyruleDream_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw HyruleDream_Idle
dw HyruleDream_Talk
dw HyruleDream_GiveItem
HyruleDream_Idle:
{
%PlayAnimation(0,0,1)
JSL GetDistance8bit_Long : CMP.b #$20 : BCS +
INC.w SprAction, X
+
RTS
}
HyruleDream_Talk:
{
%PlayAnimation(0,0,1)
%ShowSolicitedMessage($01B3) : BCC +
INC.w SprAction, X
+
RTS
}
HyruleDream_GiveItem:
{
%PlayAnimation(0,0,1)
LDA.w SprTimerA, X : BNE +
LDY #$12 : JSL Link_ReceiveItem
LDA.b #$01 : STA.l $7EF410
STZ.w SprState, X
+
RTS
}
}
```
## Initialization (`Sprite_HyruleDream_Prep`)
This routine initializes the Hyrule Dream sprite upon spawning. It sets `SprDefl, X` to `$80` (preventing despawning off-screen). Crucially, it checks the "Dream" flag (`$7EF410`). If Link has already obtained the Dream, the sprite immediately despawns (`STZ.w SprState, X`), ensuring it only appears once.
```asm
Sprite_HyruleDream_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.l $7EF410 : BNE +
STZ.w SprState, X
+
PLB
RTL
}
```
## Drawing (`Sprite_HyruleDream_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_HyruleDream_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00
.nbr_of_tiles
db 3
.x_offsets
dw -8, 8, -8, 8
.y_offsets
dw -8, -8, 8, 8
.chr
db $C0, $C2, $E0, $E2
.properties
db $3B, $7B, $3B, $7B
.sizes
db $02, $02, $02, $02
}
```
## Design Patterns
* **NPC Interaction**: The sprite is designed to engage with the player through dialogue and the granting of a unique item, driving a specific questline.
* **Quest Progression Integration**: The sprite's appearance and item-granting are directly tied to a flag (`$7EF410`) for the "Dream" item, ensuring it appears only once per playthrough.
* **Conditional Spawning/Despawning**: The sprite dynamically despawns if Link has already obtained the "Dream" item, preventing redundant interactions.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

43
Docs/Sprites/NPCs/Impa.md Normal file
View File

@@ -0,0 +1,43 @@
# Impa (Zelda)
## Overview
The `impa.asm` file is not a complete sprite definition but rather a collection of routines and vanilla overrides that modify the behavior of the character Impa (or Zelda, as indicated by some labels). Its primary purpose is to manage spawn points and manipulate game state during critical events, likely cutscenes or key progression points within the game.
## Spawn Point Definitions
The file defines a WRAM address `SPAWNPT = $7EF3C8` for a spawn point flag, along with comments detailing various spawn point IDs:
* `0x00` - Link's house
* `0x01` - Sanctuary (Hall of Secrets)
* `0x02` - Castle Prison
* `0x03` - Castle Basement
* `0x04` - Throne
* `0x05` - Old man cave
* `0x06` - Old man home
## `Impa_SetSpawnPointFlag`
This routine is responsible for setting a specific spawn point flag. It stores a value into `$7EF372` (likely the actual spawn point ID) and then sets bit `$04` in `$7EF3D6` (a custom progression flag), indicating that a particular event has occurred.
```asm
Impa_SetSpawnPointFlag:
{
STA.l $7EF372
LDA.l $7EF3D6 : ORA.b #$04 : STA.l $7EF3D6
RTL
}
```
## Vanilla Overrides
This file extensively uses `pushpc`/`pullpc` blocks and `org` directives to inject custom code into specific vanilla routines, thereby altering the game's default behavior:
* **`org $05EE46` (`Zelda_AtSanctuary`)**: Injects `JSL Impa_SetSpawnPointFlag`. This modification ensures that when Zelda (or Impa) is at the Sanctuary, a specific spawn point flag is set, influencing where Link might respawn or transition.
* **`org $05EBCF`**: Modifies a comparison involving `$7EF359` (likely Link's Sword level) with `$05`. This is noted as a `TODO`, suggesting it's an incomplete or placeholder modification.
* **`org $029E2E` (`Module15_0C`)**: Modifies an overlay that Impa activates after the intro sequence. It sets bit `$20` in `$7EF2A3` (likely an overlay control flag), potentially changing the visual environment.
* **`org $05ED43` (`Zelda_BecomeFollower`)**: Prevents Impa from setting a spawn point by clearing `$02E4` and `$7EF3C8`. This suggests a custom handling of Impa's follower state.
* **`org $05ED63`**: NOPs out 5 bytes, effectively disabling some vanilla code at this address.
* **`org $05ED10` (`Zelda_ApproachHero`)**: NOPs out 5 bytes, preventing Impa from changing the game's background music or sound, indicating custom control over audio during this event.
## Design Patterns
* **Vanilla Override**: This file is a prime example of how to extensively override vanilla code to integrate custom NPC behaviors and progression systems into an existing game.
* **Quest Progression Tracking**: Utilizes custom progression flags (`$7EF3D6`) and spawn point flags (`$7EF372`, `$7EF3C8`) to meticulously track key events and the player's progress through the game's narrative.
* **Game State Manipulation**: Directly modifies WRAM addresses to control various aspects of the game, such as visual overlays and audio, providing fine-grained control over the player's experience.
* **Modular Code Injection**: The use of `org` directives allows for precise injection of custom routines into specific points of the vanilla codebase, enabling targeted modifications without disrupting unrelated functionality.

184
Docs/Sprites/NPCs/Korok.md Normal file
View File

@@ -0,0 +1,184 @@
# Korok
## Overview
The Korok sprite (`!SPRID = Sprite_Korok`) implements a multi-variant NPC system, allowing for different Korok characters (Makar, Hollo, Rown) to appear from a single sprite definition. These Koroks exhibit random walking behavior, engage in dialogue, and are liftable, contributing to environmental interactions and minor puzzles.
## Sprite Properties
* **`!SPRID`**: `Sprite_Korok` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `03`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Korok_Long`)
This routine acts as a dispatcher for drawing the correct Korok variant based on its `SprSubtype, X`. It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_Korok_Long:
{
PHB : PHK : PLB
LDA $0AA5 : BEQ .done
LDA.w SprSubtype, X : BEQ .draw_makar
CMP.b #$01 : BEQ .draw_hollo
CMP.b #$02 : BEQ .draw_rown
.draw_makar
JSR Sprite_Korok_DrawMakar
BRA .done
.draw_hollo
JSR Sprite_Korok_DrawHollo
BRA .done
.draw_rown
JSR Sprite_Korok_DrawRown
BRA .done
.done
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Korok_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Korok_Prep`)
This routine initializes the Korok upon spawning by randomly assigning a `SprSubtype, X` (0-3). This subtype determines which Korok variant (Makar, Hollo, or Rown) the sprite will represent.
```asm
Sprite_Korok_Prep:
{
PHB : PHK : PLB
JSL GetRandomInt : AND.b #$03 : STA.w SprSubtype, X
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Korok_Main`)
The Korok's core behavior is managed by a state machine that includes idle, walking, and liftable states.
* **`Sprite_Korok_Idle`**: The Korok plays an idle animation. Upon player interaction (`%ShowSolicitedMessage($001D)`), it randomly transitions to a walking state. It also prevents player passage (`Sprite_PlayerCantPassThrough`).
* **`Sprite_Korok_WalkingDown` / `Up` / `Left` / `Right`**: These states control the Korok's movement in different directions. Each state plays a specific walking animation, sets the appropriate speed (`KorokWalkSpeed`), moves the sprite (`Sprite_Move`), and after a timer (`SprTimerB, X`), randomly transitions to another walking state.
* **`Sprite_Korok_Liftable`**: This state handles the Korok's interaction when lifted (`Sprite_CheckIfLifted`) and thrown (`ThrownSprite_TileAndSpriteInteraction_long`).
```asm
Sprite_Korok_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw Sprite_Korok_Idle
dw Sprite_Korok_WalkingDown
dw Sprite_Korok_WalkingUp
dw Sprite_Korok_WalkingLeft
dw Sprite_Korok_WalkingRight
dw Sprite_Korok_Liftable
Sprite_Korok_Idle:
{
%PlayAnimation(0, 0, 10)
LDA $0AA5 : BNE +
PHX
JSL ApplyKorokSpriteSheets
PLX
LDA.b #$01 : STA.w $0AA5
+
%ShowSolicitedMessage($001D) : BCC .no_talk
JSL GetRandomInt : AND.b #$03
STA.w SprAction, X
RTS
.no_talk
JSL Sprite_PlayerCantPassThrough
RTS
}
Sprite_Korok_WalkingDown:
{
%PlayAnimation(0, 2, 10)
LDA.b #KorokWalkSpeed : STA.w SprYSpeed, X
JSL Sprite_Move
LDA.w SprTimerB, X : BNE +
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X
+
RTS
}
Sprite_Korok_WalkingUp:
{
%PlayAnimation(3, 5, 10)
LDA.b #-KorokWalkSpeed : STA.w SprYSpeed, X
JSL Sprite_Move
LDA.w SprTimerB, X : BNE +
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X
+
RTS
}
Sprite_Korok_WalkingLeft:
{
%PlayAnimation(6, 8, 10)
LDA.b #KorokWalkSpeed : STA.w SprXSpeed, X
JSL Sprite_Move
LDA.w SprTimerB, X : BNE +
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X
+
RTS
}
Sprite_Korok_WalkingRight:
{
%PlayAnimation(9, 11, 10)
LDA.b #-KorokWalkSpeed : STA.w SprXSpeed, X
JSL Sprite_Move
LDA.w SprTimerB, X : BNE +
JSL GetRandomInt : AND.b #$03 : STA.w SprAction, X
+
RTS
}
Sprite_Korok_Liftable:
{
JSL Sprite_Move
JSL Sprite_CheckIfLifted
JSL ThrownSprite_TileAndSpriteInteraction_long
RTS
}
}
```
## Drawing (`Sprite_Korok_DrawMakar`, `Sprite_Korok_DrawHollo`, `Sprite_Korok_DrawRown`)
Each Korok variant has its own dedicated drawing routine (`Sprite_Korok_DrawMakar`, `Sprite_Korok_DrawHollo`, `Sprite_Korok_DrawRown`). These routines handle OAM allocation and animation, and explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the respective Korok character.
## Design Patterns
* **Multi-Variant NPC**: A single sprite definition (`Sprite_Korok`) is used to represent multiple distinct Korok characters (Makar, Hollo, Rown) based on a randomly assigned `SprSubtype`, showcasing efficient resource utilization and varied visual appearances.
* **Randomized Behavior**: The Korok's initial variant and its walking directions are randomized, adding an element of unpredictability and variety to encounters.
* **NPC Interaction**: The Korok can be interacted with through dialogue (`%ShowSolicitedMessage`) and is liftable (`Sprite_CheckIfLifted`), allowing for environmental puzzles or simple interactions.
* **Conditional Drawing**: The drawing routine dispatches to different sub-routines based on the Korok's subtype, allowing for distinct visual appearances for each variant.
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make the NPC a solid object that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,137 @@
# Maku Tree
## Overview
The Maku Tree sprite (`!SPRID = Sprite_MakuTree`) represents a significant NPC in the game, likely serving as a quest giver or a key character in the narrative. Its interactions are primarily dialogue-driven and tied to game progression, culminating in the granting of a Heart Container. Notably, its graphics are not handled by a conventional sprite drawing routine within this file, suggesting it might be a background element or drawn by a separate system.
## Sprite Properties
* **`!SPRID`**: `Sprite_MakuTree` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `00` (Indicates graphics are handled externally or as a background)
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `0`
* **`!Damage`**: `0`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `0`
* **`!Hitbox`**: `$0D`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `0`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_MakuTree_Long`)
This routine primarily checks if the Maku Tree sprite is active and then dispatches to its main logic routine. The absence of a direct drawing call (`JSR Sprite_MakuTree_Draw`) here suggests its visual representation is managed outside of the standard sprite drawing pipeline.
```asm
Sprite_MakuTree_Long:
{
PHB : PHK : PLB
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_MakuTree_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_MakuTree_Prep`)
This routine initializes the Maku Tree upon spawning. It sets `SprDefl, X` and includes logic to potentially play the "Maku Song" by checking a custom progression flag (`OOSPROG2`).
```asm
Sprite_MakuTree_Prep:
{
PHB : PHK : PLB
; Play the Maku Song
LDA.l OOSPROG2 : AND.b #$04 : BEQ +
LDA.b #$03 : STA.w $012C
+
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_MakuTree_Main`)
The Maku Tree's core behavior is managed by a state machine that guides its interaction with Link and quest progression.
* **Player Collision**: Prevents Link from passing through the Maku Tree (`JSL Sprite_PlayerCantPassThrough`).
* **`MakuTree_Handler`**: Checks the `MakuTreeQuest` flag to determine if Link has already met the Maku Tree, transitioning to `MakuTree_MeetLink` or `MakuTree_HasMetLink` accordingly.
* **`MakuTree_MeetLink`**: When Link is close enough, the Maku Tree displays an unconditional message (`%ShowUnconditionalMessage($20)`), updates quest flags (`MakuTreeQuest`, `MapIcon`, `$7EF3D6`), and transitions to `MakuTree_SpawnHeartContainer`.
* **`MakuTree_SpawnHeartContainer`**: Grants Link a Heart Container (`LDY #$3E : JSL Link_ReceiveItem`) and then transitions to `MakuTree_HasMetLink`.
* **`MakuTree_HasMetLink`**: Displays a solicited message (`%ShowSolicitedMessage($22)`) and updates a progression flag (`$7EF3D6`) upon message dismissal.
```asm
Sprite_MakuTree_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw MakuTree_Handler
dw MakuTree_MeetLink
dw MakuTree_SpawnHeartContainer
dw MakuTree_HasMetLink
MakuTree_Handler:
{
; Check the progress flags
LDA.l MakuTreeQuest : AND.b #$01 : BNE .has_met_link
%GotoAction(1)
RTS
.has_met_link
%GotoAction(3)
RTS
}
MakuTree_MeetLink:
{
JSL GetDistance8bit_Long : CMP #$28 : BCS .not_too_close
%ShowUnconditionalMessage($20)
LDA.b #$01 : STA.l MakuTreeQuest
LDA.b #$01 : STA.l MapIcon ; Mushroom Grotto
LDA.l $7EF3D6 : ORA.b #$02 : STA.l $7EF3D6
%GotoAction(2)
.not_too_close
RTS
}
MakuTree_SpawnHeartContainer:
{
; Give Link a heart container
LDY #$3E : JSL Link_ReceiveItem
%GotoAction(3)
RTS
}
MakuTree_HasMetLink:
{
%ShowSolicitedMessage($22) : BCC .no_talk
LDA.l $7EF3D6 : ORA.b #$02 : STA.l $7EF3D6
.no_talk
RTS
}
}
```
## Drawing
There is no `Sprite_MakuTree_Draw` routine defined within this file. This strongly suggests that the Maku Tree's graphical representation is handled as a background element or by a separate drawing system, rather than as a conventional sprite with its own OAM data.
## Design Patterns
* **Background/Static NPC**: The Maku Tree functions as a static NPC whose visual representation is likely integrated into the background, as evidenced by the absence of a dedicated sprite drawing routine.
* **Quest Gating/Progression**: The Maku Tree's interactions are deeply tied to custom quest flags (`MakuTreeQuest`, `OOSPROG2`, `$7EF3D6`), controlling when Link can meet it, engage in dialogue, and receive rewards.
* **Item Granting**: The Maku Tree serves as a source for a significant reward, granting Link a Heart Container upon meeting specific quest conditions.
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make the Maku Tree a solid, impassable object in the game world.
* **Dialogue-Driven Progression**: Dialogue (`%ShowUnconditionalMessage`, `%ShowSolicitedMessage`) is strategically used to advance the quest narrative and provide context to the player's journey.

227
Docs/Sprites/NPCs/Maple.md Normal file
View File

@@ -0,0 +1,227 @@
# Maple
## Overview
The `maple.asm` file defines the behavior for the NPC "Maple," a significant character involved in a branching "Dream" questline. Maple interacts with Link through extensive dialogue, offers explanations about game mechanics, and possesses the unique ability to put Link to sleep, triggering special dream sequences that advance the narrative and potentially grant rewards.
## Main Logic (`MapleHandler`)
This routine orchestrates Maple's complex interactions with Link, managing dialogue, quest progression, and the initiation of dream sequences.
* **Player Collision**: Prevents Link from passing through Maple (`JSL Sprite_PlayerCantPassThrough`).
* **`Maple_Idle`**: Displays a solicited message (`%ShowSolicitedMessage($01B3)`). Upon dismissal, it transitions to `Maple_HandleFirstResponse`. It also includes logic to set a flag (`$7EF351`) and a timer (`$012F`) for a specific event.
* **`Maple_HandleFirstResponse`**: Processes Link's initial dialogue response (`$1CE8`), leading to different branches: `Maple_Idle`, `Maple_ExplainHut`, or `Maple_DreamOrExplain`.
* **`Maple_DreamOrExplain`**: Displays an unconditional message (`%ShowUnconditionalMessage($01B4)`) and, based on Link's response, transitions to `Maple_ExplainPendants`, `Maple_CheckForPendant`, or back to `Maple_Idle`.
* **`Maple_ExplainHut`**: Displays an unconditional message (`%ShowUnconditionalMessage($01B5)`) and returns to `Maple_Idle`.
* **`Maple_ExplainPendants`**: Displays an unconditional message (`%ShowUnconditionalMessage($01B8)`) and returns to `Maple_Idle`.
* **`Maple_CheckForPendant`**: Checks Link's collected Pendants (`Pendants` SRAM flag) and Dreams (`Dreams` SRAM flag) to determine if a new Dream is available. If so, it sets `CurrentDream`, displays a message (`%ShowUnconditionalMessage($01B6)`), and transitions to `Maple_PutLinkToSleep`. Otherwise, it transitions to `Maple_NoNewPendant`.
* **`Maple_NoNewPendant`**: Displays an unconditional message (`%ShowUnconditionalMessage($01B7)`) and returns to `Maple_Idle`.
* **`Maple_PutLinkToSleep`**: Calls `Sprite_PutLinkToSleep` to initiate the sleep sequence and then transitions to `Maple_HandleDreams`.
* **`Maple_HandleDreams`**: After a timer (`SprTimerA, X`), calls `Link_HandleDreams` to process the dream sequence.
```asm
MapleHandler:
{
%PlayAnimation(0,1,16)
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw Maple_Idle
dw Maple_HandleFirstResponse
dw Maple_DreamOrExplain
dw Maple_ExplainHut
dw Maple_ExplainPendants
dw Maple_CheckForPendant
dw Maple_NoNewPendant
dw Maple_PutLinkToSleep
dw Maple_HandleDreams
Maple_Idle:
{
%ShowSolicitedMessage($01B3) : BCC +
INC.w SprAction, X
+
LDA.l $7EF351 : BEQ +
LDA.b #$02 : STA.l $7EF351
LDA.b #$1B : STA.w $012F
+
RTS
}
Maple_HandleFirstResponse:
{
LDA.w $1CE8 : CMP.b #$02 : BNE +
STZ.w SprAction, X
RTS
+
CMP.b #$01 : BNE .next_response
LDA.b #$03 : STA.w SprAction, X
RTS
.next_response
INC.w SprAction, X
RTS
}
Maple_DreamOrExplain:
{
%ShowUnconditionalMessage($01B4)
LDA.w $1CE8 : BEQ .check_for_pendant
CMP.b #$01 : BNE .another_time
LDA.b #$04 : STA.w SprAction, X
RTS
.check_for_pendant
LDA.b #$05 : STA.w SprAction, X
RTS
.another_time
STZ.w SprAction, X
RTS
}
Maple_ExplainHut:
{
%ShowUnconditionalMessage($01B5)
STZ.w SprAction, X
RTS
}
Maple_ExplainPendants:
{
%ShowUnconditionalMessage($01B8)
STZ.w SprAction, X
RTS
}
Maple_CheckForPendant:
{
; Check for pendant
LDA.l Pendants : AND.b #$04 : BNE .courage
LDA.l Pendants : AND.b #$02 : BNE .power
LDA.l Pendants : AND.b #$01 : BNE .wisdom
JMP .none
.courage
LDA.l Dreams : AND.b #$04 : BNE .power
LDA.b #$02 : STA.w CurrentDream : BRA +
.power
LDA.l Dreams : AND.b #$02 : BNE .wisdom
LDA.b #$01 : STA.w CurrentDream : BRA +
.wisdom
LDA.l Dreams : AND.b #$01 : BNE .none
STZ.w CurrentDream
+
%ShowUnconditionalMessage($01B6)
LDA.b #$07 : STA.w SprAction, X
LDA.b #$40 : STA.w SprTimerA, X
RTS
.none
INC.w SprAction, X
RTS
}
Maple_NoNewPendant:
{
%ShowUnconditionalMessage($01B7)
STZ.w SprAction, X
RTS
}
Maple_PutLinkToSleep:
{
JSR Sprite_PutLinkToSleep
INC.w SprAction, X
RTS
}
Maple_HandleDreams:
{
LDA.w SprTimerA, X : BNE +
JSR Link_HandleDreams
+
RTS
}
}
```
## `Sprite_PutLinkToSleep`
This routine initiates a cinematic sleep sequence for Link. It adjusts Link's coordinates, sets his state to sleeping (`$5D = $16`), spawns a blanket ancilla, adjusts Link's OAM coordinates, and applies a blinding white palette filter to transition into a dream sequence.
```asm
Sprite_PutLinkToSleep:
{
PHX
LDA.b $20 : SEC : SBC.b #$14 : STA.b $20
LDA.b $22 : CLC : ADC.b #$18 : STA.b $22
LDA.b #$16 : STA.b $5D ; Set Link to sleeping
LDA.b #$20 : JSL AncillaAdd_Blanket
LDA.b $20 : CLC : ADC.b #$04 : STA.w $0BFA,X
LDA.b $21 : STA.w $0C0E,X
LDA.b $22 : SEC : SBC.b #$08 : STA.w $0C04,X
LDA.b $23 : STA.w $0C18,X
JSL PaletteFilter_StartBlindingWhite
JSL ApplyPaletteFilter
PLX
RTS
}
```
## `Link_HandleDreams`
This routine manages the different dream sequences based on the `CurrentDream` variable. It sets specific bits in the `Dreams` SRAM flag and warps Link to a designated room using `Link_WarpToRoom`.
* **`Dream_Wisdom`**: Sets bit `0` in `Dreams`, warps Link to a room, and sets `$EE` to `$01`.
* **`Dream_Power`**: Sets bit `1` in `Dreams` and warps Link to a room.
* **`Dream_Courage`**: Sets bit `2` in `Dreams` and warps Link to a room.
```asm
Link_HandleDreams:
{
LDA.w CurrentDream
JSL JumpTableLocal
dw Dream_Wisdom
dw Dream_Power
dw Dream_Courage
Dream_Wisdom:
{
LDA.l Dreams : ORA.b #%00000001 : STA.l Dreams
LDX.b #$00
JSR Link_WarpToRoom
LDA.b #$01 : STA.b $EE
RTS
}
Dream_Power:
{
LDA.l Dreams : ORA.b #%00000010 : STA.l Dreams
LDX.b #$01
JSR Link_WarpToRoom
RTS
}
Dream_Courage:
{
LDA.l Dreams : ORA.b #%00000100 : STA.l Dreams
LDX.b #$02
JSR Link_WarpToRoom
RTS
}
}
```
## `Link_WarpToRoom`
This routine sets Link's state for warping, including setting his `LinkState` and room coordinates, and uses a `.room` data table to determine the target room for the warp.
## `Link_FallIntoDungeon`
This routine sets Link's state for falling into a dungeon, including setting the entrance ID and various state flags. It uses an `.entrance` data table to determine the target entrance.
## Vanilla Override
* **`org $068C9C`**: Sets a byte to `$0F`, likely a minor adjustment to vanilla code.
## Design Patterns
* **Complex Dialogue System**: Maple's interactions feature a highly branching and conditional dialogue system, where player choices and game progression influence the conversation flow and subsequent events.
* **Quest Gating/Progression**: Maple is a central figure in a "Dream" questline, with her dialogue and actions dynamically adapting based on Link's collected Pendants and Dreams, guiding the player through a significant narrative arc.
* **Player State Manipulation**: Maple possesses the unique ability to put Link to sleep, which triggers special dream sequences and warps him to different locations, creating immersive and story-rich transitions.
* **Cinematic Sequences**: The `Sprite_PutLinkToSleep` routine orchestrates a cinematic effect, incorporating screen transitions, visual filters, and the spawning of ancillae to enhance the player's experience during dream initiations.
* **Global State Management**: The sprite extensively modifies `Pendants`, `Dreams`, `CurrentDream`, and other global variables to meticulously track and influence quest progress, ensuring a consistent and evolving game world.

View File

@@ -0,0 +1,363 @@
# Mask Salesman
## Overview
The Mask Salesman sprite (`!SPRID = Sprite_MaskSalesman`) is a complex NPC that functions as a vendor and a quest-giver, offering masks for sale and teaching Link songs. His interactions are highly conditional, branching based on Link's inventory (Ocarina, learned songs, owned masks) and current rupee count.
## Sprite Properties
* **`!SPRID`**: `Sprite_MaskSalesman` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Impervious to all attacks)
* **`!SmallShadow`**: `01`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `02`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_MaskSalesman_Long`)
This routine handles the Mask Salesman's drawing and dispatches to its main logic if the sprite is active.
```asm
Sprite_MaskSalesman_Long:
{
PHB : PHK : PLB
JSR Sprite_MaskSalesman_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_MaskSalesman_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_MaskSalesman_Prep`)
This routine is empty, indicating that the Mask Salesman requires no custom initialization upon spawning.
## Main Logic & State Machine (`Sprite_MaskSalesman_Main`)
The Mask Salesman's core behavior is managed by a complex state machine that facilitates a branching dialogue and transaction system.
* **Player Collision**: Prevents Link from passing through the Mask Salesman (`JSL Sprite_PlayerCantPassThrough`).
* **`InquiryHandler`**: Plays an animation, checks Link's Ocarina status (`$7EF34C`), and displays a solicited message asking if Link wants to buy a mask. Based on Link's response (`$1CE8`) and inventory, it transitions to various states like `NoOcarina`, `HasOcarina`, `OfferBunnyHood`, `OfferStoneMask`, or `PlayerSaidNoToMask`.
* **`NoOcarina`**: Displays a message instructing Link to get the Ocarina first, then returns to `InquiryHandler`.
* **`HasOcarina`**: Displays a message acknowledging Link has the Ocarina, then transitions to `TeachLinkSong`.
* **`TeachLinkSong`**: Increments Link's learned songs count (`$7EF34C`), plays a song learned sound, and returns to `InquiryHandler`.
* **`OfferBunnyHood`**: Displays a message offering the Bunny Hood for 100 rupees, then transitions to `BoughtBunnyHood`.
* **`OfferStoneMask`**: Displays a message offering the Stone Mask for 650 rupees, then transitions to `BoughtStoneMask`.
* **`PlayerSaidNoToMask`**: Displays a message and returns to `InquiryHandler`.
* **`PlayerHasAllMasks`**: Displays a message indicating Link has all masks, then returns to `InquiryHandler`.
* **`BoughtBunnyHood`**: Processes Link's decision to buy the Bunny Hood. Checks rupee count, grants the item (`LDY #$10`, `JSL Link_ReceiveItem`), deducts rupees, displays a confirmation message, and returns to `InquiryHandler`. If rupees are insufficient, it transitions to `NotEnoughMoney`.
* **`BoughtStoneMask`**: Similar to `BoughtBunnyHood`, but for the Stone Mask (`LDY #$19`) and a higher rupee cost.
* **`NotEnoughMoney`**: Displays a message indicating insufficient funds, then returns to `InquiryHandler`.
```asm
Sprite_MaskSalesman_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw InquiryHandler
dw NoOcarina
dw HasOcarina
dw TeachLinkSong
dw OfferBunnyHood
dw OfferStoneMask
dw PlayerSaidNoToMask
dw PlayerHasAllMasks
dw BoughtBunnyHood
dw BoughtStoneMask
dw NotEnoughMoney
; 0x00
InquiryHandler:
{
%PlayAnimation(0, 1, 16)
; Player has a Lv1 Ocarina, skip to the you got it message
LDA.l $7EF34C : CMP.b #$01 : BEQ .has_ocarina
; Player has no Ocarina or Lv2 Ocarina
; Do you want to buy a mask?
%ShowSolicitedMessage($E5) : BCC .didnt_converse
LDA $1CE8 : BNE .player_said_no
; Player wants to buy a mask
LDA.l $7EF34C : CMP.b #$02 : BCS .has_song_healing
; No Ocarina yet
%GotoAction(1)
RTS
.has_ocarina
%GotoAction(2)
RTS
.has_song_healing
LDA.l $7EF348 : CMP.b #$01 : BCS .has_bunny_mask
%GotoAction(4)
RTS
.has_bunny_mask
LDA.l $7EF352 : CMP.b #$01 : BCS .has_stone_mask
%GotoAction(5)
RTS
.has_stone_mask
%GotoAction(7)
RTS
.player_said_no
%GotoAction(6)
.didnt_converse
RTS
}
; 0x01 - Link has not yet gotten the Ocarina
NoOcarina:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($E9) ; Go get the Ocarina first!
%GotoAction(0)
RTS
}
; 0x02 - Link has the Ocarina, but not all the songs
HasOcarina:
{
%PlayAnimation(0, 1, 16)
%ShowSolicitedMessage($081) ; Oh! You got it!
%GotoAction(3)
RTS
}
; 0x03
TeachLinkSong:
{
LDA #$02 : STA $7EF34C ; Increment the number of songs Link has
LDA.b #$13
STA.w $0CF8
JSL $0DBB67 ; Link_CalculateSFXPan
ORA.w $0CF8
STA $012E ; Play the song learned sound
%GotoAction(0)
RTS
}
; 0x04 - Offer Bunny Hood
OfferBunnyHood:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($07F) ; Bunny Hood for 100 rupees?
%GotoAction(8)
RTS
}
; 0x05 - Offer Stone Mask
OfferStoneMask:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($082) ; Stone Mask for 650 rupees?
%GotoAction(9)
RTS
}
; 0x06 - Player said no to buying a mask
PlayerSaidNoToMask:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($E8)
%GotoAction(0)
RTS
}
; 0x07 - Player has all the masks
PlayerHasAllMasks:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($028)
%GotoAction(0)
RTS
}
BoughtBunnyHood:
{
%PlayAnimation(0, 1, 16)
LDA $1CE8 : BNE .player_said_no
REP #$20
LDA.l $7EF360 : CMP.w #$64 ; 100 rupees
SEP #$30
BCC .not_enough_rupees
LDY.b #$10 ; Bunny Hood
STZ.w $02E9
PHX
JSL Link_ReceiveItem
PLX
REP #$20
LDA.l $7EF360
SEC : SBC.w #$64 ; Subtract 100 rupees
STA.l $7EF360
SEP #$30
%ShowUnconditionalMessage($063)
%GotoAction(0)
RTS
.not_enough_rupees
%GotoAction($0A)
RTS
.player_said_no
%GotoAction(6)
RTS
}
BoughtStoneMask:
{
%PlayAnimation(0, 1, 16)
LDA $1CE8 : BNE .player_said_no
REP #$20
LDA.l $7EF360 : CMP.w #$352 ; 850 rupees
SEP #$30
BCC .not_enough_rupees
LDY #$19 ; Stone Mask
STZ.w $02E9
PHX
JSL Link_ReceiveItem
PLX
REP #$20
LDA.l $7EF360
SEC : SBC.w #$352 ; Subtract 850 rupees
STA.l $7EF360
SEP #$30
%ShowUnconditionalMessage($055)
%GotoAction(0)
RTS
.not_enough_rupees
%GotoAction($0A)
RTS
.player_said_no
%GotoAction(6)
RTS
}
NotEnoughMoney:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($029)
%GotoAction(0)
RTS
}
}
```
## Drawing (`Sprite_MaskSalesman_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_MaskSalesman_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $04
.nbr_of_tiles
db 3, 3
.x_offsets
dw -4, 12, 0, 0
dw 4, -12, 0, 0
.y_offsets
dw -8, -8, 0, -11
dw -8, -8, 0, -10
.chr
db $82, $84, $A0, $80
db $82, $84, $A0, $80
.properties
db $39, $39, $39, $39
db $79, $79, $79, $39
.sizes
db $02, $02, $02, $02
db $02, $02, $02, $02
}
```
## Design Patterns
* **Complex Dialogue and Shop System**: The Mask Salesman implements a sophisticated dialogue tree that functions as a shop, offering items (masks) and services (teaching songs) based on player choices and inventory. This creates a dynamic and interactive vendor experience.
* **Quest Gating/Progression**: Interactions with the Mask Salesman are gated by Link's possession of the Ocarina and the number of songs he has learned, integrating the NPC into the game's progression system.
* **Conditional Transactions**: The process of buying masks involves checking Link's current rupee count and deducting the cost upon a successful purchase, simulating a real in-game economy.
* **Player Choice and Branching Dialogue**: Link's responses to the Mask Salesman's inquiries directly influence the flow of conversation and the available options, leading to a personalized interaction.
* **Item Granting**: The Mask Salesman grants masks to Link and teaches him new songs, providing valuable rewards and abilities.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,119 @@
# Mermaid / Maple / Librarian
## Overview
The `mermaid.asm` file is a highly versatile sprite definition that implements three distinct NPC characters: the "Mermaid," "Maple," and "Librarian." This multi-purpose sprite leverages `SprSubtype` and `SprMiscE, X` to dispatch to different behaviors and drawing routines, allowing for efficient resource reuse and complex, context-sensitive interactions within the game world.
## Sprite Properties
* **`!SPRID`**: `Sprite_Mermaid` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Mermaid_Long`)
This routine acts as a central dispatcher, selecting the appropriate drawing routine based on `SprMiscE, X` (0 for Mermaid, 1 for Maple, 2 for Librarian). It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_Mermaid_Long:
{
PHB : PHK : PLB
LDA.w SprMiscE, X : BEQ .MermaidDraw
CMP.b #$02 : BEQ .LibrarianDraw
JSR Sprite_Maple_Draw
JMP .Continue
.LibrarianDraw
JSR Sprite_Librarian_Draw
JMP .Continue
.MermaidDraw
JSR Sprite_Mermaid_Draw
.Continue
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Mermaid_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Mermaid_Prep`)
This routine initializes the sprite upon spawning. It sets `SprDefl, X`, `SprTimerA, X`, and `SprHitbox, X`. Crucially, it sets `SprMiscE, X` based on `SprSubtype, X` to determine which character the sprite will represent (0 for Mermaid, 1 for Maple, 2 for Librarian).
```asm
Sprite_Mermaid_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.b #$40 : STA.w SprTimerA, X
LDA.b #$07 : STA.w SprHitbox, X
; Mermaid Sprite
STZ.w SprMiscE, X
; Maple Sprite
LDA.w SprSubtype, X : CMP.b #$01 : BNE +
LDA.b #$01 : STA.w SprMiscE, X
+
; Librarian Sprite
CMP.b #$02 : BNE ++
LDA.b #$02 : STA.w SprMiscE, X
++
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Mermaid_Main`)
This routine acts as a dispatcher for the main logic, calling the appropriate handler (`MermaidHandler`, `MapleHandler`, or `LibrarianHandler`) based on `SprMiscE, X`.
### `MermaidHandler`
Manages the Mermaid's behavior through a state machine:
* **`MermaidWait`**: Plays an idle animation, prevents player passage, and displays a message on contact. Upon message dismissal, it transitions to `MermaidDive`.
* **`MermaidDive`**: Plays a diving animation, moves horizontally, and transitions to `MermaidSwim` after a timer.
* **`MermaidSwim`**: Plays a swimming animation, moves, sets `SprXSpeed, X`, spawns a splash effect, and can despawn or change direction after a timer.
### `LibrarianHandler`
Manages the Librarian's behavior, primarily focused on a map and scroll translation quest:
* **`LibrarianIdle`**: Plays an animation, prevents player passage, and displays messages based on whether Link has no maps, all maps, or new scrolls. Transitions to `Librarian_CheckResponse` if new scrolls are available.
* **`Librarian_CheckResponse`**: Processes Link's response to the translation offer, transitioning to `Librarian_OfferTranslation` or back to `LibrarianIdle`.
* **`Librarian_OfferTranslation`**: Displays a message, prevents player passage, and checks `Scrolls` and `DNGMAP1`/`DNGMAP2` to identify new scrolls. If found, it updates `Scrolls`, sets `SprMiscG, X` to the scroll ID, and transitions to `Librarian_TranslateScroll`.
* **`Librarian_TranslateScroll`**: Displays a message based on the scroll ID and transitions to `Librarian_FinishTranslation`.
* **`Librarian_FinishTranslation`**: Displays a final message and returns to `LibrarianIdle`.
## `Librarian_CheckForAllMaps` and `Librarian_CheckForNoMaps`
These helper routines check `DNGMAP1` and `DNGMAP2` (SRAM flags for dungeon maps) to determine Link's map collection status.
## Drawing (`Sprite_Mermaid_Draw`, `Sprite_Maple_Draw`, `Sprite_Librarian_Draw`)
Each character has its own dedicated drawing routine. These routines handle OAM allocation and animation, and explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the respective character.
## Design Patterns
* **Multi-Character Sprite (Conditional Drawing/Logic)**: A single sprite definition (`Sprite_Mermaid`) is used to represent three distinct NPCs (Mermaid, Maple, Librarian) based on `SprSubtype` and `SprMiscE`, showcasing efficient resource utilization and context-sensitive character representation.
* **Quest Progression Integration**: The Librarian's dialogue and actions are tied to collected dungeon maps and scrolls, indicating its role in a translation quest, driving narrative progression.
* **Context-Sensitive Dialogue**: The Librarian's messages dynamically change based on whether Link has maps, all maps, or new scrolls, providing a personalized and evolving interaction.
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make NPCs solid objects that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,181 @@
# Piratian
## Overview
The Piratian sprite (`!SPRID = $0E`) represents an NPC that initially behaves in a friendly manner, engaging Link through dialogue and moving randomly. However, it possesses an "aggro" system, becoming hostile and attacking Link if provoked. A unique aspect of this sprite is its dynamic health scaling, which adjusts based on Link's current Sword level.
## Sprite Properties
* **`!SPRID`**: `$0E` (Vanilla sprite ID, likely for a generic NPC)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `00` (Initially harmful, but `Sprite_Piratian_Friendly` suggests otherwise)
* **`!HVelocity`**: `00`
* **`!Health`**: `00` (Dynamically set in `_Prep`)
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Piratian_Long`)
This routine handles the Piratian's drawing, shadow rendering, and dispatches to its main logic if the sprite is active.
```asm
Sprite_Piratian_Long:
{
PHB : PHK : PLB
JSR Sprite_Piratian_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Piratian_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Piratian_Prep`)
This routine initializes the Piratian upon spawning. Its health (`SprHealth, X`) is dynamically set based on Link's current Sword level (`$7EF359`), providing a form of difficulty scaling. `SprMiscA, X` is initialized to `0` (likely an aggro flag), and a specific bit of `SprNbrOAM, X` is set, potentially for drawing behavior.
```asm
Sprite_Piratian_Prep:
{
PHB : PHK : PLB
LDA.l $7EF359 : TAY
LDA.w .health, Y : STA.w SprHealth, X
STZ.w SprMiscA, X
LDA.w SprNbrOAM, X : ORA.b #$80 : STA.w SprNbrOAM, X
PLB
RTL
.health
db $08, $0A, $0C, $0F
}
```
## Main Logic & State Machine (`Sprite_Piratian_Main`)
This routine orchestrates the Piratian's movement and animation, calling `Sprite_Piratian_Move` and then dispatching to various animation states based on `SprAction, X`.
* **`Piratian_MoveDown` / `Up` / `Left` / `Right`**: Each state plays a specific walking animation.
* **`SkullHead`**: Plays a specific animation, likely when the Piratian is defeated or in a particular state.
```asm
Sprite_Piratian_Main:
{
JSR Sprite_Piratian_Move
LDA.w SprAction, X
JSL JumpTableLocal
dw Piratian_MoveDown
dw Piratian_MoveUp
dw Piratian_MoveLeft
dw Piratian_MoveRight
dw SkullHead
Piratian_MoveDown:
{
%PlayAnimation(0,1,16)
RTS
}
Piratian_MoveUp:
{
%PlayAnimation(2,3,16)
RTS
}
Piratian_MoveLeft:
{
%PlayAnimation(4,5,16)
RTS
}
Piratian_MoveRight:
{
%PlayAnimation(6,7,16)
RTS
}
SkullHead:
{
%PlayAnimation(8,9,16)
RTS
}
}
```
## Movement and Interaction (`Sprite_Piratian_Move`)
This routine handles the Piratian's movement, collision, damage reactions, and implements its "aggro" system.
* **Random Movement**: If `SprTimerA, X` is `0`, the Piratian randomly selects a new direction (`Sprite_SelectNewDirection`) and updates its animation state (`SprAction, X`).
* **Physics & Collision**: Moves the sprite (`JSL Sprite_MoveXyz`), handles tile collision (`JSL Sprite_BounceFromTileCollision`), damage flash (`JSL Sprite_DamageFlash_Long`), and interaction with thrown sprites (`JSL ThrownSprite_TileAndSpriteInteraction_long`).
* **Aggro Logic**: If the Piratian takes damage from Link (`JSL Sprite_CheckDamageFromPlayer`), it sets `SprMiscA, X` to `01` (aggro flag), changes its drawing behavior (`SprNbrOAM, X`), sets timers, and begins to attack Link (`Sprite_ProjectSpeedTowardsPlayer`, `Sprite_CheckDamageToPlayer`).
* **Friendly Behavior**: If not in an aggro state, it calls `Sprite_Piratian_Friendly` for dialogue interaction.
```asm
Sprite_Piratian_Move:
{
LDA.w SprTimerA, X : BNE +
JSL Sprite_SelectNewDirection
TYA
CMP.b #$03 : BCC ++
SEC : SBC.b #$03
++
STA.w SprAction, X
+
JSL Sprite_MoveXyz
JSL Sprite_BounceFromTileCollision
JSL Sprite_DamageFlash_Long
JSL ThrownSprite_TileAndSpriteInteraction_long
JSL Sprite_CheckDamageFromPlayer : BCC .no_dano
LDA.b #$01 : STA.w SprMiscA, X
LDA.w SprNbrOAM, X : AND.b #$7F : STA.w SprNbrOAM, X
%SetTimerA($60)
%SetTimerF($20)
.no_dano
LDA.w SprMiscA, X : BEQ .no_aggro
LDA.b #$10 : STA.w SprTimerA, X
LDA.b #$08
JSL Sprite_ProjectSpeedTowardsPlayer
JSL Sprite_CheckDamageToPlayer
JMP .return
.no_aggro
JSR Sprite_Piratian_Friendly
.return
RTS
}
```
## Friendly Interaction (`Sprite_Piratian_Friendly`)
This routine handles the Piratian's friendly dialogue. If `SprTimerD, X` is `0`, it displays a message on contact (`%ShowMessageOnContact($01BB)`). Upon message dismissal, it sets `SprTimerD, X` to `$FF`.
## Drawing (`Sprite_Piratian_Draw`)
The drawing routine uses the `%DrawSprite()` macro to render the Piratian's graphics based on defined OAM data tables.
## Design Patterns
* **Dynamic Health Scaling**: The Piratian's health is dynamically adjusted based on Link's current Sword level, providing a form of adaptive difficulty.
* **Aggro System**: The Piratian features an "aggro" system where it transitions from a friendly, dialogue-based NPC to a hostile enemy if Link attacks it, adding depth to interactions.
* **Random Movement**: The Piratian moves randomly, contributing to its NPC-like behavior and making its movements less predictable.
* **NPC Interaction**: The Piratian can be interacted with through dialogue when in its friendly state, offering context or hints.
* **Conditional Behavior**: The sprite's behavior changes significantly based on its "friendly" or "aggro" state, demonstrating complex state management.
* **16-bit OAM Calculations**: Although `%DrawSprite()` is used, the underlying drawing routines likely utilize `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,95 @@
# Ranch Girl
## Overview
The `ranch_girl.asm` file defines the behavior for the "Ranch Girl" NPC, who is involved in a "Chicken Easter Egg" quest. This character plays a crucial role in granting Link the Ocarina and teaching him a song. Her behavior is implemented as a vanilla override, modifying the existing `ChickenLady` routine.
## Vanilla Overrides
This file directly modifies the vanilla `ChickenLady` routine at `org $01AFECF` to inject custom logic for the Ranch Girl's interactions.
## `RanchGirl_Message`
This routine handles the dialogue displayed by the Ranch Girl. It checks Link's Ocarina status (`$7EF34C`).
* If Link already possesses the Ocarina, it displays message `$010E`.
* Otherwise, it displays message `$017D` and sets `SprMiscD, X` to `$01`, indicating the start of the Ocarina quest.
```asm
RanchGirl_Message:
{
LDA $7EF34C : CMP.b #$01 : BCS .has_ocarina
%ShowUnconditionalMessage($017D)
LDA #$01 : STA.w SprMiscD, X
RTL
.has_ocarina
%ShowUnconditionalMessage($010E)
RTL
}
```
## `RanchGirl_TeachSong`
This routine is responsible for teaching Link a song (specifically the "Song of Storms") and granting him the Ocarina. It checks the Ocarina quest flag (`SprMiscD, X`) and Link's current Ocarina status (`$7EF34C`).
* If the conditions are met, it plays the "Song of Storms" sound, gives Link the Ocarina (`LDY #$14`, `JSL Link_ReceiveItem`), and sets `$7EF34C` to `$01`.
```asm
RanchGirl_TeachSong:
{
LDA.w SprMiscD, X : CMP.b #$01 : BNE .not_started
LDA $10 : CMP.b #$0E : BEQ .running_dialog
LDA $7EF34C : CMP.b #$01 : BCS .has_song
; Play the song of storms
LDA.b #$2F
STA.w $0CF8
JSL $0DBB67 ; Link_CalculateSFXPan
ORA.w $0CF8
STA $012E ; Play the song learned sound
; Give Link the Ocarina
LDY #$14
; Clear the item receipt ID
STZ $02E9
PHX
JSL Link_ReceiveItem
PLX
LDA #$01 : STA $7EF34C ; The item gives 02 by default, so decrement that for now
.not_started
.running_dialog
.has_song
LDA.b $1A : LSR #4 : AND.b #$01 : STA.w $0DC0,X
RTL
}
```
## `ChickenLady` (Vanilla Override)
This is the main entry point for the Ranch Girl's custom behavior, overriding the vanilla `ChickenLady` routine. It sets `SprMiscC, X` to `$01`, calls vanilla drawing and activity check routines, and then executes `RanchGirl_Message` and `RanchGirl_TeachSong`.
```asm
org $01AFECF
ChickenLady:
{
JSR .main
RTL
.main
LDA.b #$01 : STA.w SprMiscC, X
JSL SpriteDraw_RaceGameLady
JSR Sprite_CheckIfActive_Bank1A
LDA.w SprTimerA, X : CMP.b #$01 : BNE .no_message
JSL RanchGirl_Message
.no_message
JSL RanchGirl_TeachSong
.return
RTS
}
```
## Design Patterns
* **Vanilla Override**: This file directly modifies a vanilla routine (`ChickenLady`) to implement custom NPC behavior, demonstrating a common ROM hacking technique.
* **Quest Gating/Progression**: The Ranch Girl's dialogue and the granting of the Ocarina are tied to Link's possession of the Ocarina and the state of the Ocarina quest, integrating her into the game's progression system.
* **Item Granting**: The Ranch Girl serves as a source for the Ocarina, a key item in the game.
* **Game State Manipulation**: Directly modifies `$7EF34C` (Ocarina flag) and `SprMiscD, X` (quest flag) to track and influence game state.

250
Docs/Sprites/NPCs/Tingle.md Normal file
View File

@@ -0,0 +1,250 @@
# Tingle
## Overview
The Tingle sprite (`!SPRID = Sprite_Tingle`) implements the iconic map salesman character. Tingle's primary function is to sell a map to Link, with his interactions and dialogue flow being conditional on Link's rupee count and whether the map has already been purchased.
## Sprite Properties
* **`!SPRID`**: `Sprite_Tingle` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `02`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Tingle_Long`)
This routine handles Tingle's drawing, shadow rendering, and dispatches to his main logic if the sprite is active.
```asm
Sprite_Tingle_Long:
{
PHB : PHK : PLB
JSR Sprite_Tingle_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Tingle_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Tingle_Prep`)
This routine is empty, indicating that Tingle requires no custom initialization upon spawning.
## Main Logic & State Machine (`Sprite_Tingle_Main`)
Tingle's core behavior is managed by a state machine that facilitates a dialogue and transaction flow for selling a map.
* **Player Collision**: Prevents Link from passing through Tingle (`JSL Sprite_PlayerCantPassThrough`).
* **`Tingle_Idle`**: Plays an animation. Checks if Link has already bought the map (`$7EF3D6` bit `$01`). If so, it transitions to `Tingle_AlreadyBoughtMap`. Otherwise, it displays a solicited message (`%ShowSolicitedMessage($01A4)`) asking if Link wants to buy a map. Based on Link's response (`$1CE8`), it transitions to `Tingle_BuyMap` or `Tingle_PlayerSaidNo`.
* **`Tingle_BuyMap`**: Plays an animation. Checks if Link has enough rupees (`$7EF360`). If sufficient, it deducts the rupees, sets the map bought flag (`$7EF3D6` bit `$01`), displays a confirmation message (`%ShowUnconditionalMessage($01A5)`), and transitions to `Tingle_AlreadyBoughtMap`. If rupees are insufficient, it transitions to `Tingle_NotEnoughMoney`.
* **`Tingle_PlayerSaidNo`**: Plays an animation, displays a message (`%ShowUnconditionalMessage($01A6)`), and returns to `Tingle_Idle`.
* **`Tingle_AlreadyBoughtMap`**: Plays an animation, displays a message (`%ShowUnconditionalMessage($01A3)`) confirming the map has been bought, and returns to `Tingle_Idle`.
* **`Tingle_NotEnoughMoney`**: Plays an animation, displays a message (`%ShowUnconditionalMessage($029)`) about insufficient funds, and returns to `Tingle_Idle`.
```asm
Sprite_Tingle_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw Tingle_Idle
dw Tingle_BuyMap
dw Tingle_PlayerSaidNo
dw Tingle_AlreadyBoughtMap
dw Tingle_NotEnoughMoney
; 0x00
Tingle_Idle:
{
%PlayAnimation(0, 1, 16)
; Player has already bought the map
LDA.l $7EF3D6 : AND.b #$01 : BNE .already_bought_map
%ShowSolicitedMessage($01A4) : BCC .didnt_converse
LDA $1CE8 : BEQ .buy_map
; Player said no
%GotoAction(2)
RTS
.buy_map
%GotoAction(1)
RTS
.already_bought_map
%GotoAction(3)
RTS
.didnt_converse
RTS
}
; 0x01
Tingle_BuyMap:
{
%PlayAnimation(0, 1, 16)
REP #$20
LDA.l $7EF360 : CMP.w #$0064 ; 100 rupees
SEP #$30
BCC .not_enough_money
; Deduct rupees
REP #$20
LDA.l $7EF360
SEC : SBC.w #$0064
STA.l $7EF360
SEP #$30
; Set map bought flag
LDA.l $7EF3D6 : ORA.b #$01 : STA.l $7EF3D6
%ShowUnconditionalMessage($01A5)
%GotoAction(3)
RTS
.not_enough_money
%GotoAction(4)
RTS
}
; 0x02
Tingle_PlayerSaidNo:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($01A6)
%GotoAction(0)
RTS
}
; 0x03
Tingle_AlreadyBoughtMap:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($01A3)
%GotoAction(0)
RTS
}
; 0x04
Tingle_NotEnoughMoney:
{
%PlayAnimation(0, 1, 16)
%ShowUnconditionalMessage($029)
%GotoAction(0)
RTS
}
}
```
## Drawing (`Sprite_Tingle_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_Tingle_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $04
.nbr_of_tiles
db 3, 3
.x_offsets
dw -4, 12, 0, 0
dw 4, -12, 0, 0
.y_offsets
dw -8, -8, 0, -11
dw -8, -8, 0, -10
.chr
db $82, $84, $A0, $80
db $82, $84, $A0, $80
.properties
db $39, $39, $39, $39
db $79, $79, $79, $39
.sizes
db $02, $02, $02, $02
db $02, $02, $02, $02
}
```
## Design Patterns
* **Shop System**: Tingle implements a basic shop system for selling a map, including price checks and rupee deduction, providing a functional in-game vendor.
* **Quest Gating/Progression**: The availability of the map and Tingle's dialogue are conditional on whether Link has already purchased the map (`$7EF3D6` bit `$01`), ensuring a logical progression of events.
* **Conditional Transactions**: The process of buying the map involves checking Link's rupee count and deducting the cost upon a successful purchase, simulating a real in-game economy.
* **Player Choice and Branching Dialogue**: Link's responses (`$1CE8`) to Tingle's inquiries directly influence the flow of conversation and the available options, leading to a personalized interaction.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

210
Docs/Sprites/NPCs/Vasu.md Normal file
View File

@@ -0,0 +1,210 @@
# Vasu / Error
## Overview
The `vasu.asm` file defines the behavior for a multi-character NPC sprite that can represent either "Vasu," the ring appraiser, or a special "Error" sprite. The specific character displayed and its interactions are determined by `SprSubtype, X`. Vasu offers a service to appraise rings, with conditional dialogue and transactions based on Link's inventory and rupee count.
## Sprite Properties
* **`!SPRID`**: `Sprite_Vasu` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `03`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `09`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Vasu_Long`)
This routine acts as a dispatcher for drawing, selecting `Sprite_Vasu_Draw` for Vasu (`SprSubtype, X = 0`) or `Sprite_Error_Draw` for the Error sprite. It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_Vasu_Long:
{
PHB : PHK : PLB
LDA.w SprSubtype, X : BNE +
JSR Sprite_Vasu_Draw
JMP ++
+
JSR Sprite_Error_Draw
++
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Vasu_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Vasu_Prep`)
This routine initializes the sprite upon spawning. It sets `SprDefl, X` to `$80`. If the sprite is Vasu (`SprSubtype, X = 0`), it sets `SprAction, X` to `$04`.
```asm
Sprite_Vasu_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
LDA.w SprSubtype, X : BEQ +
LDA.b #$04 : STA.w SprAction, X
+
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Vasu_Main`)
This routine manages the various states and interactions for both Vasu and the Error sprite.
* **Player Collision**: Prevents Link from passing through (`JSL Sprite_PlayerCantPassThrough`).
* **`Vasu_Idle`**: Plays an animation and displays a solicited message (`%ShowSolicitedMessage($00A9)`). Upon message dismissal, it transitions to `Vasu_MessageHandler`.
* **`Vasu_MessageHandler`**: Plays an animation and processes Link's choice (`MsgChoice`). It can lead to `Vasu_AppraiseRing`, `Vasu_ExplainRings` (displays message `$00AA` and returns to `Vasu_Idle`), or return to `Vasu_Idle` if Link chooses "nevermind."
* **`Vasu_AppraiseRing`**: Plays an animation. Checks `FOUNDRINGS` (SRAM flag for found rings). If no rings are found, it displays a message (`%ShowUnconditionalMessage($00AD)`) and returns to `Vasu_Idle`. If rings are found, it checks `MAGICRINGS` (SRAM flag for owned rings). If Link has no rings yet, it offers the first appraisal for free (`%ShowUnconditionalMessage($00AB)`). Otherwise, it checks for 20 rupees (`$7EF360`). If Link has enough, it deducts the rupees, updates `MAGICRINGS` by ORing with `FOUNDRINGS`, and transitions to `Vasu_RingAppraised`. If not enough rupees, it displays a message (`%ShowUnconditionalMessage($0189)`) and returns to `Vasu_Idle`.
* **`Vasu_RingAppraised`**: Plays an animation, displays a message (`%ShowUnconditionalMessage($00AC)`), and returns to `Vasu_Idle`.
* **`Error_Idle`**: Plays an animation and displays a solicited message (`%ShowSolicitedMessage($0121)`) "I am Error." Upon message dismissal, it randomly sets `FOUNDRINGS`.
```asm
Sprite_Vasu_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw Vasu_Idle
dw Vasu_MessageHandler
dw Vasu_AppraiseRing
dw Vasu_RingAppraised
dw Error_Idle
Vasu_Idle:
{
%PlayAnimation(0,1,20)
%ShowSolicitedMessage($00A9) : BCC .didnt_talk
%GotoAction(1)
.didnt_talk
RTS
}
Vasu_MessageHandler:
{
%PlayAnimation(0,1,20)
LDA.w MsgChoice : BEQ .appraise_rings
CMP.b #$01 : BEQ .explain_rings
; Player said nevermind.
%GotoAction(0)
RTS
.explain_rings
%ShowUnconditionalMessage($00AA)
%GotoAction(0)
RTS
.appraise_rings
LDA.b #$40 : STA.w SprTimerB, X
%GotoAction(2)
RTS
}
Vasu_AppraiseRing:
{
%PlayAnimation(0,1,20)
; Check if the player has found any rings to appraise
REP #$30
LDA.l FOUNDRINGS
AND.w #$00FF
SEP #$30
BEQ .no_rings
; Check if the player has any rings, if not give them one for free
LDA.l MAGICRINGS : BEQ .no_rings_yet
REP #$20
LDA.l $7EF360
CMP.w #$14 ; 20 rupees
SEP #$30
BCC .not_enough_rupees
REP #$20
LDA.l $7EF360
SEC
SBC.w #$14 ; Subtract 20 rupees
STA.l $7EF360
SEP #$30
JMP .appraise_me
.not_enough_rupees
%ShowUnconditionalMessage($0189) ; 'You don't have enough rupees!'
%GotoAction(0)
RTS
.no_rings_yet
%ShowUnconditionalMessage($00AB) ; 'First one is free!'
JMP .appraise_me
.no_rings
%ShowUnconditionalMessage($00AD) ; 'You don't have any rings!'
%GotoAction(0)
RTS
.appraise_me
; Check the found rings and set the saved rings
; Get the bit from found rings and set it in MAGICRINGS
LDA.l FOUNDRINGS
ORA.l MAGICRINGS
STA.l MAGICRINGS
%GotoAction(3)
RTS
}
Vasu_RingAppraised:
{
%PlayAnimation(0,1,20)
%ShowUnconditionalMessage($00AC) ; 'Come back later for more appraisals!'
%GotoAction(0)
RTS
}
Error_Idle:
{
%PlayAnimation(0,1,24)
; "I am Error"
%ShowSolicitedMessage($0121) : BCC +
JSL GetRandomInt : AND.b #$06 : STA.l FOUNDRINGS
+
RTS
}
}
```
## Drawing (`Sprite_Vasu_Draw` and `Sprite_Error_Draw`)
Both drawing routines handle OAM allocation and animation for their respective characters. They explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the character.
## Design Patterns
* **Multi-Character Sprite (Conditional Drawing/Logic)**: A single sprite definition (`Sprite_Vasu`) is used to represent two distinct characters (Vasu and the "Error" sprite) based on `SprSubtype`, showcasing efficient resource utilization and varied visual appearances.
* **Shop/Service System**: Vasu implements a service where he appraises rings for a fee (or for free the first time), integrating a transactional element into NPC interactions.
* **Quest Gating/Progression**: Vasu's interactions are conditional on Link having found rings (`FOUNDRINGS`) and his rupee count, ensuring that the appraisal service is available only when relevant.
* **Conditional Transactions**: The appraisal process involves checking Link's rupee count and deducting the cost, simulating a real in-game economy.
* **Player Choice and Branching Dialogue**: Link's choices (`MsgChoice`) directly influence the flow of conversation, leading to different outcomes and information from Vasu.
* **Item Management**: Vasu interacts with `FOUNDRINGS` and `MAGICRINGS` (SRAM flags) to manage Link's ring collection, updating his inventory based on appraisals.
* **Easter Egg/Hidden Content**: The "Error" sprite, with its unique dialogue, likely serves as an Easter egg or a placeholder for debugging, adding a touch of humor or mystery.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,263 @@
# Village Dog / Eon Dog
## Overview
The `village_dog.asm` file defines the behavior for two distinct dog NPCs: the "Village Dog" and the "Eon Dog." Their appearance and behavior are dynamically determined by the global `WORLDFLAG`. These dogs exhibit random movement, react to Link's proximity, can be lifted and thrown, and offer context-sensitive dialogue based on Link's current form.
## Sprite Properties
* **`!SPRID`**: `Sprite_VillageDog` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `01`
* **`!Palette`**: `00`
* **`!Hitbox`**: `09`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `01` (Checks both layers for collision)
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_VillageDog_Long`)
This routine acts as a dispatcher for drawing, selecting `Sprite_VillageDog_Draw` for the Village Dog (`WORLDFLAG = 0`) or `Sprite_EonDog_Draw` for the Eon Dog. It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_VillageDog_Long:
{
PHB : PHK : PLB
LDA.w WORLDFLAG : BEQ .village
JSR Sprite_EonDog_Draw
JMP +
.village
JSR Sprite_VillageDog_Draw
+
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_VillageDog_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_VillageDog_Prep`)
This routine initializes the dog upon spawning. If it's an Eon Dog (`WORLDFLAG` is not `0`), it sets `SprAction, X` to `$07` and `SprTimerA, X` to `$40`.
```asm
Sprite_VillageDog_Prep:
{
PHB : PHK : PLB
LDA.w WORLDFLAG : BEQ .village
LDA.b #$07 : STA.w SprAction, X
LDA.b #$40 : STA.w SprTimerA, X
.village
PLB
RTL
}
```
## `HandleTossedDog`
This routine manages the vertical movement of a dog that has been tossed. If `SprHeight, X` is not `0`, it decrements it, simulating gravity.
## `LiftOrTalk`
This routine determines whether Link can lift the dog or engage in dialogue. It checks Link's current form (`$02B2`). If Link is in Wolf or Minish form, it calls `ShowMessageIfMinish`. Otherwise, it checks if the dog is lifted (`JSL Sprite_CheckIfLifted`) and handles interactions with thrown sprites (`JSL ThrownSprite_TileAndSpriteInteraction_long`).
## Main Logic & State Machine (`Sprite_VillageDog_Main`)
This routine manages the various states and behaviors of both Village Dogs and Eon Dogs.
* **`Dog_Handler`**: Plays a sitting animation, calls `HandleTossedDog`, and if Link is nearby, sets a timer and transitions to `Dog_LookLeftAtLink` or `Dog_LookRightAtLink`. It also calls `LiftOrTalk`.
* **`Dog_LookLeftAtLink` / `Dog_LookRightAtLink`**: Plays an animation of the dog looking towards Link. After a timer, it transitions to `Dog_MoveLeftTowardsLink` or `Dog_MoveRightTowardsLink`.
* **`Dog_MoveLeftTowardsLink` / `Dog_MoveRightTowardsLink`**: Plays a walking animation, calls `HandleTossedDog`, and if Link is nearby, transitions to `Dog_WagTailLeft` or `Dog_WagTailRight`. It handles tile collisions, applies speed towards Link, and calls `LiftOrTalk`. After a timer, it returns to `Dog_Handler`.
* **`Dog_WagTailLeft` / `Dog_WagTailRight`**: Plays a wagging tail animation, calls `LiftOrTalk` and `HandleTossedDog`. After a timer, it returns to `Dog_Handler`.
* **`EonDog_Handler` / `EonDog_Right`**: These states are specific to the Eon Dog, playing animations and calling `EonDog_Walk`.
```asm
Sprite_VillageDog_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw Dog_Handler ; 00
dw Dog_LookLeftAtLink ; 01
dw Dog_LookRightAtLink ; 02
dw Dog_MoveLeftTowardsLink ; 03
dw Dog_MoveRightTowardsLink ; 04
dw Dog_WagTailLeft ; 05
dw Dog_WagTailRight ; 06
dw EonDog_Handler ; 07
dw EonDog_Right ; 08
; 0
Dog_Handler:
{
%PlayAnimation(8,8,8) ; Sitting
JSR HandleTossedDog
LDA $0309 : AND #$03 : BNE .lifting
LDA #$20 : STA.w SprTimerD, X
JSL Sprite_IsToRightOfPlayer : TYA : BEQ .walk_right
%GotoAction(1)
JMP .lifting
.walk_right
%GotoAction(2)
.lifting
JSR LiftOrTalk
JSL Sprite_Move
RTS
}
; 01
Dog_LookLeftAtLink:
{
%PlayAnimation(9,9,8)
JSR HandleTossedDog
LDA.w SprTimerD, X : BNE +
; Load the timer for the run
LDA.b #$60 : STA.w SprTimerD, X
%GotoAction(3)
+
RTS
}
; 02
Dog_LookRightAtLink:
{
%PlayAnimation(10,10,8)
JSR HandleTossedDog
LDA.w SprTimerD, X : BNE +
; Load the timer for the run
LDA.b #$60 : STA.w SprTimerD, X
%GotoAction(4)
+
RTS
}
; 03
Dog_MoveLeftTowardsLink:
{
%PlayAnimation(2,4,6)
JSR HandleTossedDog
; Check if the dog is near link, then wag the tail
JSR CheckIfPlayerIsNearby : BCC +
%GotoAction(5)
+
; Check for collision
JSL Sprite_CheckTileCollision
LDA $0E70, X : BEQ .no_collision
%GotoAction(0)
.no_collision
LDA.b #$0A
JSL Sprite_ApplySpeedTowardsPlayer
STZ $06 : STZ $07
JSL Sprite_MoveLong
JSR LiftOrTalk
LDA.w SprTimerD, X : BNE +
%GotoAction(0)
+
RTS
}
; 04
Dog_MoveRightTowardsLink:
{
%PlayAnimation(5,7,6)
JSR HandleTossedDog
JSR CheckIfPlayerIsNearby : BCC +
%GotoAction(6)
+
; Check for collision
JSL Sprite_CheckTileCollision
LDA $0E70, X : BEQ .no_collision
%GotoAction(0)
.no_collision
LDA.b #$0A
JSL Sprite_ApplySpeedTowardsPlayer
STZ $06 : STZ $07
JSL Sprite_MoveLong
JSR LiftOrTalk
LDA.w SprTimerD, X : BNE ++
%GotoAction(0)
++
RTS
}
; 05
Dog_WagTailLeft:
{
%PlayAnimation(0,1, 8)
JSR LiftOrTalk
JSR HandleTossedDog
LDA.w SprTimerD, X : BNE +
%GotoAction(0)
+
RTS
}
; 06
Dog_WagTailRight:
{
%PlayAnimation(11,12,8)
JSR LiftOrTalk
JSR HandleTossedDog
LDA.w SprTimerD, X : BNE +
%GotoAction(0)
+
RTS
}
EonDog_Handler:
{
%PlayAnimation(0,1,8)
JSR EonDog_Walk
RTS
}
EonDog_Right:
{
%PlayAnimation(2,3,8)
JSR EonDog_Walk
RTS
}
}
```
## `EonDog_Walk`
This routine handles the Eon Dog's random movement. It moves the sprite (`JSL Sprite_MoveLong`), handles tile collision (`JSL Sprite_BounceFromTileCollision`), and after a timer, randomly selects a new direction and updates its speed and action.
## `CheckIfPlayerIsNearby`
This routine checks if Link is within a specific rectangular area around the dog, returning with the carry flag set if true.
## `ShowMessageIfMinish`
This routine displays a context-sensitive message based on Link's current form (`$02B2`). If Link is in Minish form, it displays message `$18`; otherwise, it displays message `$1B`.
## Drawing (`Sprite_VillageDog_Draw` and `Sprite_EonDog_Draw`)
Both drawing routines handle OAM allocation and animation for their respective dog types. They explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the character.
## Design Patterns
* **Multi-Character NPC (Conditional Drawing/Logic)**: A single sprite definition (`Sprite_VillageDog`) is used to represent two distinct dog characters (Village Dog and Eon Dog) based on `WORLDFLAG`, showcasing efficient resource utilization and varied visual appearances.
* **Random Movement**: The dogs exhibit random movement patterns, contributing to the environmental ambiance and making their movements less predictable.
* **Player Interaction**: The dogs can be lifted and thrown (`LiftOrTalk`), and they react to Link's presence by looking at him and wagging their tails, adding to the interactive elements of the game world.
* **Conditional Dialogue**: The `ShowMessageIfMinish` routine provides context-sensitive dialogue based on Link's current form, enhancing the narrative and player experience.
* **Player Collision**: Implements `Sprite_PlayerCantPassThrough` to make the dogs solid objects that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,38 @@
# Village Elder
## Overview
The `village_elder.asm` file defines the behavior for the "Village Elder" NPC. This is a straightforward NPC whose primary function is to interact with Link through dialogue. The content of the dialogue is conditional, changing based on whether Link has previously met the elder, as tracked by a custom progression flag (`OOSPROG`).
## Main Logic (`Sprite_VillageElder_Main`)
This routine manages the Village Elder's interactions and dialogue flow:
* **Animation**: Plays a specific animation (`%PlayAnimation(2,3,16)`).
* **Player Collision**: Prevents Link from passing through the elder (`JSL Sprite_PlayerCantPassThrough`).
* **Progression Check (`OOSPROG`)**: It checks the `OOSPROG` (Oracle of Secrets Progression) flag. Specifically, it checks if bit `$10` is set, which indicates that Link has already met the elder.
* **First Meeting**: If Link has not yet met the elder, it displays a solicited message (`%ShowSolicitedMessage($143)`). Upon dismissal of this message, it sets bit `$10` in `OOSPROG` to mark that Link has now met the elder.
* **Subsequent Meetings**: If Link has already met the elder, a different solicited message (`%ShowSolicitedMessage($019)`) is displayed.
```asm
Sprite_VillageElder_Main:
{
%PlayAnimation(2,3,16)
JSL Sprite_PlayerCantPassThrough
REP #$30
LDA.l OOSPROG : AND.w #$00FF
SEP #$30
AND.b #$10 : BNE .already_met
%ShowSolicitedMessage($143) : BCC .no_message
LDA.l OOSPROG : ORA.b #$10 : STA.l OOSPROG
.no_message
RTS
.already_met
%ShowSolicitedMessage($019)
RTS
}
```
## Design Patterns
* **Simple NPC Interaction**: The Village Elder provides basic dialogue interaction with Link.
* **Quest Progression Tracking**: Utilizes a custom progression flag (`OOSPROG`) to track whether Link has met the elder, allowing for dynamic changes in dialogue based on game state.
* **Player Collision**: Implements `JSL Sprite_PlayerCantPassThrough` to make the elder a solid object that Link cannot walk through.

218
Docs/Sprites/NPCs/Zora.md Normal file
View File

@@ -0,0 +1,218 @@
# Zora (Generic Sea Zora Handler)
## Overview
The `zora.asm` file serves as a centralized handler for various Zora NPCs within the game. It acts as a dispatcher, directing execution to specific drawing and main logic routines for the Zora Princess, Eon Zora, Eon Zora Elder, and a generic Sea Zora. This dynamic dispatch is based on the current `ROOM`, `WORLDFLAG`, and `SprSubtype`, allowing for a single sprite definition to manage a diverse cast of Zora characters.
## Main Structure (`Sprite_Zora_Long`)
This routine is a complex dispatcher that determines which Zora variant to draw and process based on several game state variables:
* **Zora Princess**: If the current `ROOM` is `$0105`, it calls `Sprite_ZoraPrincess_Draw` and sets `SprMiscG, X` to `$01`.
* **Eon Zora**: If `WORLDFLAG` is not `0`, it calls `Sprite_EonZora_Draw`, `Sprite_DrawShadow`, and sets `SprMiscG, X` to `$02`.
* **Eon Zora Elder**: If `SprSubtype, X` is not `0` (and not the Princess or Eon Zora), it calls `Sprite_EonZoraElder_Draw` and sets `SprMiscG, X` to `$03`.
* **Generic Sea Zora**: Otherwise, it calls `Sprite_Zora_Draw`, `Sprite_DrawShadow`, and sets `SprMiscG, X` to `0`.
* After drawing, it calls `Sprite_CheckActive` and then `Sprite_Zora_Handler` if the sprite is active.
```asm
Sprite_Zora_Long:
{
PHB : PHK : PLB
; Check what Zora we are drawing
REP #$30
LDA.w ROOM : CMP.w #$0105 : BNE .not_princess
SEP #$30
JSR Sprite_ZoraPrincess_Draw
LDA.b #$01 : STA.w SprMiscG, X
JMP +
.not_princess
LDA.w WORLDFLAG : AND.w #$00FF : BEQ .eon_draw
SEP #$30
JSR Sprite_EonZora_Draw
JSL Sprite_DrawShadow
LDA.b #$02 : STA.w SprMiscG, X
JMP +
.eon_draw
SEP #$30
LDA.w SprSubtype, X : BNE .special_zora
JSR Sprite_Zora_Draw
JSL Sprite_DrawShadow
STZ.w SprMiscG, X
JMP +
.special_zora
JSR Sprite_EonZoraElder_Draw
LDA.b #$03 : STA.w SprMiscG, X
+
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Zora_Handler
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Zora_Prep`)
This routine is empty, indicating that custom initialization for the Zora handler is minimal or handled by the individual Zora sprite routines.
## Main Logic Dispatcher (`Sprite_Zora_Handler`)
This routine dispatches to the appropriate main logic routine for the specific Zora variant based on the value of `SprMiscG, X`:
* `$01`: Calls `Sprite_ZoraPrincess_Main`
* `$00`: Calls `Sprite_Zora_Main` (Generic Sea Zora)
* `$02`: Calls `Sprite_EonZora_Main`
* `$03`: Calls `Sprite_EonZoraElder_Main`
```asm
Sprite_Zora_Handler:
{
LDA.w SprMiscG, X
CMP.b #$01 : BNE .not_princess
JSR Sprite_ZoraPrincess_Main
RTS
.not_princess
JSL JumpTableLocal
dw Sprite_Zora_Main
dw Sprite_ZoraPrincess_Main
dw Sprite_EonZora_Main
dw Sprite_EonZoraElder_Main
}
```
## `Sprite_Zora_Main` (Generic Sea Zora)
This routine defines the behavior for a generic Sea Zora NPC.
* **Head Tracking**: Calls `Zora_TrackHeadToPlayer` to make the Zora face Link.
* **Player Collision**: Prevents Link from passing through the Zora (`JSL Sprite_PlayerCantPassThrough`).
* **Dialogue**: Calls `Zora_HandleDialogue` for context-sensitive dialogue interactions.
* **Animation**: Uses a jump table for animation states: `Zora_Forward`, `Zora_Right`, `Zora_Left`, each playing a specific animation.
```asm
Sprite_Zora_Main:
{
JSR Zora_TrackHeadToPlayer
JSL Sprite_PlayerCantPassThrough
JSR Zora_HandleDialogue
LDA.w SprAction, X
JSL JumpTableLocal
dw Zora_Forward
dw Zora_Right
dw Zora_Left
Zora_Forward:
{
%PlayAnimation(0,0,10)
RTS
}
Zora_Right:
{
%PlayAnimation(1,1,10)
RTS
}
Zora_Left:
{
%PlayAnimation(1,1,10)
RTS
}
}
```
## `Zora_TrackHeadToPlayer`
This routine makes the Zora face Link by setting `SprAction, X` to `0` (forward) or `1` (right/left) based on Link's horizontal position relative to the Zora.
## `Zora_HandleDialogue`
This routine handles context-sensitive dialogue for the generic Sea Zora. It checks the `Crystals` SRAM flag (specifically bit `$20`) to determine if a certain crystal has been collected. Based on this and the Zora's `SprAction, X`, it displays different solicited messages (`$01A6`, `$01A5`, or `$01A4`).
## Drawing (`Sprite_Zora_Draw`)
This routine handles OAM allocation and animation for the generic Sea Zora. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_Zora_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprFrame, X : TAY ;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $02, $04
.nbr_of_tiles
db 1, 1, 1
.x_offsets
dw 0, 0
dw 0, 0
dw 0, 0
.y_offsets
dw -8, 0
dw -8, 0
dw -8, 0
.chr
db $DE, $EE
db $DC, $EC
db $DC, $EC
.properties
db $35, $35
db $35, $35
db $75, $75
.sizes
db $02, $02
db $02, $02
db $02, $02
}
```
## Design Patterns
* **Centralized NPC Handler**: This file acts as a central dispatcher for multiple Zora-type NPCs (Zora Princess, Eon Zora, Eon Zora Elder, and generic Sea Zora), demonstrating efficient management of diverse character behaviors from a single entry point.
* **Multi-Character Sprite (Conditional Drawing/Logic)**: A single sprite ID is used to represent various Zora characters, with their specific drawing and main logic routines dynamically selected based on game state variables like `ROOM`, `WORLDFLAG`, and `SprSubtype`.
* **Context-Sensitive Dialogue**: The generic Sea Zora's dialogue changes based on collected crystals and its current `SprAction`, providing dynamic and responsive interactions with the player.
* **Player Collision**: Implements `JSL Sprite_PlayerCantPassThrough` to make the Zora NPCs solid objects that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,219 @@
# Zora Princess
## Overview
The Zora Princess sprite (`!SPRID = Sprite_ZoraPrincess`) is a key NPC involved in a quest that culminates in Link receiving the Zora Mask. Her interactions are conditional, primarily triggered by Link playing the "Song of Healing," and her presence is tied to whether Link has already obtained the Zora Mask.
## Sprite Properties
* **`!SPRID`**: `Sprite_ZoraPrincess` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `9`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `02`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_ZoraPrincess_Long`)
This routine handles the Zora Princess's drawing and dispatches to her main logic if the sprite is active.
```asm
Sprite_ZoraPrincess_Long:
{
PHB : PHK : PLB
JSR Sprite_ZoraPrincess_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_ZoraPrincess_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_ZoraPrincess_Prep`)
This routine initializes the Zora Princess upon spawning. It checks the Zora Mask flag (`$7EF302`). If Link already possesses the Zora Mask, the sprite immediately despawns (`STZ.w SprState, X`), ensuring the quest is a one-time event. It also sets `SprDefl, X` and `SprTileDie, X` to `0`.
```asm
Sprite_ZoraPrincess_Prep:
{
PHB : PHK : PLB
LDA.l $7EF302 : BEQ .doesnt_have_mask
STZ.w SprState, X ; Kill the sprite
.doesnt_have_mask
LDA #$00 : STA.w SprDefl, X
LDA #$00 : STA.w SprTileDie, X
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_ZoraPrincess_Main`)
This routine manages the Zora Princess's interactions and the process of granting the Zora Mask.
* **Player Collision**: Prevents Link from passing through the Zora Princess (`JSL Sprite_PlayerCantPassThrough`).
* **`WaitForLink`**: Plays an animation and displays a solicited message (`%ShowSolicitedMessage($0C5)`). Upon message dismissal, it transitions to `CheckForSongOfHealing`.
* **`CheckForSongOfHealing`**: Plays an animation and checks the `SongFlag`. If the "Song of Healing" has been played, it clears the `SongFlag`, sets a timer (`SprTimerD, X`), and transitions to `ThanksMessage`.
* **`ThanksMessage`**: Plays an animation. After a timer (`SprTimerD, X`), it displays an unconditional message (`%ShowUnconditionalMessage($0C6)`) and transitions to `GiveZoraMask`.
* **`GiveZoraMask`**: After a timer (`SprTimerD, X`), it grants Link the Zora Mask (`LDY #$0F`, `JSL Link_ReceiveItem`), sets the Zora Mask obtained flag (`$7EF302` to `$01`), and despawns the sprite (`STZ.w SprState, X`).
```asm
Sprite_ZoraPrincess_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL JumpTableLocal
dw WaitForLink
dw CheckForSongOfHealing
dw ThanksMessage
dw GiveZoraMask
WaitForLink:
{
%PlayAnimation(0, 1, 10)
%ShowSolicitedMessage($0C5) : BCC .no_hablaba
%GotoAction(1)
.no_hablaba
RTS
}
CheckForSongOfHealing:
{
%PlayAnimation(0, 1, 10)
LDA.b SongFlag : BEQ .ninguna_cancion
STZ.b SongFlag
LDA.b #$C0 : STA.w SprTimerD, X
%GotoAction(2)
.ninguna_cancion
RTS
}
ThanksMessage:
{
%PlayAnimation(0, 1, 10)
LDA.w SprTimerD, X : BNE +
%ShowUnconditionalMessage($0C6)
LDA.b #$C0 : STA.w SprTimerD, X
%GotoAction(3)
+
RTS
}
GiveZoraMask:
{
LDA.w SprTimerD, X : BNE +
LDY #$0F : STZ $02E9 ; Give the Zora Mask
JSL Link_ReceiveItem
LDA #$01 : STA.l $7EF302
LDA.b #$00 : STA.w SprState, X
+
RTS
}
}
```
## Drawing (`Sprite_ZoraPrincess_Draw`)
The drawing routine handles OAM allocation and animation. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_ZoraPrincess_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $04
.nbr_of_tiles
db 3, 11
.x_offsets
dw -4, 4, -4, 4
dw 4, 4, 4, 4, -4, -4, -4, -4, 12, 12, 12, 12
.y_offsets
dw -8, -8, 8, 8
dw -8, 0, 8, 16, -8, 0, 8, 16, -8, 0, 8, 16
.chr
db $C0, $C1, $E0, $E1
db $C1, $D1, $E1, $F1, $C3, $D3, $E3, $F3, $C3, $D3, $E3, $F3
.properties
db $33, $33, $33, $33
db $33, $33, $33, $33, $33, $33, $33, $33, $73, $73, $73, $73
.sizes
db $02, $02, $02, $02
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
}
```
## Design Patterns
* **Quest Gating/Progression**: The Zora Princess's appearance and the granting of the Zora Mask are conditional on Link not already possessing the mask and playing the "Song of Healing," integrating her into a specific questline.
* **NPC Interaction**: The Zora Princess interacts with the player through dialogue and grants a key item (the Zora Mask), which is essential for progression.
* **Conditional Spawning/Despawning**: The sprite dynamically despawns if Link has already obtained the Zora Mask, ensuring that the quest is a one-time event and preventing redundant interactions.
* **Item Granting**: The Zora Princess serves as the source for the Zora Mask, a significant item that likely grants new abilities or access to new areas.
* **Player Collision**: Implements `JSL Sprite_PlayerCantPassThrough` to make the Zora Princess a solid object that Link cannot walk through.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

56
Docs/Sprites/Objects.md Normal file
View File

@@ -0,0 +1,56 @@
# Objects Analysis
This document provides an analysis of the object sprites found in the `Sprites/Objects/` directory. These sprites are typically interactive elements of the environment rather than enemies.
## File Overview
| Filename | Sprite ID(s) | Description |
|---|---|---|
| `collectible.asm` | `$52` | A generic collectible sprite that can represent a Pineapple, Seashell, Sword/Shield, or Rock Sirloin. |
| `deku_leaf.asm` | `Sprite_DekuLeaf` | A Deku Leaf platform that Link can stand on. Also used for whirlpools. |
| `ice_block.asm` | `$D5` | A pushable ice block used in puzzles. |
| `minecart.asm` | `Sprite_Minecart` (`$A3`) | A rideable minecart used for transportation puzzles in dungeons. |
| `mineswitch.asm` | `Sprite_Mineswitch` | A lever switch that can be hit to change the state of other objects, like minecart tracks. |
| `pedestal.asm` | (Hooks `$1EE05F`) | Logic for the magic pedestals where Link can read text with the Book of Mudora. |
| `portal_sprite.asm` | `Sprite_Portal` | The blue and orange portals created by the Portal Rod. |
| `switch_track.asm` | `Sprite_SwitchTrack` (`$B0`) | The visual component of a switchable minecart track, which rotates when a lever is hit. |
## Detailed Object Analysis
### `collectible.asm`
- **Sprite ID:** `$52`
- **Summary:** This is a versatile sprite that acts as a world collectible. Its behavior and appearance are determined by its `SprAction` state, which is set during prep.
- **Key Logic:**
- **`Sprite_Collectible_Prep`:** Checks the current map (`$8A`) to determine what the sprite should be. For example, on map `$58` (intro), it becomes the sword and shield.
- **`Sprite_Collectible_Main`:** The main state machine. On contact with the player (`Sprite_CheckDamageToPlayer`), it increments the corresponding counter in SRAM (e.g., `Pineapples`, `Seashells`) or grants an item (`Link_ReceiveItem`) and then despawns itself.
### `ice_block.asm`
- **Sprite ID:** `$D5`
- **Summary:** A block that slides on icy floors when pushed by Link. It is used for puzzles.
- **Key Logic:**
- **Pushing:** When Link is in contact (`Sprite_CheckDamageToPlayerSameLayer`), the `Sprite_ApplyPush` routine gives the block velocity based on the direction Link is facing.
- **Sliding:** The block continues to move in that direction (`Sprite_Move`) until it hits a wall (`Sprite_CheckTileCollision`) or another object.
- **Switch Interaction:** `Sprite_IceBlock_CheckForSwitch` checks if the block is on top of a floor switch tile. If so, it sets a flag (`$0642`) to activate the switch and stops moving.
### `minecart.asm` / `switch_track.asm` / `mineswitch.asm`
- **Sprite IDs:** `Sprite_Minecart` (`$A3`), `Sprite_SwitchTrack` (`$B0`), `Sprite_Mineswitch`
- **Summary:** This is a complex system of three interconnected sprites that create minecart puzzles.
- **Key Logic:**
- **`Sprite_Minecart`:**
- The player can press B to enter the cart (`Minecart_WaitHoriz`/`Vert`). This sets the `!LinkInCart` flag and attaches the player.
- The cart moves along a path defined by custom tile types (`$B0`-`$BE`).
- At intersections (`$B6`, etc.), it reads player input (`$F0`) to determine which way to turn (`CheckForPlayerInput`).
- At corners (`$B2`-`$B5`), it automatically turns (`CheckForCornerTiles`).
- At dynamic switch tracks (`$D0`-`$D3`), it checks the state of the corresponding `Sprite_Mineswitch` to determine its path (`HandleDynamicSwitchTileDirections`).
- At dungeon transitions, it converts into a follower sprite (`MinecartFollower_TransitionToSprite`) to persist between rooms.
- **`Sprite_SwitchTrack`:** This is a purely visual sprite. Its frame is set based on the on/off state of its corresponding `Mineswitch`, which is stored in `SwitchRam`.
- **`Sprite_Mineswitch`:** This is a lever. When hit by the player, it toggles its state in the `SwitchRam` array, which is then read by the `SwitchTrack` and `Minecart` sprites.
### `portal_sprite.asm`
- **Sprite ID:** `Sprite_Portal`
- **Summary:** This sprite handles the logic for the portals created by the Portal Rod.
- **Key Logic:**
- **Spawning:** Two portals can exist at once: one blue and one orange. The `StateHandler` determines which type to create based on the `$7E0FA6` flag.
- **Warping:** When Link overlaps with a portal (`CheckIfHitBoxesOverlap`), it triggers a warp. The destination is the location of the *other* portal, whose coordinates are stored in RAM (`BluePortal_X/Y`, `OrangePortal_X/Y`).
- **Dismissal:** The `CheckForDismissPortal` routine despawns the oldest portal when a third one is created.
- **Invalid Placement:** `RejectOnTileCollision` prevents portals from being placed on invalid surfaces like walls and despawns the sprite if they are.

View File

@@ -0,0 +1,172 @@
# Collectible Sprites (Pineapple, Seashell, Sword/Shield, Rock Sirloin)
## Overview
The Collectible sprite (`!SPRID = $52`) is a versatile implementation designed to represent various collectible items within the game, including Pineapples, Seashells, the starting Sword/Shield, and Rock Sirloin. Its specific appearance and behavior are dynamically determined by the `SprAction, X` state and the current `AreaIndex`, allowing for context-sensitive item placement and interaction.
## Sprite Properties
* **`!SPRID`**: `$52` (Vanilla sprite ID, likely for a generic collectible)
* **`!NbrTiles`**: `03`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Collectible_Long`)
This routine acts as a dispatcher for drawing, selecting the appropriate drawing routine based on the `AreaIndex`:
* If `AreaIndex` is `$58` (Intro Sword area), it calls `Sprite_SwordShield_Draw`.
* If `AreaIndex` is `$4B` (Lupo Mountain area), it calls `Sprite_RockSirloin_Draw`.
* Otherwise, it calls `Sprite_Pineapple_Draw`.
* It also handles shadow drawing and dispatches to the main logic if the sprite is active.
```asm
Sprite_Collectible_Long:
{
PHB : PHK : PLB
LDA.b $8A : CMP.b #$58 : BNE .not_intro_sword
JSR Sprite_SwordShield_Draw
BRA +
.not_intro_sword
LDA.b $8A : CMP.b #$4B : BNE .not_lupo_mountain
JSR Sprite_RockSirloin_Draw
BRA +
.not_lupo_mountain
JSR Sprite_Pineapple_Draw
+
JSL Sprite_DrawShadow
JSL Sprite_CheckActive
BCC .SpriteIsNotActive
JSR Sprite_Collectible_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Collectible_Prep`)
This routine initializes the collectible sprite upon spawning, with conditional logic based on the `AreaIndex`:
* **Intro Sword**: If `AreaIndex` is `$58`, it checks Link's Sword flag (`$7EF359`). If Link already has the Sword, the sprite despawns. It also sets `SprAction, X` to `$02` (SwordShield).
* **Rock Sirloin**: If `AreaIndex` is `$4B`, it sets `SprAction, X` to `$03` (RockSirloin).
```asm
Sprite_Collectible_Prep:
{
PHB : PHK : PLB
; Don't spawn the sword if we have it.
LDA.b $8A : CMP.b #$58 : BNE .not_intro_sword
LDA.l $7EF359 : BEQ +
STZ.w SprState, X
+
LDA.b #$02 : STA.w SprAction, X
.not_intro_sword
LDA.b $8A : CMP.b #$4B : BNE .not_lupo_mountain
LDA.b #$03 : STA.w SprAction, X
.not_lupo_mountain
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_Collectible_Main`)
This routine manages the behavior of various collectible items through a jump table based on `SprAction, X`:
* **`Pineapple`**: Moves the sprite (`JSL Sprite_Move`). If Link touches it (`JSL Sprite_CheckDamageToPlayer`), it increments the `Pineapples` custom item count and despawns the sprite.
* **`Seashell`**: Similar to Pineapple, but increments the `Seashells` custom item count.
* **`SwordShield`**: Plays an animation, moves the sprite. If Link touches it, it grants Link the Sword (`LDY.b #$00`, `JSL Link_ReceiveItem`) and despawns the sprite.
* **`RockSirloin`**: Moves the sprite. It checks Link's Glove flag (`$7EF354`). If Link has the Glove, it checks for player contact. If touched, it handles interaction with thrown sprites (`JSL ThrownSprite_TileAndSpriteInteraction_long`), increments the `RockMeat` custom item count, and despawns the sprite.
```asm
Sprite_Collectible_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw Pineapple
dw Seashell
dw SwordShield
dw RockSirloin
Pineapple:
{
JSL Sprite_Move
JSL Sprite_CheckDamageToPlayer : BCC +
LDA.l Pineapples : INC A : STA.l Pineapples
STZ.w SprState, X
+
RTS
}
Seashell:
{
JSL Sprite_Move
JSL Sprite_CheckDamageToPlayer : BCC +
LDA.l Seashells : INC A : STA.l Seashells
STZ.w SprState, X
+
RTS
}
SwordShield:
{
%PlayAnimation(0,0,1)
JSL Sprite_Move
JSL Sprite_CheckDamageToPlayer : BCC +
LDY.b #$00 : STZ $02E9
JSL Link_ReceiveItem
STZ.w SprState, X
+
RTS
}
RockSirloin:
{
JSL Sprite_Move
LDA.l $7EF354 : BEQ .do_you_even_lift_bro
JSL Sprite_CheckDamageToPlayer : BCC +
JSL ThrownSprite_TileAndSpriteInteraction_long
LDA.l RockMeat : INC A : STA.l RockMeat
STZ.w SprState, X
+
.do_you_even_lift_bro
RTS
}
}
```
## Drawing (`Sprite_Pineapple_Draw`, `Sprite_SwordShield_Draw`, `Sprite_RockSirloin_Draw`)
Each collectible type has its own dedicated drawing routine. These routines handle OAM allocation and animation, and explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the respective item.
## Design Patterns
* **Multi-Item Collectible**: A single sprite definition (`!SPRID = $52`) is used to represent multiple distinct collectible items, with their specific appearance and behavior determined by `SprAction, X` and `AreaIndex`. This allows for efficient reuse of sprite slots for various in-game items.
* **Context-Sensitive Spawning/Drawing**: The sprite's initial appearance and drawing routine are dynamically selected based on the `AreaIndex`, enabling specific items to appear in designated locations within the game world.
* **Item Granting**: Collectibles grant items to Link upon contact, directly influencing his inventory and progression.
* **Quest Progression Integration**: The Sword/Shield collectible despawns if Link already possesses the Sword, and the Rock Sirloin requires Link to have the Glove to interact with it, integrating these items into the game's quest and progression systems.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,147 @@
# Deku Leaf / Whirlpool
## Overview
The `deku_leaf.asm` file defines a versatile sprite (`!SPRID = Sprite_DekuLeaf`) that can function as two distinct in-game objects: the "Deku Leaf" and a "Whirlpool." Its specific behavior and visual representation are dynamically determined by the current `AreaIndex`, allowing it to serve different purposes in various locations.
## Sprite Properties
* **`!SPRID`**: `Sprite_DekuLeaf` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `00` (Graphics are handled externally or as a background)
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `$0D`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_DekuLeaf_Long`)
This routine acts as a dispatcher for drawing, selecting `Sprite_Whirlpool_Draw` if `AreaIndex` is `$3D` (Whirlpool area), and `Sprite_DekuLeaf_Draw` otherwise. It also dispatches to the main logic if the sprite is active.
```asm
Sprite_DekuLeaf_Long:
{
PHB : PHK : PLB
LDA $8A : CMP.b #$3D : BEQ .whirlpool
JSR Sprite_DekuLeaf_Draw
JMP +
.whirlpool
JSR Sprite_Whirlpool_Draw
+
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_DekuLeaf_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_DekuLeaf_Prep`)
This routine initializes the sprite upon spawning. If `AreaIndex` is `$3D` (Whirlpool area), it sets `SprAction, X` to `$01` (`Whirlpool_Main`), indicating its role as a whirlpool.
```asm
Sprite_DekuLeaf_Prep:
{
PHB : PHK : PLB
LDA $8A : CMP.b #$3D : BNE .not_whirlpool
LDA.b #$01 : STA.w SprAction, X
.not_whirlpool
PLB
RTL
}
```
## Main Logic & State Machine (`Sprite_DekuLeaf_Main`)
This routine manages the behavior of both the Deku Leaf and the Whirlpool through a jump table based on `SprAction, X`:
* **`WaitForPlayer` (Deku Leaf)**: Plays an idle animation. It checks if Link is on the leaf (`JSR CheckIfPlayerIsOn`). If so, it sets a flag (`$71`) and, if Link is in Minish form, spawns a poof garnish. Otherwise, it clears the flag.
* **`Whirlpool_Main`**: Plays an animation. If Link is on the whirlpool and the underwater flag (`$0AAB`) is set, it resets various Link state flags (`$55`, `$0AAB`, `$0351`, `$037B`, `$02B2`). If Link's state is not `$0B` (Mirror), it saves Link's coordinates and sets `GameMode` to `$23` to initiate a warp, similar to the Mirror effect.
```asm
Sprite_DekuLeaf_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw WaitForPlayer
dw Whirlpool_Main
WaitForPlayer:
{
%StartOnFrame(0)
%PlayAnimation(0, 0, 10)
JSR CheckIfPlayerIsOn : BCC +
LDA.b #$01 : STA.b $71
LDA.w $02B2 : CMP.b #$01 : BNE ++
JSL Sprite_SpawnPoofGarnish
++
RTS
+
STZ.b $71
RTS
}
Whirlpool_Main:
{
%PlayAnimation(0, 2, 10)
JSR CheckIfPlayerIsOn : BCC .not_on
LDA $0AAB : BEQ .not_on
STZ $55 ; Reset cape flag
STZ $0AAB ; Reset underwater flag
STZ $0351 ; Reset ripple flag
STZ $037B ; Reset invincibility flag
STZ $02B2 ; Reset mask flag
LDA.b $10 : CMP.b #$0B : BEQ .exit
LDA.b $8A : AND.b #$40 : STA.b $7B : BEQ .no_mirror_portal
LDA.b $20 : STA.w $1ADF
LDA.b $21 : STA.w $1AEF
LDA.b $22 : STA.w $1ABF
LDA.b $23 : STA.w $1ACF
.no_mirror_portal
LDA.b #$23
#SetGameModeLikeMirror:
STA.b $11
STZ.w $03F8
LDA.b #$01 : STA.w $02DB
STZ.b $B0
STZ.b $27 : STZ.b $28
LDA.b #$14 : STA.b $5D
.not_on
.exit
RTS
}
}
```
## Drawing (`Sprite_DekuLeaf_Draw` and `Sprite_Whirlpool_Draw`)
Each object type has its own dedicated drawing routine. These routines handle OAM allocation and animation, and explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations. Each routine contains its own specific OAM data for rendering the respective object.
## Design Patterns
* **Multi-Object Sprite (Conditional Drawing/Logic)**: A single sprite definition (`Sprite_DekuLeaf`) is used to represent two distinct objects (Deku Leaf and Whirlpool) based on `AreaIndex`, showcasing efficient resource utilization and varied functionality.
* **Context-Sensitive Behavior**: The sprite's behavior changes entirely based on the `AreaIndex`, allowing it to function as a traversal item (Deku Leaf) or a warp point (Whirlpool), adapting to different game contexts.
* **Player Interaction**: The Deku Leaf allows Link to stand on it for traversal, while the Whirlpool provides a warp mechanism, both offering unique forms of player interaction.
* **Game State Manipulation**: The Whirlpool modifies various Link state flags to initiate a warp, demonstrating direct control over the player's game state during transitions.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,208 @@
# Ice Block (Pushable)
## Overview
The Ice Block sprite (`!SPRID = $D5`) is an interactive object designed as a puzzle element that Link can push. It features complex logic for detecting Link's push, applying movement with momentum, and interacting with switch tiles. This sprite is impervious to most attacks and behaves like a solid statue.
## Sprite Properties
* **`!SPRID`**: `$D5` (Vanilla sprite ID, likely for a pushable block)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `09`
* **`!Persist`**: `00`
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `01` (Behaves like a solid statue)
* **`!DeflectProjectiles`**: `01` (Deflects all projectiles)
* **`!ImperviousArrow`**: `01` (Impervious to arrows)
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Constants
* **`!ICE_BLOCK_SPEED`**: `16` (Speed at which the ice block moves when pushed)
* **`!PUSH_CONFIRM_FRAMES`**: `10` (Number of frames Link must maintain a push for it to be confirmed)
* **`!ALIGN_TOLERANCE`**: `4` (Pixel tolerance for Link's alignment with the block)
* **`!WRAM_FLAG_0642`**: `$0642` (WRAM address for a flag related to switch activation)
* **`!WRAM_TILE_ATTR`**: `$0FA5` (WRAM address for tile attributes)
* **`!SPRITE_LOOP_MAX`**: `$0F` (Max index for sprite loops)
* **`!SPRITE_TYPE_STATUE`**: `$1C` (Sprite ID for a generic statue)
* **`!SPRITE_STATE_ACTIVE`**: `$09` (Sprite state for active sprites)
* **`!TILE_ATTR_ICE`**: `$0E` (Tile attribute for ice, currently unused)
* **`!SWITCH_TILE_ID_1` to `!SWITCH_TILE_ID_4`**: IDs for various switch tiles.
* **`!SWITCH_TILE_COUNT_MINUS_1`**: `$03`
## Main Structure (`Sprite_IceBlock_Long`)
This routine handles the Ice Block's drawing and dispatches to its main logic if active. It also manages Link's interaction with the block, setting Link's speed and actions when pushing.
```asm
Sprite_IceBlock_Long:
{
PHB : PHK : PLB
LDA.w SprMiscC, X : BEQ .not_being_pushed
STZ.w SprMiscC, X
STZ.b LinkSpeedTbl
STZ.b $48 ; Clear push actions bitfield
.not_being_pushed
LDA.w SprTimerA, X : BEQ .retain_momentum
LDA.b #$01 : STA.w SprMiscC, X
LDA.b #$84 : STA.b $48 ; Set statue and push block actions
LDA.b #$04 : STA.b LinkSpeedTbl ; Slipping into pit speed
.retain_momentum
JSR Sprite_IceBlock_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_IceBlock_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_IceBlock_Prep`)
This routine initializes the Ice Block upon spawning. It caches the sprite's initial position in `SprMiscD, X` through `SprMiscG, X`. It sets `SprDefl, X` to `$04` (designating it as a pushable statue) and initializes `SprMiscB, X` to `0` (movement state).
```asm
Sprite_IceBlock_Prep:
{
PHB : PHK : PLB
; Cache Sprite position
LDA.w SprX, X : STA.w SprMiscD, X
LDA.w SprY, X : STA.w SprMiscE, X
LDA.w SprXH, X : STA.w SprMiscF, X
LDA.w SprYH, X : STA.w SprMiscG, X
LDA.b #$04 : STA.w SprDefl, X ; Set as pushable statue
LDA.w SprHitbox, X : ORA.b #$09 : STA.w SprHitbox, X
; Initialize movement state tracking
STZ.w SprMiscB, X ; Clear movement state
PLB
RTL
}
```
## Main Logic (`Sprite_IceBlock_Main`)
This routine manages the Ice Block's behavior, including push detection, movement, and interaction with switches.
* **Animation**: Plays a static animation (`%PlayAnimation(0, 0, 1)`).
* **Sprite-to-Sprite Collision**: Calls `IceBlock_HandleSpriteToSpriteCollision` to manage interactions with other sprites.
* **Damage Reaction**: If the block takes damage, its position, speed, and movement state are reset.
* **Switch Detection**: Calls `Sprite_IceBlock_CheckForSwitch`. If the block is on a switch, it stops movement, sets `!WRAM_FLAG_0642` to `01`, and resets its movement state.
* **Push Logic**: This is a core part of the routine. If the block is not moving, it checks if Link is in contact and correctly aligned (`IceBlock_CheckLinkPushAlignment`). If so, a push timer (`SprTimerA, X`) is initiated. If the timer expires while Link is still pushing, the block snaps to the grid, applies push speed (`Sprite_ApplyPush`), and begins moving. If the block is already moving, it continues to move (`JSL Sprite_Move`) and checks for tile collisions, stopping if an obstacle is encountered.
```asm
Sprite_IceBlock_Main:
{
%PlayAnimation(0, 0, 1)
JSR IceBlock_HandleSpriteToSpriteCollision ; Renamed from Statue_BlockSprites
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
LDA.w SprMiscD, X : STA.w SprX, X
LDA.w SprY, X : STA.w SprY, X
LDA.w SprXH, X : STA.w SprXH, X
LDA.w SprYH, X : STA.w SprYH, X
STZ.w SprXSpeed, X : STZ.w SprYSpeed, X
STZ.w SprTimerA, X : STZ.w SprMiscA, X
STZ.w SprMiscB, X ; Reset movement state when hit
.no_damage
STZ.w !WRAM_FLAG_0642
JSR Sprite_IceBlock_CheckForSwitch : BCC .no_switch
STZ.w SprXSpeed, X : STZ.w SprYSpeed, X
LDA.b #$01 : STA.w !WRAM_FLAG_0642
STZ.w SprMiscB, X ; Reset movement state when hitting switch
.no_switch
; If the block is currently moving, apply movement and check for collisions
LDA.w SprMiscB, X
BNE .block_is_moving
; --- Block is NOT moving, check for push initiation ---
JSL Sprite_CheckDamageToPlayerSameLayer : BCC .NotInContact
; Link is in contact. Now check if he's properly aligned and facing the block.
JSR IceBlock_CheckLinkPushAlignment
BCC .NotInContact ; Link is not aligned or facing correctly.
; Link is aligned and facing the block. Start or continue the push timer.
LDA.w SprTimerA, X
BNE .timer_is_running ; Timer already started, let it count down.
; Start the timer for the first time.
LDA.b #!PUSH_CONFIRM_FRAMES
STA.w SprTimerA, X
RTS ; Wait for next frame
.timer_is_running
; Timer is running. Has it reached zero? (SprTimerA is decremented by engine)
LDA.w SprTimerA, X
BNE .NotInContact ; Not zero yet, keep waiting.
; --- PUSH CONFIRMED ---
; Timer reached zero while still in contact and aligned.
; Snap to grid before setting speed for clean movement.
LDA.w SprX, X : AND.b #$F8 : STA.w SprX, X
LDA.w SprY, X : AND.b #$F8 : STA.w SprY, X
JSR Sprite_ApplyPush ; Set speed based on Link's direction.
LDA.b #$01 : STA.w SprMiscB, X ; Set "is moving" flag.
RTS
.NotInContact
; No contact or improper alignment, reset push timer.
STZ.w SprTimerA, X
RTS
.block_is_moving
JSL Sprite_Move
JSL Sprite_Get_16_bit_Coords
JSL Sprite_CheckTileCollision
; ----udlr , u = up, d = down, l = left, r = right
LDA.w SprCollision, X : AND.b #$0F : BEQ + ; If no collision, continue moving
STZ.w SprXSpeed, X : STZ.w SprYSpeed, X ; Stop movement
STZ.w SprMiscB, X ; Reset movement state
+
RTS
}
```
## `IceBlock_CheckLinkPushAlignment`
This complex routine precisely determines if Link is correctly aligned and facing the ice block to initiate a push. It calculates the relative positions of Link and the block, considers Link's facing direction, and uses `!ALIGN_TOLERANCE` to allow for slight pixel variations. It returns with the carry flag set for success or clear for failure.
## `Sprite_ApplyPush`
This routine sets the Ice Block's `SprXSpeed, X` or `SprYSpeed, X` based on Link's facing direction (`SprMiscA, X`) and the predefined `!ICE_BLOCK_SPEED`.
## `IceBlock_CheckForGround`
This routine is currently unused but was intended to check if the tile beneath the sprite was a sliding ice tile.
## `Sprite_IceBlock_CheckForSwitch`
This routine checks if any of the four corners of the Ice Block are currently positioned on a switch tile (identified by `!SWITCH_TILE_ID_1` to `!SWITCH_TILE_ID_4`). It returns with the carry flag set if any corner is on a switch tile.
## `IceBlock_HandleSpriteToSpriteCollision`
This routine (renamed from `Statue_BlockSprites`) manages collisions between the Ice Block and other active sprites. It iterates through other sprites, checks for collision, and applies recoil or other effects to them.
## Drawing (`Sprite_IceBlock_Draw`)
This routine handles OAM allocation and animation for the Ice Block. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
## Design Patterns
* **Interactive Puzzle Element**: The Ice Block is a core interactive puzzle element that Link can manipulate by pushing, requiring precise player input and environmental interaction.
* **Precise Collision and Alignment Detection**: Implements detailed logic to ensure Link is correctly positioned and facing the block before a push is registered, providing a robust and fair interaction mechanism.
* **Movement with Momentum**: The block retains momentum after being pushed, sliding across the terrain until it encounters an obstacle, adding a realistic physics element.
* **Switch Activation**: The block can activate switch tiles upon contact, integrating it into environmental puzzles and triggering game events.
* **Sprite-to-Sprite Collision**: Handles interactions with other sprites, applying recoil effects to them, demonstrating complex inter-sprite dynamics.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,166 @@
# Mine Switch
## Overview
The Mine Switch sprite (`!SPRID = Sprite_Mineswitch`) is an interactive puzzle element, typically found in the Goron Mines. It functions as a lever-style switch that Link can activate by attacking it, altering the state of minecart tracks or other game elements. This sprite supports both a regular on/off switch and a speed-controlling switch, with its behavior and appearance changing based on its current state.
## Sprite Properties
* **`!SPRID`**: `Sprite_Mineswitch` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `01`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `01`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_LeverSwitch_Long`)
This routine handles the Mine Switch's drawing and dispatches to its main logic if the sprite is active.
```asm
Sprite_LeverSwitch_Long:
{
PHB : PHK : PLB
JSR Sprite_LeverSwitch_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_LeverSwitch_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_LeverSwitch_Prep`)
This routine initializes the Mine Switch upon spawning. It sets `SprDefl, X` to `0`. It retrieves the switch's on/off state from `SwitchRam`, indexed by `SprSubtype, X`, and sets `SprAction, X` and `SprFrame, X` accordingly. It also sets `SprTileDie, X` to `0` and `SprBulletproof, X` to `0`.
```asm
Sprite_LeverSwitch_Prep:
{
PHB : PHK : PLB
LDA.b #$00 : STA.w SprDefl, X
; Get the subtype of the switch so that we can get its on/off state.
LDA.w SprSubtype, X : TAY
LDA.w SwitchRam, Y : STA.w SprAction, X : STA.w SprFrame, X
LDA.b #$00 : STA.w SprTileDie, X
STZ.w SprBulletproof, X
PLB
RTL
}
```
## Constants
* **`SwitchRam = $0230`**: A WRAM address that stores the state (on/off) of each individual switch, indexed by its `SprSubtype`.
## Main Logic & State Machine (`Sprite_LeverSwitch_Main`)
This routine manages the Mine Switch's behavior through a jump table, supporting different types of switches:
* **Player Collision**: Prevents Link from passing through the switch (`JSL Sprite_PlayerCantPassThrough`).
* **`SwitchOff`**: Plays an animation. If Link attacks it (`JSL Sprite_CheckDamageFromPlayer`) and a timer (`SprTimerA, X`) allows, it plays a sound (`$25`), turns the switch on (`STA.w SwitchRam, Y` to `01`), sets a timer, and transitions to `SwitchOn`.
* **`SwitchOn`**: Plays an animation. If Link attacks it and a timer allows, it plays a sound (`$25`), turns the switch off (`STA.w SwitchRam, Y` to `00`), sets a timer, and transitions to `SwitchOff`.
* **`SpeedSwitchOff`**: Plays an animation. If Link attacks it, it plays a sound (`$25`), sets `$36` to `01` (likely a global speed flag for minecarts), and transitions to `SpeedSwitchOn`.
* **`SpeedSwitchOn`**: Plays an animation. If Link attacks it, it plays a sound (`$25`), clears `$36`, and transitions to `SpeedSwitchOff`.
```asm
Sprite_LeverSwitch_Main:
{
JSL Sprite_PlayerCantPassThrough
LDA.w SprAction, X
JSL UseImplicitRegIndexedLocalJumpTable
dw SwitchOff
dw SwitchOn
dw SpeedSwitchOff
dw SpeedSwitchOn
SwitchOff:
{
%PlayAnimation(0,0,4)
LDA.w SprTimerA, X : BNE .NoDamage
JSL Sprite_CheckDamageFromPlayer : BCC .NoDamage
LDA #$25 : STA $012F
; Get the subtype of the switch so that we can get its on/off state.
LDA.w SprSubtype, X : TAY
; Turn the switch on.
LDA #$01 : STA.w SwitchRam, Y
LDA #$10 : STA.w SprTimerA, X
%GotoAction(1)
.NoDamage
RTS
}
SwitchOn:
{
%PlayAnimation(1,1,4)
LDA.w SprTimerA, X : BNE .NoDamage
JSL Sprite_CheckDamageFromPlayer : BCC .NoDamage
LDA #$25 : STA $012F
; Get the subtype of the switch so that we can get its on/off state.
LDA.w SprSubtype, X : TAY
; Turn the switch off.
LDA #$00 : STA.w SwitchRam, Y
LDA #$10 : STA.w SprTimerA, X
%GotoAction(0)
.NoDamage
RTS
}
SpeedSwitchOff:
{
%PlayAnimation(0,0,4)
JSL Sprite_CheckDamageFromPlayer : BCC .NoDamage
LDA.b #$25 : STA $012F
LDA.b #$01 : STA $36
%GotoAction(3)
.NoDamage
RTS
}
SpeedSwitchOn:
{
%PlayAnimation(1,1,4)
JSL Sprite_CheckDamageFromPlayer : BCC .NoDamage
LDA #$25 : STA $012F
STZ.w $36
%GotoAction(2)
.NoDamage
RTS
}
}
```
## Drawing (`Sprite_LeverSwitch_Draw`)
This routine handles OAM allocation and animation for the Mine Switch. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
## Design Patterns
* **Interactive Puzzle Element**: The Mine Switch is a key interactive puzzle element that Link can activate by attacking it, triggering changes in the game environment.
* **State-Based Behavior**: The switch has distinct "on" and "off" states, with different animations and effects, providing clear visual feedback to the player.
* **Subtype-Driven State**: The `SprSubtype` is used to index into `SwitchRam`, allowing each individual switch to maintain its own independent state, enabling complex puzzle designs with multiple switches.
* **Speed Control**: The "Speed Switch" variant directly controls a global speed flag (`$36`), likely affecting the speed of minecarts or other moving objects, adding another layer of interaction to the minecart system.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,113 @@
# Minecart
## Overview
The Minecart sprite (`!SPRID = Sprite_Minecart`) is a highly complex and interactive object primarily used in the Goron Mines. It allows Link to ride it through a network of tracks, with its movement dictated by various track tile types, player input, and seamless dungeon transitions. The Minecart system features persistent state across rooms and intricate collision detection.
## Sprite Properties
* **`!SPRID`**: `Sprite_Minecart` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `08`
* **`!Harmless`**: `01`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `01` (Impervious to all attacks)
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `14`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Constants
* **`!LinkInCart`**: `$35` (Flag indicating Link is currently riding the Minecart)
* **`!MinecartSpeed`**: `20` (Normal movement speed)
* **`!DoubleSpeed`**: `30` (Faster movement speed, possibly for boosts)
* **Directions**: `North`, `East`, `South`, `West` (Used for `!MinecartDirection` and `SprMiscB`)
* **Sprite Facing Directions**: `Up`, `Down`, `Left`, `Right` (Used for `!SpriteDirection`)
* **`!MinecartDirection`**: `$0DE0` (Maps to `SprMiscC`, stores the current movement direction)
* **`!SpriteDirection`**: `$0DE0` (Stores the sprite's visual facing direction)
* **Track Persistence**: A system for saving and loading minecart state across rooms:
* **`!MinecartTrackRoom`**: `$0728` (Stores the room ID where a specific track was left)
* **`!MinecartTrackX`**: `$0768` (Stores the X position of a track)
* **`!MinecartTrackY`**: `$07A8` (Stores the Y position of a track)
* **Active Cart Tracking**: Variables to manage the currently active minecart:
* **`!MinecartTrackCache`**: `$07E8` (Stores the ID of the track Link is currently on)
* **`!MinecartDirectionCache`**: `$07E9` (Stores the direction during room transitions)
* **`!MinecartCurrent`**: `$07EA` (Stores the sprite slot index of the current minecart)
## Collision Setup (Tile Types)
Defines various tile types that represent different parts of the minecart track, including straight sections, corners, intersections, stop tiles, and dynamic switch tiles. These are crucial for guiding the minecart's movement and interaction with the environment.
## Main Structure (`Sprite_Minecart_Long`)
This routine handles the Minecart's multi-layered drawing (top and bottom portions) and dispatches to its main logic if the sprite is active.
```asm
Sprite_Minecart_Long:
{
PHB : PHK : PLB
JSR Sprite_Minecart_DrawTop ; Draw behind Link
JSR Sprite_Minecart_DrawBottom ; Draw in front of Link
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Minecart_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Minecart_Prep`)
This routine initializes the Minecart upon spawning. It updates cached coordinates, manages track persistence (initializing track data if not already set), and handles despawning if the cart is not in its designated room or its coordinates don't match. It sets various sprite properties and determines the initial movement direction based on the tile the minecart is placed on.
## Main Logic & State Machine (`Sprite_Minecart_Main`)
This routine manages the Minecart's complex behavior through a state machine:
* **`Minecart_WaitHoriz` / `Minecart_WaitVert`**: The cart waits in a horizontal or vertical orientation. If Link is on the cart (`CheckIfPlayerIsOn`) and presses the B button, it saves the track ID, cancels Link's dash, sets `LinkSomaria` and `!LinkInCart`, adjusts Link's position, and transitions to a movement state (`Minecart_MoveEast`, `Minecart_MoveWest`, `Minecart_MoveNorth`, `Minecart_MoveSouth`).
* **`Minecart_MoveNorth` / `MoveEast` / `MoveSouth` / `MoveWest`**: The cart moves in the specified direction. It plays animations, sets speed (`!MinecartSpeed` or `!DoubleSpeed`), moves the sprite, drags Link along (`JSL DragPlayer`), handles the player camera, and processes track tiles (`HandleTileDirections`).
* **`Minecart_Release`**: Stops the cart, releases Link, and transitions back to a `Minecart_Wait` state.
## Helper Routines
* **`HandlePlayerCameraAndMoveCart`**: Manages Link's animation, camera, and plays cart sound effects.
* **`StopCart`**: Stops the cart, releases Link, rounds its coordinates, and saves its position to track variables for persistence.
* **`InitMovement`**: Caches Link's coordinates for movement calculations.
* **`Minecart_SetDirectionNorth` / `East` / `South` / `West`**: Set the cart's direction, animation, and update track caches.
* **`HandleTileDirections`**: A crucial routine that checks the tile the minecart is currently on and determines its next action, handling out-of-bounds, stop tiles, player input at intersections, corner tiles, and dynamic switch tiles.
* **`CheckForOutOfBounds`**: Determines if the cart is on an out-of-bounds tile.
* **`CheckForStopTiles`**: Checks for stop tiles and sets the cart's next direction.
* **`CheckForPlayerInput`**: Detects player input on intersection tiles to allow Link to choose the cart's direction.
* **`CheckForCornerTiles`**: Handles direction changes when the cart encounters corner tiles.
* **`HandleDynamicSwitchTileDirections`**: Manages movement on dynamic switch tiles, which can alter the cart's path.
* **`CheckTrackSpritePresence`**: Checks for the presence and collision of a `Sprite $B0` (Switch Track) with the minecart.
* **`CheckIfPlayerIsOn`**: Determines if Link is overlapping the minecart.
* **`ResetTrackVars`**: Resets all minecart track-related variables.
* **`Minecart_HandleToss` / `Minecart_HandleTossedCart` / `Minecart_HandleLiftAndToss`**: Routines for handling the minecart being tossed or lifted by Link.
## Drawing (`Sprite_Minecart_DrawTop` and `Sprite_Minecart_DrawBottom`)
These routines draw the Minecart in two separate portions (top and bottom) to create the illusion of Link riding inside it. They utilize `JSL Sprite_PrepOamCoord` and `OAM_AllocateFromRegionB`/`C` for OAM allocation, and explicitly use `REP #$20` and `SEP #$20` for 16-bit coordinate calculations.
## Vanilla Overrides
* **`RoomTag_ShutterDoorRequiresCart`**: Modifies a room tag to require Link to be in a cart to open a shutter door, integrating the Minecart into dungeon puzzles.
* **`org $028260`**: Injects `JSL ResetTrackVars` to ensure minecart track variables are reset at specific points.
## Design Patterns
* **Complex Interactive Object**: The Minecart is a highly interactive object with intricate movement, collision, and state management, providing a unique traversal mechanic.
* **Track-Based Movement**: Movement is precisely governed by specific track tile types (stops, corners, intersections), requiring careful design of the minecart routes.
* **Player Input for Direction**: Link can influence the minecart's direction at intersections, adding an element of player control to the ride.
* **Persistent State**: Minecart position and direction are saved across room transitions, ensuring continuity and allowing for complex multi-room puzzles.
* **Multi-Part Drawing**: The minecart is drawn in two separate parts to allow Link to appear "inside" it, enhancing visual immersion.
* **Player State Manipulation**: The minecart directly controls Link's state (`!LinkInCart`, `LinkSomaria`, `LinkState`), seamlessly integrating the ride into Link's overall actions.
* **Dynamic Room Transitions**: Handles seamless transitions between rooms while Link is in the minecart, maintaining the flow of gameplay.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,76 @@
# Pedestal (Magic Pedestal Plaque)
## Overview
The `pedestal.asm` file defines the custom behavior for a "Magic Pedestal" sprite, which is an interactive object that responds to Link's actions. This implementation overrides a vanilla pedestal plaque sprite (`Sprite_B3_PedestalPlaque`) to trigger specific game events based on Link's inventory, input, and the current `AreaIndex`.
## Vanilla Overrides
* **`org $1EE05F`**: Injects `JSL CheckForBook` into the `Sprite_B3_PedestalPlaque` routine. This means the custom logic defined in `CheckForBook` will execute when the vanilla pedestal plaque sprite is processed.
## `CheckForBook`
This routine is the primary entry point for the custom pedestal logic. It checks several conditions to determine if Link is interacting with the pedestal in a specific way:
* **Link's Action**: Checks `$2F` (Link's current action/state).
* **Player Contact**: Checks for damage to player (`JSL Sprite_CheckDamageToPlayer`), which in this context likely means Link is in contact with the pedestal.
* **Item Held**: Checks if Link is holding a specific item (`$0202` compared to `$0F`, which likely corresponds to a book item).
* **Player Input**: Checks if Link is pressing the Y button (`BIT.b $F4`).
* **State Manipulation**: If Link is holding the book and pressing Y, it sets `$0300` to `0`, `$037A` to `$20`, and `$012E` to `0` (these are likely related to Link's animation or state changes).
* **Event Trigger**: Calls `JSR PedestalPlaque` to execute area-specific logic.
```asm
CheckForBook:
{
LDA.b $2F : BNE .exit
JSL Sprite_CheckDamageToPlayer : BCC .exit
LDA.w $0202 : CMP.b #$0F : BNE .not_holding_book
LDY.b #$01 : BIT.b $F4 : BVS .not_pressing_y
.not_holding_book
LDY.b #$00
.not_pressing_y
CPY.b #$01 : BNE .no_book_pose
STZ.w $0300
LDA.b #$20
STA.w $037A
STZ.w $012E
.no_book_pose
JSR PedestalPlaque
.exit
LDA.b AreaIndex : CMP.b #$30
RTL
}
```
## `PedestalPlaque`
This routine contains the area-specific logic for the pedestal, triggering different events based on the current `AreaIndex`:
* **Zora Temple (`AreaIndex = $1E`)**: Checks a flag (`$7EF29E` bit `$20`) and `SongFlag` (`$03`). If specific conditions are met (e.g., a certain event has not occurred and a particular song has been played), it sets `$04C6` to `$01` (likely a flag to open a gate or trigger an event) and clears `SongFlag`.
* **Goron Desert (`AreaIndex = $36`)**: No specific logic defined in this file.
* **Fortress Secrets (`AreaIndex = $5E`)**: No specific logic defined in this file.
```asm
PedestalPlaque:
{
LDA.b AreaIndex : CMP.b #$1E : BEQ .zora_temple
CMP.b #$36 : BEQ .goron_desert
CMP.b #$5E : BEQ .fortress_secrets
JMP .return
.zora_temple
LDA.l $7EF29E : AND.b #$20 : BNE .return
LDA.b SongFlag : CMP.b #$03 : BNE .return
LDA.b #$01 : STA $04C6
STZ.b SongFlag
JMP .return
.goron_desert
.fortress_secrets
.return
RTS
}
```
## Design Patterns
* **Vanilla Override**: This file directly modifies the vanilla pedestal plaque sprite to implement custom interactive behavior, demonstrating how to integrate new puzzle mechanics into existing game elements.
* **Context-Sensitive Interaction**: The pedestal responds specifically when Link is holding a particular item (a book) and pressing a button, creating a unique and logical interaction for puzzle solving.
* **Quest Progression Integration**: The pedestal triggers events based on the `AreaIndex` and various game state flags (e.g., `SongFlag`, `$7EF29E`), indicating its role in advancing specific quests and unlocking new areas.
* **Game State Manipulation**: Directly modifies WRAM addresses (`$04C6`, `SongFlag`) to trigger game events, such as opening gates or clearing flags, which are crucial for puzzle resolution and progression.

View File

@@ -0,0 +1,281 @@
# Portal Sprite
## Overview
The Portal sprite (`!SPRID = Sprite_Portal`) implements a sophisticated two-way warping system within the game. It allows Link to instantly travel between designated Blue and Orange portals, which can be placed in both dungeons and the overworld. This sprite features complex logic for portal activation, collision detection with Link, and seamless management of Link's state during warps.
## Sprite Properties
* **`!SPRID`**: `Sprite_Portal` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `01`
* **`!Harmless`**: `00`
* **`!HVelocity`**: `00`
* **`!Health`**: `00`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_Portal_Long`)
This routine handles the Portal's drawing and dispatches to its main logic if the sprite is active.
```asm
Sprite_Portal_Long:
{
PHB : PHK : PLB
JSR Sprite_Portal_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_Portal_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_Portal_Prep`)
This routine initializes the Portal upon spawning. It sets `SprDefl, X` to `0` (ensuring persistence outside the camera view), modifies `SprHitbox, X` properties, sets `SprTileDie, X` to `0`, and makes the portal bulletproof (`SprBulletproof, X` to `$FF`).
```asm
Sprite_Portal_Prep:
{
PHB : PHK : PLB
; Persist outside of camera
LDA #$00 : STA.w SprDefl, X
LDA.w SprHitbox, X : AND.b #$C0 : STA.w SprHitbox, X
STZ.w SprTileDie, X
LDA.b #$FF : STA.w SprBulletproof, X
PLB
RTL
}
```
## Portal Data Memory Locations
* **`BluePortal_X`, `BluePortal_Y`, `OrangePortal_X`, `OrangePortal_Y`**: WRAM addresses storing the X and Y coordinates of the Blue and Orange portals, respectively.
* **`BlueActive`, `OrangeActive`**: Flags indicating whether the Blue and Orange portals are currently active.
* **`OrangeSpriteIndex`, `BlueSpriteIndex`**: Store the sprite indices of the Orange and Blue portals.
## Main Logic & State Machine (`Sprite_Portal_Main`)
This routine manages the various states and behaviors of the portals, including their creation, activation, and warping functionality.
* **`StateHandler`**: Calls `CheckForDismissPortal` and `RejectOnTileCollision`. It then checks `$7E0FA6` (likely a flag indicating which portal is being spawned). If `$7E0FA6` is `0`, it sets up an Orange Portal (stores coordinates, sets `SprSubtype, X` to `01`, and transitions to `OrangePortal`). Otherwise, it sets up a Blue Portal (stores coordinates, sets `SprSubtype, X` to `02`, and transitions to `BluePortal`).
* **`BluePortal` / `OrangePortal`**: Plays an animation. It checks if Link has been warped (`$11` compared to `$2A`). It then checks for overlap with Link's hitbox (`CheckIfHitBoxesOverlap`). If Link overlaps, it determines if Link is in a dungeon or overworld (`$1B`) and transitions to the appropriate warp state (`BluePortal_WarpDungeon`, `OrangePortal_WarpDungeon`, `BluePortal_WarpOverworld`, `OrangePortal_WarpOverworld`).
* **`BluePortal_WarpDungeon` / `OrangePortal_WarpDungeon`**: Warps Link's coordinates (`$20`, `$22`), sets camera scroll boundaries, stores the other portal's coordinates, sets its `SprTimerD, X`, sets `$11` to `$14`, and returns to the respective portal state.
* **`BluePortal_WarpOverworld` / `OrangePortal_WarpOverworld`**: Warps Link's coordinates (`$20`, `$22`), sets camera scroll boundaries, applies Link's movement to the camera (`JSL ApplyLinksMovementToCamera`), stores the other portal's coordinates, sets its `SprTimerD, X`, sets `$5D` to `$01`, and returns to the respective portal state.
```asm
Sprite_Portal_Main:
{
LDA.w SprAction, X
JSL JumpTableLocal
dw StateHandler
dw BluePortal
dw OrangePortal
dw BluePortal_WarpDungeon
dw OrangePortal_WarpDungeon
dw BluePortal_WarpOverworld
dw OrangePortal_WarpOverworld
StateHandler:
{
JSR CheckForDismissPortal
JSR RejectOnTileCollision
LDA $7E0FA6 : BNE .BluePortal
LDA #$01 : STA $0307
TXA : STA.w OrangeSpriteIndex
LDA.w SprY, X : STA.w OrangePortal_X
LDA.w SprX, X : STA.w OrangePortal_Y
LDA.b #$01 : STA.w SprSubtype, X
%GotoAction(2)
RTS
.BluePortal
LDA #$02 : STA $0307
TXA : STA.w BlueSpriteIndex
LDA.w SprY, X : STA.w BluePortal_X
LDA.w SprX, X : STA.w BluePortal_Y
LDA.b #$02 : STA.w SprSubtype, X
%GotoAction(1)
RTS
}
BluePortal:
{
%StartOnFrame(0)
%PlayAnimation(0,1,8)
LDA $11 : CMP.b #$2A : BNE .not_warped_yet
STZ $11
.not_warped_yet
CLC
LDA.w SprTimerD, X : BNE .NoOverlap
JSL Link_SetupHitBox
JSL $0683EA ; Sprite_SetupHitbox_long
JSL CheckIfHitBoxesOverlap : BCC .NoOverlap
CLC
LDA $1B : BEQ .outdoors
%GotoAction(3) ; BluePortal_WarpDungeon
.NoOverlap
RTS
.outdoors
%GotoAction(5) ; BluePortal_WarpOverworld
RTS
}
OrangePortal:
{
%StartOnFrame(2)
%PlayAnimation(2,3,8)
LDA $11 : CMP.b #$2A : BNE .not_warped_yet
STZ $11
.not_warped_yet
CLC
LDA.w SprTimerD, X : BNE .NoOverlap
JSL Link_SetupHitBox
JSL $0683EA ; Sprite_SetupHitbox_long
JSL CheckIfHitBoxesOverlap : BCC .NoOverlap
CLC
; JSL $01FF28 ; Player_CacheStatePriorToHandler
LDA $1B : BEQ .outdoors
%GotoAction(4) ; OrangePortal_WarpDungeon
.NoOverlap
RTS
.outdoors
%GotoAction(6) ; OrangePortal_WarpOverworld
RTS
}
BluePortal_WarpDungeon:
{
LDA $7EC184 : STA $20
LDA $7EC186 : STA $22
LDA $7EC188 : STA $0600
LDA $7EC18A : STA $0604
LDA $7EC18C : STA $0608
LDA $7EC18E : STA $060C
PHX
LDA.w OrangeSpriteIndex : TAX
LDA #$40 : STA.w SprTimerD, X
LDA.w SprY, X : STA $7EC184
STA.w BluePortal_Y
LDA.w SprX, X : STA $7EC186
STA.w BluePortal_X
PLX
LDA #$14 : STA $11
%GotoAction(1) ; Return to BluePortal
RTS
}
OrangePortal_WarpDungeon:
{
LDA $7EC184 : STA $20
LDA $7EC186 : STA $22
; Camera Scroll Boundaries
LDA $7EC188 : STA $0600 ; Small Room North
LDA $7EC18A : STA $0604 ; Small Room South
LDA $7EC18C : STA $0608 ; Small Room West
LDA $7EC18E : STA $060C ; Small Room South
PHX
LDA.w BlueSpriteIndex : TAX
LDA #$40 : STA.w SprTimerD, X
LDA.w SprY, X : STA $7EC184
STA.w OrangePortal_Y
LDA.w SprX, X : STA $7EC186
STA.w OrangePortal_X
PLX
LDA #$14 : STA $11
%GotoAction(2) ; Return to OrangePortal
RTS
}
BluePortal_WarpOverworld:
{
LDA.w OrangePortal_X : STA $20
LDA.w OrangePortal_Y : STA $22
LDA $7EC190 : STA $0610
LDA $7EC192 : STA $0612
LDA $7EC194 : STA $0614
LDA $7EC196 : STA $0616
JSL ApplyLinksMovementToCamera
PHX ; Infinite loop prevention protocol
LDA.w OrangeSpriteIndex : TAX
LDA #$40 : STA.w SprTimerD, X
PLX
LDA #$01 : STA $5D
;LDA #$2A : STA $11
%GotoAction(1) ; Return to BluePortal
RTS
}
OrangePortal_WarpOverworld:
{
LDA.w BluePortal_X : STA $20
LDA.w BluePortal_Y : STA $22
LDA $7EC190 : STA $0610
LDA $7EC192 : STA $0612
LDA $7EC194 : STA $0614
LDA $7EC196 : STA $0616
JSL ApplyLinksMovementToCamera
PHX
LDA.w BlueSpriteIndex : TAX
LDA #$40 : STA.w SprTimerD, X
PLX
LDA #$01 : STA $5D
;LDA #$2A : STA $11
%GotoAction(2) ; Return to BluePortal
RTS
}
}
```
## Helper Routines
* **`CheckForDismissPortal`**: Checks a ticker (`$06FE`). If it exceeds `02`, it despawns the active portals (Blue and Orange) and decrements the ticker. Otherwise, it increments the ticker. This ticker needs to be reset during room and map transitions.
* **`RejectOnTileCollision`**: Checks for tile collision. If a portal is placed on an invalid tile (tile attribute `0` or `48`), it despawns the portal, plays an error sound (`SFX2.3C`), and decrements the ticker (`$06FE`).
## Drawing (`Sprite_Portal_Draw`)
This routine handles OAM allocation and animation for the Portal. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
## Design Patterns
* **Two-Way Warping System**: Implements a complex two-way portal system that allows Link to instantly travel between two designated points, enhancing exploration and puzzle design.
* **Context-Sensitive Warping**: Portals can intelligently warp Link between dungeons and the overworld, adapting to the current game context and providing seamless transitions.
* **Persistent Portal Locations**: Portal coordinates are stored in WRAM, allowing them to be placed and remembered across game sessions, enabling dynamic puzzle setups.
* **Link State Management**: Modifies Link's coordinates, camera boundaries, and game mode during warps, ensuring a smooth and consistent player experience during transitions.
* **Collision Detection**: Utilizes `CheckIfHitBoxesOverlap` to accurately detect when Link enters a portal, triggering the warp sequence.
* **Error Handling**: Includes logic to dismiss portals if they are placed on invalid tiles, preventing game-breaking scenarios and providing feedback to the player.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

View File

@@ -0,0 +1,232 @@
# Switch Track
## Overview
The Switch Track sprite (`!SPRID = Sprite_SwitchTrack`) is an interactive object designed to function as a rotating segment of a minecart track. Its visual appearance and implied path change dynamically based on its `SprAction` (which represents its mode of rotation) and the on/off state of a corresponding switch, stored in `SwitchRam`.
## Sprite Properties
* **`!SPRID`**: `Sprite_SwitchTrack` (Custom symbol, likely a remapped vanilla ID)
* **`!NbrTiles`**: `02`
* **`!Harmless`**: `00`
* **`!HVelocity`**: `00`
* **`!Health`**: `01`
* **`!Damage`**: `00`
* **`!DeathAnimation`**: `00`
* **`!ImperviousAll`**: `00`
* **`!SmallShadow`**: `00`
* **`!Shadow`**: `00`
* **`!Palette`**: `00`
* **`!Hitbox`**: `00`
* **`!Persist`**: `01` (Continues to live off-screen)
* **`!Statis`**: `00`
* **`!CollisionLayer`**: `00`
* **`!CanFall`**: `00`
* **`!DeflectArrow`**: `00`
* **`!WaterSprite`**: `00`
* **`!Blockable`**: `00`
* **`!Prize`**: `00`
* **`!Sound`**: `00`
* **`!Interaction`**: `00`
* **`!Statue`**: `00`
* **`!DeflectProjectiles`**: `00`
* **`!ImperviousArrow`**: `00`
* **`!ImpervSwordHammer`**: `00`
* **`!Boss`**: `00`
## Main Structure (`Sprite_RotatingTrack_Long`)
This routine handles the Switch Track's drawing and dispatches to its main logic if the sprite is active.
```asm
Sprite_RotatingTrack_Long:
{
PHB : PHK : PLB
JSR Sprite_RotatingTrack_Draw
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_RotatingTrack_Main
.SpriteIsNotActive
PLB
RTL
}
```
## Initialization (`Sprite_RotatingTrack_Prep`)
This routine initializes the Switch Track upon spawning. It sets `SprDefl, X` to `$80`. It then calculates the tile attributes of the tile directly above the switch track and sets `SprAction, X` based on the `SPRTILE` value (normalized by subtracting `$D0`). This `SprAction, X` likely determines the initial mode or orientation of the track.
```asm
Sprite_RotatingTrack_Prep:
{
PHB : PHK : PLB
LDA.b #$80 : STA.w SprDefl, X
; Setup Minecart position to look for tile IDs
; We use AND #$F8 to clamp to a 8x8 grid.
; Subtract 8 from the Y position to get the tile right above instead.
LDA.w SprY, X : AND #$F8 : SEC : SBC.b #$08 : STA.b $00
LDA.w SprYH, X : STA.b $01
LDA.w SprX, X : AND #$F8 : STA.b $02
LDA.w SprXH, X : STA.b $03
; Fetch tile attributes based on current coordinates
LDA.b #$00 : JSL Sprite_GetTileAttr
LDA.w SPRTILE : SEC : SBC.b #$D0 : STA.w SprAction, X
PLB
RTL
}
```
## Constants
* **`SwitchRam = $0230`**: A WRAM address that stores the state (on/off) of each individual switch, indexed by its `SprSubtype`. This allows for multiple independent switch tracks.
## Main Logic & State Machine (`Sprite_RotatingTrack_Main`)
This routine manages the visual state of the Switch Track based on its `SprAction` (mode of rotation) and the corresponding switch state in `SwitchRam`.
* **Modes**: The `SprAction, X` determines the mode of rotation, with four defined modes:
* `0` = TopLeft -> TopRight
* `1` = BottomLeft -> TopLeft
* `2` = TopRight -> BottomRight
* `3` = BottomRight -> BottomLeft
* **State-Based Animation**: For each mode, the `SprFrame, X` (animation frame) is set based on the on/off state of the switch (`SwitchRam, Y`). This visually changes the track's orientation.
```asm
Sprite_RotatingTrack_Main:
{
; Get the subtype of the track so that we can get its on/off state.
LDA.w SprSubtype, X : TAY
LDA.w SprAction, X
JSL UseImplicitRegIndexedLocalJumpTable
dw TopLeftToTopRight
dw BottomLeftToTopLeft
dw TopRightToBottomRight
dw BottomRightToBottomLeft
; 00 = TopLeft -> TopRight
TopLeftToTopRight:
{
LDA.w SwitchRam, Y : BNE .part2
LDA.b #$00 : STA.w SprFrame, X
RTS
.part2
LDA.b #$01 : STA.w SprFrame, X
RTS
}
; 01 = BottomLeft -> TopLeft
BottomLeftToTopLeft:
{
LDA.w SwitchRam, Y : BNE .part2_c
LDA.b #$03 : STA.w SprFrame, X
RTS
.part2_c
LDA.b #$00 : STA.w SprFrame, X
RTS
}
; 02 = TopRight -> BottomRight
TopRightToBottomRight:
{
LDA.w SwitchRam, Y : BNE .part2_a
LDA.b #$01 : STA.w SprFrame, X
RTS
.part2_a
LDA.b #$02 : STA.w SprFrame, X
RTS
}
; 03 = BottomRight -> BottomLeft
BottomRightToBottomLeft:
{
LDA.w SwitchRam, Y : BEQ .part2_b
LDA.b #$03 : STA.w SprFrame, X
RTS
.part2_b
LDA.b #$02 : STA.w SprFrame, X
RTS
}
}
```
## Drawing (`Sprite_RotatingTrack_Draw`)
This routine handles OAM allocation and animation for the Switch Track. It explicitly uses `REP #$20` and `SEP #$20` for 16-bit coordinate calculations, ensuring accurate sprite rendering.
```asm
Sprite_RotatingTrack_Draw:
{
JSL Sprite_PrepOamCoord
LDA.b #$04 : JSL OAM_AllocateFromRegionB
LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index
db $00, $01, $02, $03
.nbr_of_tiles
db 0, 0, 0, 0
.chr
db $44
db $44
db $44
db $44
.properties
db $3D
db $7D
db $FD
db $BD
}
```
## Design Patterns
* **Interactive Puzzle Element**: The Switch Track is a key puzzle element that changes its orientation based on an external switch (likely the `mineswitch` sprite), directly influencing the path of minecarts.
* **State-Based Animation**: The track's animation frame (`SprFrame, X`) is directly controlled by the on/off state of a corresponding switch in `SwitchRam`, providing clear visual feedback to the player about its current configuration.
* **Subtype-Driven State**: The `SprSubtype` is used to index into `SwitchRam`, allowing each individual Switch Track to maintain its own independent state. This enables complex puzzle designs with multiple, distinct switch tracks.
* **16-bit OAM Calculations**: Demonstrates explicit use of `REP #$20` and `SEP #$20` for precise 16-bit OAM coordinate calculations, crucial for accurate sprite rendering.

28
Docs/Sprites/Overlord.md Normal file
View File

@@ -0,0 +1,28 @@
# Overlord Sprite Analysis
This document provides an analysis of the "Overlord" sprite system, which is a special type of sprite that acts as a controller for spawning other sprites or triggering events within a room. The main logic is found in `Sprites/overlord.asm`.
## Overview
Overlord sprites are invisible, non-interactive sprites that are placed in a room via a level editor. Their purpose is to run logic in the background, often tied to room-specific events or conditions. They are distinct from standard sprites and are processed by a separate loop.
In this project, the primary use of the Overlord system is to dynamically spawn soldiers in Hyrule Castle after the player acquires the Master Sword.
## `overlord.asm` Analysis
- **File:** `Sprites/overlord.asm`
- **Summary:** This file contains the logic for `Overlord04`, which is hooked into the game at `$09B7AE`. This specific overlord is responsible for continuously spawning soldiers in Hyrule Castle to create a sense of alarm and danger.
### Key Logic
- **`Overlord_KalyxoCastleGuards`:** This is the main entry point for the overlord's logic. It is a simple routine that calls `SummonGuards`.
- **`SummonGuards`:**
- **Trigger Condition:** This routine first checks if Link has the Master Sword (`LDA.l Sword : CMP.b #$02`). It will only proceed if the sword level is 2 or greater.
- **Spawning Logic:** If the condition is met, it calls `Overlord_SpawnSoldierPath`.
- **`Overlord_SpawnSoldierPath`:**
- **Spawn Timer:** This routine uses `OverlordTimerB` as a countdown timer to manage the rate of spawning. It will not spawn a new soldier until the timer reaches zero.
- **Sprite Limit:** It checks the number of active soldiers (`Sprite Type $41`) on screen. If there are already 5 or more, it will not spawn a new one.
- **Spawning:** If the conditions are met, it calls `Sprite_SpawnDynamically_slot_limited` to create a new Blue Soldier (`$41`).
- **Positioning:** The new soldier's position and initial direction are determined by data tables within the routine (`soldier_position_x`, `soldier_position_y`, `soldier_direction`), allowing for multiple spawn points.

Some files were not shown because too many files have changed in this diff Show More