diff options
Diffstat (limited to 'Reduce-the-command-queue-system-to-just-stone-tables.md')
-rw-r--r-- | Reduce-the-command-queue-system-to-just-stone-tables.md | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/Reduce-the-command-queue-system-to-just-stone-tables.md b/Reduce-the-command-queue-system-to-just-stone-tables.md new file mode 100644 index 0000000..937344a --- /dev/null +++ b/Reduce-the-command-queue-system-to-just-stone-tables.md @@ -0,0 +1,304 @@ +One feature of the Gen 2 overworld engine is the "command queue". Event scripts may queue up to six entries with the `writecmdqueue` and `delcmdqueue` script commands. Then every time the player takes a step, the queued commands run depending on their type. In practice, the only usable command type is `CMDQUEUE_STONETABLE`, for pushing Strength boulders into holes. The other command types are dummied out or incomplete. + +This tutorial simplifies the system to replace the entire queue with a single pointer to a "stone table", which may be null or may point to a table defining how Strength boulders interact with holes. It saves ROM and RAM space, and simplifies the map callbacks that set up stone tables. + + +## Contents + +1. [Remove the command queue–related constants](#1-remove-the-command-queuerelated-constants) +2. [Replace `writecmdqueue` and `delcmdqueue` with `usestonetable` and `clearstonetable`](#2-replace-writecmdqueue-and-delcmdqueue-with-usestonetable-and-clearstonetable) +3. [Replace `MAPCALLBACK_CMDQUEUE` with `MAPCALLBACK_STONETABLE`](#3-replace-mapcallback_cmdqueue-with-mapcallback_stonetable) +4. [Update the map scripts that use stone tables](#4-update-the-map-scripts-that-use-stone-tables) +5. [Implement the simplified stone table system](#5-implement-the-simplified-stone-table-system) + + +## 1. Remove the command queue–related constants + +Edit [constants/script_constants.asm](../blob/master/constants/script_constants.asm): + +```diff +-; command queue members +-CMDQUEUE_TYPE EQU 0 +-CMDQUEUE_ADDR EQU 1 +-CMDQUEUE_02 EQU 2 +-CMDQUEUE_03 EQU 3 +-CMDQUEUE_04 EQU 4 +-CMDQUEUE_05 EQU 5 +-CMDQUEUE_ENTRY_SIZE EQU 6 +-CMDQUEUE_CAPACITY EQU 4 +- +-; HandleQueuedCommand.Jumptable indexes (see engine/overworld/events.asm) +- const_def +- const CMDQUEUE_NULL +- const CMDQUEUE_TYPE1 +- const CMDQUEUE_STONETABLE +- const CMDQUEUE_TYPE3 +- const CMDQUEUE_TYPE4 +-NUM_CMDQUEUE_TYPES EQU const_value +``` + + +## 2. Replace `writecmdqueue` and `delcmdqueue` with `usestonetable` and `clearstonetable` + +Edit [macros/scripts/events.asm](../blob/master/macros/scripts/events.asm): + +```diff +- const writecmdqueue_command ; $7d +-writecmdqueue: MACRO +- db writecmdqueue_command +- dw \1 ; queue_pointer +-ENDM ++ const usestonetable_command ; $7d ++usestonetable: MACRO ++ db usestonetable_command ++ dw \1 ; stonetable_pointer ++ENDM + +- const delcmdqueue_command ; $7e +-delcmdqueue: MACRO +- db delcmdqueue_command +- db \1 ; byte +-ENDM ++ const clearstonetable_command ; $7e ++clearstonetable: MACRO ++ db clearstonetable_command ++ENDM +``` + +(The `clearstonetable` command isn't really necessary, since maps are unlikely to need it and `usestonetable NULL` will do the same thing, but I'm including it for completeness.) + +Then edit [engine/overworld/scripting.asm](../blob/master/engine/overworld/scripting.asm): + +```diff +- dw Script_writecmdqueue ; 7d +- dw Script_delcmdqueue ; 7e ++ dw Script_usestonetable ; 7d ++ dw Script_clearstonetable ; 7e +``` + +```diff +-Script_writecmdqueue: ++Script_usestonetable: + call GetScriptByte +- ld e, a ++ ld [wStoneTableAddress], a + call GetScriptByte +- ld d, a ++ ld [wStoneTableAddress+1], a +- ld a, [wScriptBank] +- ld b, a +- farcall WriteCmdQueue ; no need to farcall + ret + +-Script_delcmdqueue: ++Script_clearstonetable: + xor a +- ld [wScriptVar], a ++ ld [wStoneTableAddress], a ++ ld [wStoneTableAddress+1], a +- call GetScriptByte +- ld b, a +- farcall DelCmdQueue ; no need to farcall +- ret c +- ld a, TRUE +- ld [wScriptVar], a + ret +``` + +And edit [wram.asm](../blob/master/wram.asm): + +```diff +-wCmdQueue:: ds CMDQUEUE_CAPACITY * CMDQUEUE_ENTRY_SIZE ++wStoneTableAddress:: dw + +- ds 40 ++ ds 62 +``` + +Now `usestonetable .StoneTable` will store the address `.StoneTable` in `wStoneTableAddress`, and `clearstonetable` will set `wStoneTableAddress` to `NULL`. The `wStoneTableAddress` pointer only needs two bytes, whereas `wCmdQueue` needed 24, so this saves 22 bytes of RAM. + + +## 3. Replace `MAPCALLBACK_CMDQUEUE` with `MAPCALLBACK_STONETABLE` + +Edit [constants/map_setup_constants.asm](../blob/master/constants/map_setup_constants.asm): + +```diff + ; callback types + const_def 1 + const MAPCALLBACK_TILES + const MAPCALLBACK_OBJECTS +- const MAPCALLBACK_CMDQUEUE ++ const MAPCALLBACK_STONETABLE + const MAPCALLBACK_SPRITES + const MAPCALLBACK_NEWMAP +``` + +Then edit [engine/overworld/warp_connection.asm](../blob/master/engine/overworld/warp_connection.asm): + +```diff + HandleContinueMap: +- farcall ClearCmdQueue ++ xor a ++ ld [wStoneTableAddress], a ++ ld [wStoneTableAddress+1], a +- ld a, MAPCALLBACK_CMDQUEUE ++ ld a, MAPCALLBACK_STONETABLE + call RunMapCallback + call GetMapTimeOfDay + ld [wMapTimeOfDay], a + ret +``` + + +## 4. Update the map scripts that use stone tables + +Edit [maps/BlackthornGym2F.asm](../blob/master/maps/BlackthornGym2F.asm): + +```diff + def_callbacks +- callback MAPCALLBACK_CMDQUEUE, .SetUpStoneTable ++ callback MAPCALLBACK_STONETABLE, .SetUpStoneTable + + .SetUpStoneTable: +- writecmdqueue .CommandQueue ++ usestonetable .StoneTable + endcallback + +-.CommandQueue: +- cmdqueue CMDQUEUE_STONETABLE, .StoneTable ; check if any stones are sitting on a warp +- + .StoneTable: + stonetable 5, BLACKTHORNGYM2F_BOULDER1, .Boulder1 + stonetable 3, BLACKTHORNGYM2F_BOULDER2, .Boulder2 + stonetable 4, BLACKTHORNGYM2F_BOULDER3, .Boulder3 + db -1 ; end +``` + +And edit [maps/IcePathB1F.asm](../blob/master/maps/IcePathB1F.asm): + +```diff + def_callbacks +- callback MAPCALLBACK_CMDQUEUE, .SetUpStoneTable ++ callback MAPCALLBACK_STONETABLE, .SetUpStoneTable + + .SetUpStoneTable: +- writecmdqueue .CommandQueue ++ usestonetable .StoneTable + endcallback + +-.CommandQueue: +- cmdqueue CMDQUEUE_STONETABLE, .StoneTable ; check if any stones are sitting on a warp +- + .StoneTable: + stonetable 3, ICEPATHB1F_BOULDER1, .Boulder1 + stonetable 4, ICEPATHB1F_BOULDER2, .Boulder2 + stonetable 5, ICEPATHB1F_BOULDER3, .Boulder3 + stonetable 6, ICEPATHB1F_BOULDER4, .Boulder4 + db -1 ; end +``` + +Both of these maps allow you to push boulders into holes with Strength. Now they use the new callback type and event commands. + +Previously, the `writecmdqueue` event command took a pointer to a command queue definition (`.CommandQueue`), and that command queue then pointed to its own data depending on its type (so the `CMDQUEUE_STONETABLE` had the `.StoneTable` pointer with `stonetable` data). Now, the `usestonetable` event command directly takes a `.StoneTable` pointer to `stonetable` data, without needing an intermediate `cmdqueue`. + + +## 5. Implement the simplified stone table system + +Edit [engine/overworld/events.asm](../blob/master/engine/overworld/events.asm): + +```diff + HandleMap: + call ResetOverworldDelay + call HandleMapTimeAndJoypad +- farcall HandleCmdQueue ; no need to farcall ++ call HandleStoneTable + call MapEvents +``` + +Then edit [engine/overworld/cmd_queue.asm](../blob/master/engine/overworld/cmd_queue.asm): + +```diff +-ClearCmdQueue:: +- ... +- +-HandleCmdQueue:: +- ... +- +-GetNthCmdQueueEntry: ; unreferenced +- ... +- +-WriteCmdQueue:: +- ... +- +-DelCmdQueue:: +- ... +- +-HandleQueuedCommand: +- ... +- +-CmdQueues_AnonJumptable: +- ... +- +-CmdQueues_IncAnonJumptableIndex: +- ... +- +-CmdQueues_DecAnonJumptableIndex: +- ... +- +-CmdQueue_Null: +- ... +- +-CmdQueue_Type1: +- ... +- +-CmdQueue_Type4: +- ... +- +-CmdQueue_Type3: +- ... +- +-CmdQueue_StoneTable: ++HandleStoneTable:: ++ ld hl, wStoneTableAddress ++ ld a, [hli] ++ ld b, [hl] ++ ld c, a ++ or b ++ ret z + + ld de, wPlayerStruct + ld a, NUM_OBJECT_STRUCTS + .loop + push af + + ... + + pop af + dec a + jr nz, .loop + ret + + .fall_down_hole + pop af + ret +``` + +Everything gets deleted except `CmdQueue_StoneTable`, which we rename to `HandleStoneTable` and add some code at the beginning to use `wStoneTableAddress` (or return if it's `NULL`). + +Finally, edit [home/stone_queue.asm](../blob/master/home/stone_queue.asm): + +```diff +.IsObjectInStoneTable: + inc e +- ld hl, CMDQUEUE_ADDR +- add hl, bc +- ld a, [hli] +- ld h, [hl] +- ld l, a ++ ld h, b ++ ld l, c +``` + +Since `HandleStoneTable` now stores the `wStoneTableAddress` value in `bc`, here we need to use that value instead of getting the relevant part of some command queue data. + +With these changes, the Blackthorn Gym and Ice Path puzzles with Strength boulders will work just like before, but the code and data are more efficient. |