- 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.
73 lines
4.5 KiB
Markdown
73 lines
4.5 KiB
Markdown
# Minecart System (`Sprites/Objects/minecart.asm`)
|
|
|
|
## Overview
|
|
|
|
The minecart is a highly complex and stateful sprite. It functions as a vehicle for the player, following predefined tracks, handling intersections, and persisting its location across rooms. This system is one of the most intricate custom sprites in the project.
|
|
|
|
## Key Functionality
|
|
|
|
- **State Machine:** The sprite operates on a state machine (`Minecart_WaitHoriz`, `Minecart_WaitVert`, `Minecart_Move...`) to handle waiting, player interaction, and movement.
|
|
- **Track System:** A custom system using a large block of SRAM (starting at `!MinecartTrackRoom = $0728`) allows up to 32 unique minecart "tracks" to exist in the world. The sprite saves its position and room index to this table, allowing it to reappear where the player left it.
|
|
- **Custom Collision:** The minecart does not use standard sprite collision. Instead, it reads the tile ID at its center to determine its behavior, following a complex set of rules for straight tracks, corners, intersections, and stops.
|
|
- **Player Interaction:** The player can start, stop, and change the direction of the cart at specific junctions.
|
|
|
|
## Analysis & Areas for Improvement
|
|
|
|
This is a very impressive piece of engineering for an SNES game. The code is dense and showcases advanced techniques. The main areas for improvement are in readability, data organization, and reducing code duplication.
|
|
|
|
### 1. Use a `struct` for the Track System
|
|
|
|
- **Observation:** The minecart tracking system is managed by a series of parallel arrays in SRAM (`!MinecartTrackRoom`, `!MinecartTrackX`, `!MinecartTrackY`). This is functional but can be confusing to read and maintain.
|
|
- **Suggestion:** This is a perfect use case for asar's `struct` directive. Define a structure for a single track and then create a table of those structures.
|
|
|
|
*Example:*
|
|
```asm
|
|
struct MinecartTrack
|
|
Room dw
|
|
XPos dw
|
|
YPos dw
|
|
endstruct
|
|
|
|
; In your RAM definitions
|
|
MinecartTracks table[32] of MinecartTrack
|
|
```
|
|
- **Benefit:** This makes the data structure explicit and far more readable. Accessing data becomes `MinecartTracks.Room[track_index]` instead of calculating offsets into a generic block of RAM.
|
|
|
|
### 2. Refactor Movement and Direction-Setting Code
|
|
|
|
- **Observation:**
|
|
- The routines `Minecart_MoveNorth`, `Minecart_MoveEast`, `Minecart_MoveSouth`, and `Minecart_MoveWest` contain very similar logic, differing only in the speed value and axis.
|
|
- The direction-setting routines (`Minecart_SetDirectionNorth`, etc.) also contain significant duplication.
|
|
- **Suggestion:**
|
|
- Create a single `Minecart_Move` subroutine that takes a direction as an argument. It could use a lookup table to fetch the correct speed and axis.
|
|
- Create a single `Minecart_SetDirection` subroutine that takes a direction argument and sets the `SprMiscB`, `!MinecartDirection`, and animation state from lookup tables.
|
|
- **Benefit:** Massively reduces code duplication, making the logic easier to debug and modify. A change to movement logic would only need to be made in one place.
|
|
|
|
### 3. Use `subroutine` for All Code Blocks
|
|
|
|
- **Observation:** The file uses a mix of labels and macros (`%GotoAction`) for its state machine. The main logic is a large jump table.
|
|
- **Suggestion:** Convert all logical blocks (`Minecart_WaitHoriz`, `HandleTileDirections`, `CheckForCornerTiles`, etc.) into proper `subroutine`s.
|
|
- **Benefit:** Enforces local scoping for labels, improves readability, and makes the code's structure much clearer.
|
|
|
|
### 4. Replace Magic Numbers with Constants
|
|
|
|
- **Observation:** The code is full of hardcoded values for directions, speeds, tile IDs, and sprite states.
|
|
- **Suggestion:** Define constants for all of these.
|
|
|
|
*Example:*
|
|
```asm
|
|
!CART_SPEED = 20
|
|
!TILE_TRACK_CORNER_TL = $B2
|
|
|
|
!DIR_NORTH = 0
|
|
!DIR_EAST = 1
|
|
; etc.
|
|
```
|
|
- **Benefit:** This is crucial for a system this complex. It makes the code self-documenting and dramatically reduces the chance of introducing bugs from typos in numerical values.
|
|
|
|
### 5. Add High-Level Comments
|
|
|
|
- **Observation:** The code has some comments, but they mostly describe *what* a single line is doing.
|
|
- **Suggestion:** Add block comments at the top of major subroutines (especially `Sprite_Minecart_Prep` and `HandleTileDirections`) explaining the overall *purpose* and *logic* of the code block. Explain the caching/tracking system in detail.
|
|
- **Benefit:** This is essential for future maintainability, especially for a system this intricate. It will make it possible for you or others to understand the code after being away from it for a while.
|