Skip to content

Instantly share code, notes, and snippets.

@ZoomTen
Last active May 16, 2021 07:53
Show Gist options
  • Save ZoomTen/59414f6b7c3044386449149189a270ab to your computer and use it in GitHub Desktop.
Save ZoomTen/59414f6b7c3044386449149189a270ab to your computer and use it in GitHub Desktop.
Notes on Pokemon G/S 1997 script editing

Notes on pokegold-spaceworld script editing

Mapping

Easily opened with the latest version of Polished Map (4.5.4 as of writing).

object_event data is a little misleading -- movement constant has wrong context (e.g. SLOW_STEP_LEFT is inaccurate)

Hex ID Movement
$00 Invisible but interactible object
$01 Wander around
$02 Look around
$03 Wander north and south
$04 Wander east and west
$05 Facing down
$06 Facing up
$07 Facing left
$08 Facing right

> $09, game locks up. SPRITEMOVEDATA_STILL is missing.

(equivalent constants in pokegold's map_object_constants.asm)

Sample map for XXX Town:

INCLUDE "constants.asm"

SECTION "data/maps/objects/XXX.asm", ROMX

	map_attributes XXX, XXX, NORTH | WEST | EAST
	connection north, PrinceRoute, PRINCE_ROUTE, 0
	connection west, Route1P1, ROUTE_1_P1, 0
	connection east, RouteSilentEast, ROUTE_SILENT_EAST, 0

XXX_MapEvents::
	dw $4000 ; unknown

	def_warp_events
	warp_event  5,  3, PLAYER_HOUSE_1F, 1, 51

	; bg_events are used for signs??
	def_bg_events
	bg_event  6,  4, 1

	def_object_events
	object_event  6,  6, SPRITE_SILVER, $03, 6, 6, -1, -1, 0, 0, 0, 0, 0, 0
	object_event 13, 13, SPRITE_BLUE, SLOW_STEP_LEFT, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0

XXX_Blocks::
INCBIN "maps/XXX.blk"

Script Defines

Scripting is still done with ASM. It's set up much more like Red/Blue's, only with the addition of which NPCs should be displayed.

Map scripts are usually:

XXX_ScriptLoader::  ; required
    ld hl, XXX_Scenes
    call RunMapScript
    call WriteBackMapScriptNumber
    ret

; call then ret's can be replaced with jp

With XXX_Scenes being:

XXX_Scenes:
; 00
    dw XXX_Scene00
    dw XXX_Scene00_NPCs
; 01
    dw XXX_Scene01
    dw XXX_Scene01_NPCs
; 02
    dw XXX_Scene02
    dw XXX_Scene02_NPCs

; and so on...

XXX_Scene## contains the ASM script run at every frame for a given script number.

XXX_Scene##_NPCs contains a $FF-terminated list of which NPCs to display when a script number is active, which seems to follow the object data order in data/maps/objects/XXX.asm:

; XXX NPC ID's
	const_def
	const XXX_OBJECT_SILVER
	const XXX_OBJECT_BLUE

XXX_Scene##_NPCs:
	db XXX_OBJECT_SILVER
	db XXX_OBJECT_BLUE
	db -1 ; terminator

Background events like signs can be assigned to XXX_BGEventRoutines, which GF calls at the end of every individual script:

    ld de, XXX_BGEventRoutines
    call CallMapTextSubroutine
    ret

You may want to do that inside the script loader itself. As for the routines themselves:

XXX_BGEventRoutines:
    dw XXX_TheOnlySign
    dw XXX_BlankRoutine

; ----- start BG event routines -----

XXX_TheOnlySign:
    ld hl, .Text
    jp OpenTextbox
.Text:
	text "123"
	done

XXX_BlankRoutine:
    ret

Object events are hooked to XXX_TextPointers, which are really just miniscripts:

XXX_TextPointers::  ; required
    dw XXX_Talk1
    dw XXX_Talk2

; ----- start object event routines -----

XXX_Talk1:
    ld hl, .Text
    jp OpenTextbox
.Text:
	text "123"
	done

XXX_Talk2:
    ld hl, .Text
    jp OpenTextbox
.Text:
	text "888"
	done

Scripting

Instead of documenting a bunch of ASM I decided to make a bunch of macros. ¯\(ツ)

; check_location <X>, <Y>
; Check if the player is in some specific map location
check_location: macro
	ld a, [wYCoord]
	cp \2
	ret nz
	ld a, [wXCoord]
	cp \1
	ret nz
endm

lock_controls: macro
	ld hl, wJoypadFlags
	set 7, [hl]
endm

unlock_controls: macro
	ld hl, wJoypadFlags
	res 7, [hl]
endm

; move_npc <npc_id>, <movement data pointer>
;
; Refer to constants/movement_constants.asm.
;
; $32 = end movement
; $33 = end movement and disappear
;
; NPC ID 0 is the player
move_npc: macro
	ld a, \1
	ld hl, \2
	call LoadMovementDataPointer
endm

; lock_screen_on <npc_id>
;
; After assigning an NPC some movement data,
; this locks script advancement until the
; NPC stops moving.
;
; This command does not actually wait inside
; the script, but is defined at the end of a
; script to tell the game to wait first before
; loading the next script.
;
; As a consequence, unlock_screen *MUST* be the
; first thing in the next script, otherwise the
; game will soft lock!
lock_screen_on: macro
	assert \1 > 0, "Player object ($00) cannot be locked"

	ld a, \1
	call Function17f9
	ld hl, wc5ed
	set 7, [hl]
	ld a, 1
	call WriteIntod637
endm

unlock_screen: macro
	call Function1848
endm

; set_scene <script number>
set_scene: macro
	ld a, \1
	ld [wMapScriptNumber], a
endm

; dialog <textbox ptr>
dialog: macro
	ld hl, \1
	call OpenTextbox
endm

; jump_dialog <textbox ptr>
jump_dialog: macro
	ld hl, \1
	jp OpenTextbox
endm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment