summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRangi <remy.oukaour+rangi42@gmail.com>2020-12-04 21:36:40 -0500
committerRangi <remy.oukaour+rangi42@gmail.com>2020-12-04 21:36:40 -0500
commitfb50de2f3ea74250f1ad5d6c8ddbeab81b9f08dc (patch)
treeaee0d2802b371fae1e7c51cefc1668d1bc094594
parent5eb8622112507db43c07af94c303a3e4a7223df1 (diff)
Reduce the command queue system to just stone tables
-rw-r--r--Reduce-the-command-queue-system-to-just-stone-tables.md304
-rw-r--r--Tutorials.md2
2 files changed, 305 insertions, 1 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.
diff --git a/Tutorials.md b/Tutorials.md
index 3f9fd7d..7d8240b 100644
--- a/Tutorials.md
+++ b/Tutorials.md
@@ -97,6 +97,7 @@ Tutorials may use diff syntax to show edits:
- [Remove the 25% failure chance for AI status moves](Remove-the-25%25-failure-chance-for-AI-status-moves)
- [Remove the redundant move grammar table](Remove-the-redundant-move-grammar-table)
- [Remove the opening intro](Removing-the-intro)
+- [Reduce the command queue system to just stone tables](Reduce-the-command-queue-system-to-just-stone-tables)
## Features from different generations
@@ -171,7 +172,6 @@ Feel free to contribute one of these!
- Show quantity already in Pack in Marts
- Create an NPC or trainer which has a phone number with custom messages when called
- E-mail system (receive mail from NPCs by accessing PC)
-- Replace command queues with just stone tables
- Implement a low health warning song similar to the one in Black and White versions
- Let Pokémon use HM moves just by being compatible with them (from [Coral](https://hax.iimarckus.org/post/45725/))
- Nuzlocke mode (an in-game enforced [Nuzlocke Challenge](https://bulbapedia.bulbagarden.net/wiki/Nuzlocke_Challenge))