summaryrefslogtreecommitdiff
path: root/macros/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'macros/scripts')
-rwxr-xr-xmacros/scripts/audio.asm186
-rwxr-xr-xmacros/scripts/events.asm471
-rw-r--r--macros/scripts/maps.asm184
-rwxr-xr-xmacros/scripts/text.asm78
4 files changed, 919 insertions, 0 deletions
diff --git a/macros/scripts/audio.asm b/macros/scripts/audio.asm
new file mode 100755
index 00000000..8a250c63
--- /dev/null
+++ b/macros/scripts/audio.asm
@@ -0,0 +1,186 @@
+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
+
+; 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
+pitch_sweep: MACRO
+ db $10
+ IF \2 < 0
+ db (\1 << 4) | (%1000 | (\2 * -1))
+ ELSE
+ db (\1 << 4) | \2
+ ENDC
+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
+square_note: MACRO
+ db $20 | \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: MACRO
+ db $20 | \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
+
+; arguments: instrument [1, 19], length [1, 16]
+drum_note: MACRO
+ db $B0 | (\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
+
+; arguments: length [1, 16]
+rest: MACRO
+ db $C0 | (\1 - 1)
+ENDM
+
+; 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
+note_type: MACRO
+ db $D0 | \1
+ IF \3 < 0
+ db (\2 << 4) | (%1000 | (\3 * -1))
+ ELSE
+ db (\2 << 4) | \3
+ ENDC
+ENDM
+
+; arguments: speed [0, 15]
+drum_speed: MACRO
+ db $D0 | \1
+ENDM
+
+; arguments: octave [1, 8]
+octave: MACRO
+ db $E8 - \1
+ENDM
+
+; when enabled, effective frequency used is incremented by 1
+toggle_perfect_pitch: MACRO
+ db $E8
+ENDM
+
+; 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
+vibrato: MACRO
+ db $EA
+ db \1
+ db (\2 << 4) | \3
+ENDM
+
+; arguments: length [1, 256], octave [1, 8], pitch
+pitch_slide: MACRO
+ db $EB
+ db \1 - 1
+ db ((8 - \2) << 4) | \3
+ENDM
+
+; arguments: duty cycle [0, 3] (12.5%, 25%, 50%, 75%)
+duty_cycle: MACRO
+ db $EC
+ 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
+tempo: MACRO
+ db $ED
+ db \1 / $100
+ db \1 % $100
+ENDM
+
+; arguments: left output enable mask, right output enable mask
+stereo_panning: MACRO
+ db $EE
+ db (\1 << 4) | \2
+ENDM
+
+; arguments: left master volume [0, 7], right master volume [0, 7]
+volume: MACRO
+ db $F0
+ db (\1 << 4) | \2
+ENDM
+
+; when enabled, the sfx data is interpreted as music data
+execute_music: MACRO
+ db $F8
+ENDM
+
+; arguments: duty cycle 1, duty cycle 2, duty cycle 3, duty cycle 4
+duty_cycle_pattern: MACRO
+ db $FC
+ db \1 << 6 | \2 << 4 | \3 << 2 | \4
+ENDM
+
+; arguments: address
+sound_call: MACRO
+ db $FD
+ dw \1
+ENDM
+
+; arguments: count, address
+sound_loop: MACRO
+ db $FE
+ db \1
+ dw \2
+ENDM
+
+sound_ret: MACRO
+ db $FF
+ENDM
diff --git a/macros/scripts/events.asm b/macros/scripts/events.asm
new file mode 100755
index 00000000..c5f90107
--- /dev/null
+++ b/macros/scripts/events.asm
@@ -0,0 +1,471 @@
+;\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
+
+
+;\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
+
+
+;\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
+
+
+; 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..a30561b9
--- /dev/null
+++ b/macros/scripts/maps.asm
@@ -0,0 +1,184 @@
+;\1 map width
+;\2 Rows above (Y-blocks)
+;\3 X movement (X-blocks)
+EVENT_DISP: MACRO
+ dw (wOverworldMap + 7 + (\1) + ((\1) + 6) * ((\2) >> 1) + ((\3) >> 1)) ; Ev.Disp
+ db \2,\3 ;Y,X
+ENDM
+
+FLYWARP_DATA: MACRO
+ EVENT_DISP \1,\2,\3
+ db ((\2) & $01) ;sub-block Y
+ db ((\3) & $01) ;sub-block X
+ENDM
+
+; external map entry macro
+EMAP: MACRO ; emap x-coordinate,y-coordinate,textpointer
+; the appearance of towns and routes in the town map, indexed by map id
+ ; nybble: y-coordinate
+ ; nybble: x-coordinate
+ ; word : pointer to map name
+ dn \2, \1
+ dw \3
+ENDM
+
+; internal map entry macro
+IMAP: MACRO ; imap mapid_less_than,x-coordinate,y-coordinate,textpointer
+; the appearance of buildings and dungeons in the town map
+ ; byte : maximum map id subject to this rule
+ ; nybble: y-coordinate
+ ; nybble: x-coordinate
+ ; word : pointer to map name
+ db \1 + 1
+ dn \3, \2
+ dw \4
+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
+ ELSE
+ IF (_NARG > 6)
+ db ITEM | \6
+ db \7
+ ELSE
+ db \6
+ ENDC
+ ENDC
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 destination warp id
+;\4 destination map (-1 = wLastMap)
+warp: MACRO
+ db \2, \1, \3, \4
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 sign id
+sign: MACRO
+ db \2, \1, \3
+ENDM
+
+;\1 x position
+;\2 y position
+;\3 map width
+warp_to: MACRO
+ EVENT_DISP \3, \2, \1
+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 "\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 "\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 "\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 "\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..732a22d4
--- /dev/null
+++ b/macros/scripts/text.asm
@@ -0,0 +1,78 @@
+text EQUS "db $00," ; Start writing text.
+next EQUS "db $4e," ; Move a line down.
+line EQUS "db $4f," ; Start writing at the bottom line.
+para EQUS "db $51," ; Start a new paragraph.
+cont EQUS "db $55," ; Scroll to the next line.
+done EQUS "db $57" ; End a text box.
+prompt EQUS "db $58" ; Prompt the player to end a text box (initiating some other event).
+
+page EQUS "db $49," ; Start a new Pokedex page.
+dex EQUS "db $5f, $50" ; End a Pokedex entry.
+
+TX_RAM: MACRO
+; prints text to screen
+; \1: RAM address to read from
+ db $1
+ dw \1
+ENDM
+
+TX_BCD: MACRO
+; \1: RAM address to read from
+; \2: number of bytes + print flags
+ db $2
+ dw \1
+ db \2
+ENDM
+
+TX_LINE EQUS "db $05"
+TX_BLINK EQUS "db $06"
+;TX_SCROLL EQUS "db $07"
+TX_ASM EQUS "db $08"
+
+TX_NUM: MACRO
+; print a big-endian decimal number.
+; \1: address to read from
+; \2: number of bytes to read
+; \3: number of digits to display
+ db $09
+ dw \1
+ db \2 << 4 | \3
+ENDM
+
+TX_DELAY EQUS "db $0a"
+TX_SFX_ITEM_1 EQUS "db $0b"
+TX_SFX_LEVEL_UP EQUS "db $0b"
+;TX_ELLIPSES EQUS "db $0c"
+TX_WAIT EQUS "db $0d"
+;TX_SFX_DEX_RATING EQUS "db $0e"
+TX_SFX_ITEM_2 EQUS "db $10"
+TX_SFX_KEY_ITEM EQUS "db $11"
+TX_SFX_CAUGHT_MON EQUS "db $12"
+TX_SFX_DEX_PAGE_ADDED EQUS "db $13"
+TX_CRY_NIDORINA EQUS "db $14"
+TX_CRY_PIDGEOT EQUS "db $15"
+;TX_CRY_DEWGONG EQUS "db $16"
+
+TX_FAR: MACRO
+ db $17
+ dw \1
+ db BANK(\1)
+ENDM
+
+TX_VENDING_MACHINE EQUS "db $f5"
+TX_CABLE_CLUB_RECEPTIONIST EQUS "db $f6"
+TX_PRIZE_VENDOR EQUS "db $f7"
+TX_POKECENTER_PC EQUS "db $f9"
+TX_PLAYERS_PC EQUS "db $fc"
+TX_BILLS_PC EQUS "db $fd"
+
+TX_MART: MACRO
+ db $FE, _NARG
+ REPT _NARG
+ db \1
+ SHIFT
+ ENDR
+ db $FF
+ENDM
+
+TX_POKECENTER_NURSE EQUS "db $ff"