summaryrefslogtreecommitdiff
path: root/macros/scripts
diff options
context:
space:
mode:
authordannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
committerdannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
commit5647ca687b92954dcf37a6ea6bfbc9a341c32de4 (patch)
treedde1937a1bfdb3a835f4155e1c2eb8f1aaf86f63 /macros/scripts
parent53fcd05aa24693093d8af1dc8ec4fedd3957decc (diff)
Sync with pokered
Diffstat (limited to 'macros/scripts')
-rwxr-xr-xmacros/scripts/audio.asm233
-rw-r--r--macros/scripts/events.asm532
-rw-r--r--macros/scripts/maps.asm225
-rwxr-xr-xmacros/scripts/text.asm213
4 files changed, 1203 insertions, 0 deletions
diff --git a/macros/scripts/audio.asm b/macros/scripts/audio.asm
new file mode 100755
index 00000000..b12a2adc
--- /dev/null
+++ b/macros/scripts/audio.asm
@@ -0,0 +1,233 @@
+audio_header: MACRO
+ db (_NARG - 2) << 6 | \2
+ dw \1_\2
+ IF _NARG > 2
+ db \3
+ dw \1_\3
+ ENDC
+ IF _NARG > 3
+ db \4
+ dw \1_\4
+ ENDC
+ IF _NARG > 4
+ db \5
+ dw \1_\5
+ ENDC
+ENDM
+
+ const_def $10
+
+; arguments: length [0, 7], pitch change [-7, 7]
+; length: length of time between pitch shifts
+; sometimes used with a value >7 in which case the MSB is ignored
+; pitch change: positive value means increase in pitch, negative value means decrease in pitch
+; small magnitude means quick change, large magnitude means slow change
+; in signed magnitude representation, so a value of 8 is the same as (negative) 0
+ const pitch_sweep_cmd ; $10
+pitch_sweep: MACRO
+ db pitch_sweep_cmd
+ IF \2 < 0
+ db (\1 << 4) | (%1000 | (\2 * -1))
+ ELSE
+ db (\1 << 4) | \2
+ ENDC
+ENDM
+
+ const_next $20
+
+ const sfx_note_cmd ; $20
+
+; arguments: length [0, 15], volume [0, 15], fade [-7, 7], frequency
+; fade: positive value means decrease in volume, negative value means increase in volume
+; small magnitude means quick change, large magnitude means slow change
+; in signed magnitude representation, so a value of 8 is the same as (negative) 0
+square_note_cmd EQU sfx_note_cmd ; $20
+square_note: MACRO
+ db square_note_cmd | \1
+ IF \3 < 0
+ db (\2 << 4) | (%1000 | (\3 * -1))
+ ELSE
+ db (\2 << 4) | \3
+ ENDC
+ dw \4
+ENDM
+
+; arguments: length [0, 15], volume [0, 15], fade [-7, 7], frequency
+; fade: positive value means decrease in volume, negative value means increase in volume
+; small magnitude means quick change, large magnitude means slow change
+; in signed magnitude representation, so a value of 8 is the same as (negative) 0
+noise_note_cmd EQU sfx_note_cmd ; $20
+noise_note: MACRO
+ db noise_note_cmd | \1
+ IF \3 < 0
+ db (\2 << 4) | (%1000 | (\3 * -1))
+ ELSE
+ db (\2 << 4) | \3
+ ENDC
+ db \4
+ENDM
+
+; arguments: pitch, length [1, 16]
+note: MACRO
+ db (\1 << 4) | (\2 - 1)
+ENDM
+
+ const_next $b0
+
+; arguments: instrument [1, 19], length [1, 16]
+ const drum_note_cmd ; $b0
+drum_note: MACRO
+ db drum_note_cmd | (\2 - 1)
+ db \1
+ENDM
+
+; arguments: instrument, length [1, 16]
+; like drum_note but one 1 byte instead of 2
+; can only be used with instruments 1-10, excluding 2
+; unused
+drum_note_short: MACRO
+ db (\1 << 4) | (\2 - 1)
+ENDM
+
+ const_next $c0
+
+; arguments: length [1, 16]
+ const rest_cmd ; $c0
+rest: MACRO
+ db rest_cmd | (\1 - 1)
+ENDM
+
+ const_next $d0
+
+; arguments: speed [0, 15], volume [0, 15], fade [-7, 7]
+; fade: positive value means decrease in volume, negative value means increase in volume
+; small magnitude means quick change, large magnitude means slow change
+; in signed magnitude representation, so a value of 8 is the same as (negative) 0
+ const note_type_cmd ; $d0
+note_type: MACRO
+ db note_type_cmd | \1
+ IF \3 < 0
+ db (\2 << 4) | (%1000 | (\3 * -1))
+ ELSE
+ db (\2 << 4) | \3
+ ENDC
+ENDM
+
+; arguments: speed [0, 15]
+drum_speed_cmd EQU note_type_cmd ; $d0
+drum_speed: MACRO
+ db drum_speed_cmd | \1
+ENDM
+
+ const_next $e0
+
+; arguments: octave [1, 8]
+ const octave_cmd ; $e0
+octave: MACRO
+ db octave_cmd | (8 - \1)
+ENDM
+
+ const_next $e8
+
+; when enabled, effective frequency used is incremented by 1
+ const toggle_perfect_pitch_cmd ; $e8
+toggle_perfect_pitch: MACRO
+ db toggle_perfect_pitch_cmd
+ENDM
+
+ const_skip ; $e9
+
+; arguments: delay [0, 255], depth [0, 15], rate [0, 15]
+; delay: time delay until vibrato effect begins
+; depth: amplitude of vibrato wave
+; rate: frequency of vibrato wave
+ const vibrato_cmd ; $ea
+vibrato: MACRO
+ db vibrato_cmd
+ db \1
+ db (\2 << 4) | \3
+ENDM
+
+; arguments: length [1, 256], octave [1, 8], pitch
+ const pitch_slide_cmd ; $eb
+pitch_slide: MACRO
+ db pitch_slide_cmd
+ db \1 - 1
+ db ((8 - \2) << 4) | \3
+ENDM
+
+; arguments: duty cycle [0, 3] (12.5%, 25%, 50%, 75%)
+ const duty_cycle_cmd ; $ec
+duty_cycle: MACRO
+ db duty_cycle_cmd
+ db \1
+ENDM
+
+; arguments: tempo [0, $ffff]
+; used to calculate note delay counters
+; so a smaller value means music plays faster
+; ideally should be set to $100 or less to guarantee no overflow
+; if larger than $100, large note speed or note length values might cause overflow
+; stored in big endian
+ const tempo_cmd ; $ed
+tempo: MACRO
+ db tempo_cmd
+ db HIGH(\1), LOW(\1)
+ENDM
+
+; arguments: left output enable mask, right output enable mask
+ const stereo_panning_cmd ; $ee
+stereo_panning: MACRO
+ db stereo_panning_cmd
+ db (\1 << 4) | \2
+ENDM
+
+ const unknownmusic0xef_cmd ; $ef
+unknownmusic0xef: MACRO
+ db unknownmusic0xef_cmd
+ db \1
+ENDM
+
+; arguments: left master volume [0, 7], right master volume [0, 7]
+ const volume_cmd ; $f0
+volume: MACRO
+ db volume_cmd
+ db (\1 << 4) | \2
+ENDM
+
+ const_next $f8
+
+; when enabled, the sfx data is interpreted as music data
+ const execute_music_cmd ; $f8
+execute_music: MACRO
+ db execute_music_cmd
+ENDM
+
+ const_next $fc
+
+; arguments: duty cycle 1, duty cycle 2, duty cycle 3, duty cycle 4
+ const duty_cycle_pattern_cmd ; $fc
+duty_cycle_pattern: MACRO
+ db duty_cycle_pattern_cmd
+ db \1 << 6 | \2 << 4 | \3 << 2 | \4
+ENDM
+
+; arguments: address
+ const sound_call_cmd ; $fd
+sound_call: MACRO
+ db sound_call_cmd
+ dw \1
+ENDM
+
+; arguments: count, address
+ const sound_loop_cmd ; $fe
+sound_loop: MACRO
+ db sound_loop_cmd
+ db \1
+ dw \2
+ENDM
+
+ const sound_ret_cmd ; $ff
+sound_ret: MACRO
+ db sound_ret_cmd
+ENDM
diff --git a/macros/scripts/events.asm b/macros/scripts/events.asm
new file mode 100644
index 00000000..266ffdd1
--- /dev/null
+++ b/macros/scripts/events.asm
@@ -0,0 +1,532 @@
+;\1 = event index
+;\2 = return result in carry instead of zero flag
+CheckEvent: MACRO
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + event_byte]
+
+ IF _NARG > 1
+ IF ((\1) % 8) == 7
+ add a
+ ELSE
+ REPT ((\1) % 8) + 1
+ rrca
+ ENDR
+ ENDC
+ ELSE
+ bit (\1) % 8, a
+ ENDC
+ENDM
+
+
+;\1 = event index
+CheckEventReuseA: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + event_byte]
+ ENDC
+
+ bit (\1) % 8, a
+ENDM
+
+
+;\1 = event index
+;\2 = event index of the last event used before the branch
+CheckEventAfterBranchReuseA: MACRO
+event_byte = ((\2) / 8)
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + event_byte]
+ ENDC
+
+ bit (\1) % 8, a
+ENDM
+
+
+;\1 = reg
+;\2 = event index
+;\3 = event index this event is relative to (optional, this is needed when there is a fixed flag address)
+EventFlagBit: MACRO
+ IF _NARG > 2
+ ld \1, ((\3) % 8) + ((\2) - (\3))
+ ELSE
+ ld \1, (\2) % 8
+ ENDC
+ENDM
+
+
+;\1 = reg
+;\2 = event index
+EventFlagAddress: MACRO
+event_byte = ((\2) / 8)
+ ld \1, wEventFlags + event_byte
+ENDM
+
+
+EventFlagAddressa: MACRO
+event_byte = ((\1) / 8)
+ ld [wEventFlags + event_byte], a
+ ENDM
+
+aEventFlagAddress: MACRO
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + event_byte]
+ ENDM
+
+;\1 = event index
+CheckEventHL: MACRO
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ bit (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+CheckEventReuseHL: MACRO
+IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ bit (\1) % 8, [hl]
+ENDM
+
+
+; dangerous, only use when HL is guaranteed to be the desired value
+;\1 = event index
+CheckEventForceReuseHL: MACRO
+event_byte = ((\1) / 8)
+ bit (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+;\2 = event index of the last event used before the branch
+CheckEventAfterBranchReuseHL: MACRO
+event_byte = ((\2) / 8)
+IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ bit (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+CheckAndSetEvent: MACRO
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ bit (\1) % 8, [hl]
+ set (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+CheckAndResetEvent: MACRO
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ bit (\1) % 8, [hl]
+ res (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+CheckAndSetEventA: MACRO
+ ld a, [wEventFlags + ((\1) / 8)]
+ bit (\1) % 8, a
+ set (\1) % 8, a
+ ld [wEventFlags + ((\1) / 8)], a
+ENDM
+
+
+;\1 = event index
+CheckAndResetEventA: MACRO
+ ld a, [wEventFlags + ((\1) / 8)]
+ bit (\1) % 8, a
+ res (\1) % 8, a
+ ld [wEventFlags + ((\1) / 8)], a
+ENDM
+
+
+CheckAndSetEventReuseHL: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ bit (\1) % 8, [hl]
+ set (\1) % 8, [hl]
+ ENDM
+
+CheckAndResetEventReuseHL: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ bit (\1) % 8, [hl]
+ res (\1) % 8, [hl]
+ ENDM
+
+
+;\1 = event index
+SetEvent: MACRO
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ set (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+SetEventReuseHL: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ set (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+;\2 = event index of the last event used before the branch
+SetEventAfterBranchReuseHL: MACRO
+event_byte = ((\2) / 8)
+IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ set (\1) % 8, [hl]
+ENDM
+
+
+; dangerous, only use when HL is guaranteed to be the desired value
+;\1 = event index
+SetEventForceReuseHL: MACRO
+event_byte = ((\1) / 8)
+ set (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+;\2 = event index
+;\3, \4, ... = additional (optional) event indices
+SetEvents: MACRO
+ SetEvent \1
+ REPT _NARG - 1
+ SetEventReuseHL \2
+ SHIFT
+ ENDR
+ENDM
+
+
+;\1 = event index
+ResetEvent: MACRO
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ res (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+ResetEventReuseHL: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ res (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+;\2 = event index of the last event used before the branch
+ResetEventAfterBranchReuseHL: MACRO
+event_byte = ((\2) / 8)
+IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld hl, wEventFlags + event_byte
+ ENDC
+
+ res (\1) % 8, [hl]
+ENDM
+
+
+; dangerous, only use when HL is guaranteed to be the desired value
+;\1 = event index
+ResetEventForceReuseHL: MACRO
+event_byte = ((\1) / 8)
+ res (\1) % 8, [hl]
+ENDM
+
+
+;\1 = event index
+;\2 = event index
+;\3 = event index (optional)
+ResetEvents: MACRO
+ ResetEvent \1
+ REPT _NARG - 1
+ ResetEventReuseHL \2
+ SHIFT
+ ENDR
+ENDM
+
+
+;\1 = event index
+;\2 = number of bytes away from the base address (optional, for matching the ROM)
+dbEventFlagBit: MACRO
+ IF _NARG > 1
+ db ((\1) % 8) + ((\2) * 8)
+ ELSE
+ db ((\1) % 8)
+ ENDC
+ENDM
+
+
+;\1 = event index
+;\2 = number of bytes away from the base address (optional, for matching the ROM)
+dwEventFlagAddress: MACRO
+ IF _NARG > 1
+ dw wEventFlags + ((\1) / 8) - (\2)
+ ELSE
+ dw wEventFlags + ((\1) / 8)
+ ENDC
+ENDM
+
+
+;\1 = start
+;\2 = end
+SetEventRange: MACRO
+event_start_byte = ((\1) / 8)
+event_end_byte = ((\2) / 8)
+
+ IF event_end_byte < event_start_byte
+ FAIL "Incorrect argument order in SetEventRange."
+ ENDC
+
+ IF event_start_byte == event_end_byte
+ ld a, [wEventFlags + event_start_byte]
+ or (1 << (((\2) % 8) + 1)) - (1 << ((\1) % 8))
+ ld [wEventFlags + event_start_byte], a
+ ELSE
+event_fill_start = event_start_byte + 1
+event_fill_count = event_end_byte - event_start_byte - 1
+
+ IF ((\1) % 8) == 0
+event_fill_start = event_fill_start - 1
+event_fill_count = event_fill_count + 1
+ ELSE
+ ld a, [wEventFlags + event_start_byte]
+ or $ff - ((1 << ((\1) % 8)) - 1)
+ ld [wEventFlags + event_start_byte], a
+ ENDC
+
+ IF ((\2) % 8) == 7
+event_fill_count = event_fill_count + 1
+ ENDC
+
+ IF event_fill_count == 1
+ ld hl, wEventFlags + event_fill_start
+ ld [hl], $ff
+ ENDC
+
+ IF event_fill_count > 1
+ ld a, $ff
+ ld hl, wEventFlags + event_fill_start
+
+ REPT event_fill_count - 1
+ ld [hli], a
+ ENDR
+
+ ld [hl], a
+ ENDC
+
+ IF ((\2) % 8) == 0
+ ld hl, wEventFlags + event_end_byte
+ set 0, [hl]
+ ELSE
+ IF ((\2) % 8) != 7
+ ld a, [wEventFlags + event_end_byte]
+ or (1 << (((\2) % 8) + 1)) - 1
+ ld [wEventFlags + event_end_byte], a
+ ENDC
+ ENDC
+ ENDC
+ENDM
+
+
+;\1 = start
+;\2 = end
+;\3 = assume a is 0 if present
+ResetEventRange: MACRO
+event_start_byte = ((\1) / 8)
+event_end_byte = ((\2) / 8)
+
+ IF event_end_byte < event_start_byte
+ FAIL "Incorrect argument order in ResetEventRange."
+ ENDC
+
+ IF event_start_byte == event_end_byte
+ ld a, [wEventFlags + event_start_byte]
+ and ~((1 << (((\2) % 8) + 1)) - (1 << ((\1) % 8))) & $ff
+ ld [wEventFlags + event_start_byte], a
+ ELSE
+event_fill_start = event_start_byte + 1
+event_fill_count = event_end_byte - event_start_byte - 1
+
+ IF ((\1) % 8) == 0
+event_fill_start = event_fill_start - 1
+event_fill_count = event_fill_count + 1
+ ELSE
+ ld a, [wEventFlags + event_start_byte]
+ and ~($ff - ((1 << ((\1) % 8)) - 1)) & $ff
+ ld [wEventFlags + event_start_byte], a
+ ENDC
+
+ IF ((\2) % 8) == 7
+event_fill_count = event_fill_count + 1
+ ENDC
+
+ IF event_fill_count == 1
+ ld hl, wEventFlags + event_fill_start
+ ld [hl], 0
+ ENDC
+
+ IF event_fill_count > 1
+ ld hl, wEventFlags + event_fill_start
+
+ ; force xor a if we just to wrote to it above
+ IF (_NARG < 3) || (((\1) % 8) != 0)
+ xor a
+ ENDC
+
+ REPT event_fill_count - 1
+ ld [hli], a
+ ENDR
+
+ ld [hl], a
+ ENDC
+
+ IF ((\2) % 8) == 0
+ ld hl, wEventFlags + event_end_byte
+ res 0, [hl]
+ ELSE
+ IF ((\2) % 8) != 7
+ ld a, [wEventFlags + event_end_byte]
+ and ~((1 << (((\2) % 8) + 1)) - 1) & $ff
+ ld [wEventFlags + event_end_byte], a
+ ENDC
+ ENDC
+ ENDC
+ENDM
+
+
+; returns whether both events are set in Z flag
+; This is counter-intuitive because the other event checks set the Z flag when
+; the event is not set, but this sets the Z flag when the event is set.
+;\1 = event index 1
+;\2 = event index 2
+;\3 = try to reuse a (optional)
+CheckBothEventsSet: MACRO
+ IF ((\1) / 8) == ((\2) / 8)
+ IF (_NARG < 3) || (((\1) / 8) != event_byte)
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + ((\1) / 8)]
+ ENDC
+ and (1 << ((\1) % 8)) | (1 << ((\2) % 8))
+ cp (1 << ((\1) % 8)) | (1 << ((\2) % 8))
+ ELSE
+ ; This case doesn't happen in the original ROM.
+ IF ((\1) % 8) == ((\2) % 8)
+ push hl
+ ld a, [wEventFlags + ((\1) / 8)]
+ ld hl, wEventFlags + ((\2) / 8)
+ and [hl]
+ cpl
+ bit ((\1) % 8), a
+ pop hl
+ ELSE
+ push bc
+ ld a, [wEventFlags + ((\1) / 8)]
+ and (1 << ((\1) % 8))
+ ld b, a
+ ld a, [wEventFlags + ((\2) / 8)]
+ and (1 << ((\2) % 8))
+ or b
+ cp (1 << ((\1) % 8)) | (1 << ((\2) % 8))
+ pop bc
+ ENDC
+ ENDC
+ENDM
+
+
+; returns the complement of whether either event is set in Z flag
+;\1 = event index 1
+;\2 = event index 2
+CheckEitherEventSet: MACRO
+ IF ((\1) / 8) == ((\2) / 8)
+ ld a, [wEventFlags + ((\1) / 8)]
+ and (1 << ((\1) % 8)) | (1 << ((\2) % 8))
+ ELSE
+ ; This case doesn't happen in the original ROM.
+ IF ((\1) % 8) == ((\2) % 8)
+ push hl
+ ld a, [wEventFlags + ((\1) / 8)]
+ ld hl, wEventFlags + ((\2) / 8)
+ or [hl]
+ bit ((\1) % 8), a
+ pop hl
+ ELSE
+ push bc
+ ld a, [wEventFlags + ((\1) / 8)]
+ and (1 << ((\1) % 8))
+ ld b, a
+ ld a, [wEventFlags + ((\2) / 8)]
+ and (1 << ((\2) % 8))
+ or b
+ pop bc
+ ENDC
+ ENDC
+ENDM
+
+
+CheckEitherEventSetReuseA: MACRO
+ IF event_byte != ((\1) / 8)
+event_byte = ((\1) / 8)
+ ld a, [wEventFlags + event_byte]
+ ENDC
+ IF ((\1) / 8) == ((\2) / 8)
+ ld a, [wEventFlags + ((\1) / 8)]
+ and (1 << ((\1) % 8)) | (1 << ((\2) % 8))
+ ELSE
+ ; This case doesn't happen in the original ROM.
+ IF ((\1) % 8) == ((\2) % 8)
+ push hl
+ ld a, [wEventFlags + ((\1) / 8)]
+ ld hl, wEventFlags + ((\2) / 8)
+ or [hl]
+ bit ((\1) % 8), a
+ pop hl
+ ELSE
+ push bc
+ ld a, [wEventFlags + ((\1) / 8)]
+ and (1 << ((\1) % 8))
+ ld b, a
+ ld a, [wEventFlags + ((\2) / 8)]
+ and (1 << ((\2) % 8))
+ or b
+ pop bc
+ ENDC
+ ENDC
+ ENDM
+
+; for handling fixed event bits when events are inserted/removed
+;\1 = event index
+;\2 = fixed flag bit
+AdjustEventBit: MACRO
+ IF ((\1) % 8) != (\2)
+ add ((\1) % 8) - (\2)
+ ENDC
+ENDM
+
diff --git a/macros/scripts/maps.asm b/macros/scripts/maps.asm
new file mode 100644
index 00000000..2032629b
--- /dev/null
+++ b/macros/scripts/maps.asm
@@ -0,0 +1,225 @@
+def_objects: MACRO
+ IF DEF(_NUM_OBJECTS)
+ PURGE _NUM_OBJECTS
+ ENDC
+_NUM_OBJECTS EQUS "_NUM_OBJECTS_\@"
+ db _NUM_OBJECTS
+_NUM_OBJECTS = 0
+ENDM
+
+;\1 sprite id
+;\2 x position
+;\3 y position
+;\4 movement (WALK/STAY)
+;\5 range or direction
+;\6 text id
+;\7 items only: item id
+;\7 trainers only: trainer class/pokemon id
+;\8 trainers only: trainer number/pokemon level
+object: MACRO
+ db \1
+ db \3 + 4
+ db \2 + 4
+ db \4
+ db \5
+ IF _NARG > 7
+ db TRAINER | \6
+ db \7
+ db \8
+ ELIF _NARG > 6
+ db ITEM | \6
+ db \7
+ ELSE
+ db \6
+ ENDC
+_NUM_OBJECTS = _NUM_OBJECTS + 1
+ENDM
+
+def_warps: MACRO
+ IF DEF(_NUM_WARPS)
+ PURGE _NUM_WARPS
+ ENDC
+_NUM_WARPS EQUS "_NUM_WARPS_\@"
+ db _NUM_WARPS
+_NUM_WARPS = 0
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 destination warp id
+;\4 destination map (-1 = wLastMap)
+warp: MACRO
+ db \2, \1, \3, \4
+_NUM_WARPS = _NUM_WARPS + 1
+; the Nth warp defines a corresponding Nth warp_to, stored in _WARP_TO_NUM_<N>
+_WARP_TO_NAME EQUS "_WARP_TO_NUM_{d:{_NUM_WARPS}}"
+_WARP_TO_NAME EQUS "warp_to \1, \2, _WARP_TO_WIDTH"
+ PURGE _WARP_TO_NAME
+ENDM
+
+def_signs: MACRO
+ IF DEF(_NUM_SIGNS)
+ PURGE _NUM_SIGNS
+ ENDC
+_NUM_SIGNS EQUS "_NUM_SIGNS_\@"
+ db _NUM_SIGNS
+_NUM_SIGNS = 0
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 sign id
+sign: MACRO
+ db \2, \1, \3
+_NUM_SIGNS = _NUM_SIGNS + 1
+ENDM
+
+;\1 source map
+def_warps_to: MACRO
+; output and purge each _WARP_TO_NUM_<N> warp_to, from N=1 to _NUM_WARPS
+_WARP_TO_WIDTH = \1_WIDTH
+_WARP_TO_N = 1
+ REPT _NUM_WARPS
+_WARP_TO_NAME EQUS "_WARP_TO_NUM_{d:_WARP_TO_N}"
+ _WARP_TO_NAME
+_WARP_TO_N = _WARP_TO_N + 1
+_PURGE_WARP_TO_NUM EQUS "PURGE {_WARP_TO_NAME}"
+ _PURGE_WARP_TO_NUM
+ PURGE _PURGE_WARP_TO_NUM
+ PURGE _WARP_TO_NAME
+ ENDR
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 map width
+warp_to: MACRO
+ event_displacement \3, \1, \2
+ENDM
+
+
+;\1 event flag
+;\2 view range
+;\3 TextBeforeBattle
+;\4 TextAfterBattle
+;\5 TextEndBattle
+trainer: MACRO
+ IF _NARG > 5
+ dbEventFlagBit \1, \2
+ db (\3 << 4)
+ dwEventFlagAddress \1, \2
+ SHIFT
+ ELSE
+ dbEventFlagBit \1
+ db (\2 << 4)
+ dwEventFlagAddress \1
+ ENDC
+ dw \3, \5, \4, \4
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 movement data
+map_coord_movement: MACRO
+ dbmapcoord \1, \2
+ dw \3
+ENDM
+
+
+;\1 map name
+;\2 map id
+;\3 tileset
+;\4 connections: combo of NORTH, SOUTH, WEST, and/or EAST, or 0 for none
+map_header: MACRO
+CURRENT_MAP_WIDTH = \2_WIDTH
+CURRENT_MAP_HEIGHT = \2_HEIGHT
+CURRENT_MAP_OBJECT EQUS "\1_Object"
+\1_h::
+ db \3
+ db CURRENT_MAP_HEIGHT, CURRENT_MAP_WIDTH
+ dw \1_Blocks
+ dw \1_TextPointers
+ dw \1_Script
+ db \4
+ENDM
+
+; Comes after map_header and connection macros
+end_map_header: MACRO
+ dw CURRENT_MAP_OBJECT
+ PURGE CURRENT_MAP_WIDTH
+ PURGE CURRENT_MAP_HEIGHT
+ PURGE CURRENT_MAP_OBJECT
+ENDM
+
+; Connections go in order: north, south, west, east
+;\1 direction
+;\2 map name
+;\3 map id
+;\4 offset of the target map relative to the current map
+; (x offset for east/west, y offset for north/south)
+connection: MACRO
+
+; Calculate tile offsets for source (current) and target maps
+_src = 0
+_tgt = (\4) + 3
+IF _tgt < 2
+_src = -_tgt
+_tgt = 0
+ENDC
+
+IF !STRCMP("\1", "north")
+_blk = \3_WIDTH * (\3_HEIGHT - 3) + _src
+_map = _tgt
+_win = (\3_WIDTH + 6) * \3_HEIGHT + 1
+_y = \3_HEIGHT * 2 - 1
+_x = (\4) * -2
+_len = CURRENT_MAP_WIDTH + 3 - (\4)
+IF _len > \3_WIDTH
+_len = \3_WIDTH
+ENDC
+
+ELIF !STRCMP("\1", "south")
+_blk = _src
+_map = (CURRENT_MAP_WIDTH + 6) * (CURRENT_MAP_HEIGHT + 3) + _tgt
+_win = \3_WIDTH + 7
+_y = 0
+_x = (\4) * -2
+_len = CURRENT_MAP_WIDTH + 3 - (\4)
+IF _len > \3_WIDTH
+_len = \3_WIDTH
+ENDC
+
+ELIF !STRCMP("\1", "west")
+_blk = (\3_WIDTH * _src) + \3_WIDTH - 3
+_map = (CURRENT_MAP_WIDTH + 6) * _tgt
+_win = (\3_WIDTH + 6) * 2 - 6
+_y = (\4) * -2
+_x = \3_WIDTH * 2 - 1
+_len = CURRENT_MAP_HEIGHT + 3 - (\4)
+IF _len > \3_HEIGHT
+_len = \3_HEIGHT
+ENDC
+
+ELIF !STRCMP("\1", "east")
+_blk = (\3_WIDTH * _src)
+_map = (CURRENT_MAP_WIDTH + 6) * _tgt + CURRENT_MAP_WIDTH + 3
+_win = \3_WIDTH + 7
+_y = (\4) * -2
+_x = 0
+_len = CURRENT_MAP_HEIGHT + 3 - (\4)
+IF _len > \3_HEIGHT
+_len = \3_HEIGHT
+ENDC
+
+ELSE
+fail "Invalid direction for 'connection'."
+ENDC
+
+ db \3
+ dw \2_Blocks + _blk
+ dw wOverworldMap + _map
+ db _len - _src
+ db \3_WIDTH
+ db _y, _x
+ dw wOverworldMap + _win
+ENDM
diff --git a/macros/scripts/text.asm b/macros/scripts/text.asm
new file mode 100755
index 00000000..2ec1de43
--- /dev/null
+++ b/macros/scripts/text.asm
@@ -0,0 +1,213 @@
+text EQUS "db TX_START," ; Start writing text.
+next EQUS "db \"<NEXT>\"," ; Move a line down.
+line EQUS "db \"<LINE>\"," ; Start writing at the bottom line.
+para EQUS "db \"<PARA>\"," ; Start a new paragraph.
+cont EQUS "db \"<CONT>\"," ; Scroll to the next line.
+done EQUS "db \"<DONE>\"" ; End a text box.
+prompt EQUS "db \"<PROMPT>\"" ; Prompt the player to end a text box (initiating some other event).
+
+page EQUS "db \"<PAGE>\"," ; Start a new Pokédex page.
+dex EQUS "db \"<DEXEND>\", \"@\"" ; End a Pokédex entry.
+
+
+; TextCommandJumpTable indexes (see home/text.asm)
+ const_def
+
+ const TX_START ; $00
+text_start: MACRO
+ db TX_START
+ENDM
+
+ const TX_RAM ; $01
+text_ram: MACRO
+ db TX_RAM
+ dw \1 ; address to read from
+ENDM
+
+ const TX_BCD ; $02
+text_bcd: MACRO
+ db TX_BCD
+ dw \1 ; address to read from
+ db \2 ; number of bytes + print flags
+ENDM
+
+ const TX_MOVE ; $03
+text_move: MACRO
+ db TX_MOVE
+ dw \1 ; address of the new location
+ENDM
+
+ const TX_BOX ; $04
+text_box: MACRO
+; draw box
+ db TX_BOX
+ dw \1 ; address of upper left corner
+ db \2, \3 ; height, width
+ENDM
+
+ const TX_LOW ; $05
+text_low: MACRO
+ db TX_LOW
+ENDM
+
+ const TX_PROMPT_BUTTON ; $06
+text_promptbutton: MACRO
+ db TX_PROMPT_BUTTON
+ENDM
+
+ const TX_SCROLL ; $07
+text_scroll: MACRO
+ db TX_SCROLL
+ENDM
+
+ const TX_START_ASM ; $08
+text_asm: MACRO
+ db TX_START_ASM
+ENDM
+
+ const TX_NUM ; $09
+text_decimal: MACRO
+; print a big-endian decimal number.
+ db TX_NUM
+ dw \1 ; address to read from
+ dn \2, \3 ; number of bytes to read, number of digits to display
+ENDM
+
+ const TX_PAUSE ; $0a
+text_pause: MACRO
+ db TX_PAUSE
+ENDM
+
+ const TX_SOUND_GET_ITEM_1 ; $0b
+sound_get_item_1: MACRO
+ db TX_SOUND_GET_ITEM_1
+ENDM
+
+TX_SOUND_LEVEL_UP EQU TX_SOUND_GET_ITEM_1
+sound_level_up EQUS "sound_get_item_1"
+
+ const TX_DOTS ; $0c
+text_dots: MACRO
+ db TX_DOTS
+ db \1 ; number of ellipses to draw
+ENDM
+
+ const TX_WAIT_BUTTON ; $0d
+text_waitbutton: MACRO
+ db TX_WAIT_BUTTON
+ENDM
+
+ const TX_SOUND_POKEDEX_RATING ; $0e
+sound_pokedex_rating: MACRO
+ db TX_SOUND_POKEDEX_RATING
+ENDM
+
+ const TX_SOUND_GET_ITEM_1_DUPLICATE ; $0f
+sound_get_item_1_duplicate: MACRO
+ db TX_SOUND_GET_ITEM_1_DUPLICATE
+ENDM
+
+ const TX_SOUND_GET_ITEM_2 ; $10
+sound_get_item_2: MACRO
+ db TX_SOUND_GET_ITEM_2
+ENDM
+
+ const TX_SOUND_GET_KEY_ITEM ; $11
+sound_get_key_item: MACRO
+ db TX_SOUND_GET_KEY_ITEM
+ENDM
+
+ const TX_SOUND_CAUGHT_MON ; $12
+sound_caught_mon: MACRO
+ db TX_SOUND_CAUGHT_MON
+ENDM
+
+ const TX_SOUND_DEX_PAGE_ADDED ; $13
+sound_dex_page_added: MACRO
+ db TX_SOUND_DEX_PAGE_ADDED
+ENDM
+
+ const TX_SOUND_CRY_PIKACHU ; $14
+sound_cry_pikachu: MACRO
+ db TX_SOUND_CRY_PIKACHU
+ENDM
+
+ const TX_SOUND_CRY_PIDGEOT ; $15
+sound_cry_pidgeot: MACRO
+ db TX_SOUND_CRY_PIDGEOT
+ENDM
+
+ const TX_SOUND_CRY_DEWGONG ; $16
+sound_cry_dewgong: MACRO
+ db TX_SOUND_CRY_DEWGONG
+ENDM
+
+ const TX_FAR ; $17
+text_far: MACRO
+ db TX_FAR
+ dab \1 ; address of text commands
+ENDM
+
+
+ const_next $50
+
+ const TX_END ; $50
+text_end: MACRO
+ db TX_END
+ENDM
+
+
+; Text script IDs (see home/text_script.asm)
+ const_def -1, -1
+
+ const TX_SCRIPT_POKECENTER_NURSE ; $ff
+script_pokecenter_nurse: MACRO
+ db TX_SCRIPT_POKECENTER_NURSE
+ENDM
+
+ const TX_SCRIPT_MART ; $fe
+script_mart: MACRO
+ db TX_SCRIPT_MART
+ db _NARG ; number of items
+REPT _NARG
+ db \1 ; item id
+ SHIFT
+ENDR
+ db -1 ; end
+ENDM
+
+ const TX_SCRIPT_BILLS_PC ; $fd
+script_bills_pc: MACRO
+ db TX_SCRIPT_BILLS_PC
+ENDM
+
+ const TX_SCRIPT_PLAYERS_PC ; $fc
+script_players_pc: MACRO
+ db TX_SCRIPT_PLAYERS_PC
+ENDM
+
+ const_skip ; $fb
+
+ const_skip ; $fa
+
+ const TX_SCRIPT_POKECENTER_PC ; $f9
+script_pokecenter_pc: MACRO
+ db TX_SCRIPT_POKECENTER_PC
+ENDM
+
+ const_skip ; $f8
+
+ const TX_SCRIPT_PRIZE_VENDOR ; $f7
+script_prize_vendor: MACRO
+ db TX_SCRIPT_PRIZE_VENDOR
+ENDM
+
+ const TX_SCRIPT_CABLE_CLUB_RECEPTIONIST ; $f6
+script_cable_club_receptionist: MACRO
+ db TX_SCRIPT_CABLE_CLUB_RECEPTIONIST
+ENDM
+
+ const TX_SCRIPT_VENDING_MACHINE ; $f5
+script_vending_machine: MACRO
+ db TX_SCRIPT_VENDING_MACHINE
+ENDM