Skip to content

Instantly share code, notes, and snippets.

@PhoenixBound
Created October 4, 2024 04:22
Show Gist options
  • Select an option

  • Save PhoenixBound/f6d19ab63f7bbed28960be5cc2d57c03 to your computer and use it in GitHub Desktop.

Select an option

Save PhoenixBound/f6d19ab63f7bbed28960be5cc2d57c03 to your computer and use it in GitHub Desktop.
More kinds of item boxes in EarthBound -- untested edition
// Item mode script by PhoenixBound
// Last updated: 2024-10-03
//
// This script lets you give more kinds of things and experiences in item boxes.
// You're no longer limited to just items! If you can script it, you can gift it!
// To name just a few possibilities:
// - Party members (simple example provided)
// - Chests that just show a cutscene like in Mother 3 (simple examples provided)
// - Experience points or stat boosts or one-time healing
// - Nebulous, unquantifiable story progress
// - Macguffin items that don't appear in your inventory
// - The requirement to beat a specific enemy to get the item inside
// - A battle. No reward for beating the battle, just a battle.
// - A trap that warps you somewhere scary
// - Other PK Scramble-worthy "curses"
// It was originally created for the EarthBound archipelago randomizer by PinkSwitch.
//
// .--------------------.
// | Usage Instructions |
// '--------------------'
//
// The way this script works is, it changes how the `Text Pointer 2` field in the NPC table works
// for "item"-type NPCs.
// It's now of the format $XXXXYYYY, where XXXX is the mode number (0 for items, 1 for money,
// 2+ for custom modes). That means you can have hundreds or even thousands of modes and "items" in
// those modes, which should be more than enough.
// But!
// !!!!!!!⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
// NOTE THAT THIS MEANS ALL OF THE MONEY PRESENTS IN THE VANILLA GAME ARE BROKEN
// !!!!!!!⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
// You have to fix them to manually use `$1XXXX` where XXXX is the money amount,
// instead of just adding 0x100 to the amount of money.
// For example, to give a thousand dollars in a chest, set the Text Pointer 2 to $103E8
// (03E8 in hex is 1000), instead of the original game's $4e8.
// To give something in mode 2 with an item number/strength of 69, set the Text Pointer 2 to $20045.
import asm65816
command promptw "[03]"
command switch_goto(num) "[09 {byte num}]"
command switch_entry(target) long target
command compare_register(num, reg) "[18 07 {long num} {byte reg}]"
command compare_result(num) compare_register(num, 0)
command compare_argument(num) compare_register(num, 1)
command compare_counter(num) compare_register(num, 2)
command goto_if_true(target) "[1B 03 {long target}]"
command sprite2_spawn(sprite, move, style) "[1F 15 {short sprite} {short move} {byte style}]"
command wait_input_timeout(n) "[1F 60 {byte n}]"
command wait_movement "[1F 61]"
// Edits to the present script to support more than two modes of operation
// !!! MAKE THESE EDITS TO YOUR DECOMPILED COPY OF THE PRESENT SCRIPT IF NECESSARY!
ROM[0xC7D8A5] = goto(present_jump_table)
present_jump_table:
// Update vvvvv this number to match the number of modes you add after one
switch_goto(1) // <--- Update this number!
// ^^^^^ Don't forget to update this number!
// Mode 1: giving money
switch_entry(0xC7D8EE)
// Example mode 2: transient event in the chest
// switch_entry(_example_transient_event)
// Example mode 3: party member in the chest
// switch_entry(_example_party)
// Mode 0: giving a normal item
goto(0xC7D8AD)
/*
_example_transient_event: {
// music_effect(2)
// pause(30)
// music_stop
swap
switch_goto(3)
switch_entry(_creepy_music) // 1
switch_entry(_retro_music) // 2
switch_entry(_bomb) // 3
swap
"@There is absolutely nothing in the box,| because transient event {number(0)} doesn't exist..." next
"@Transient event {number(0)}?!" linebreak
" (Show this to the hack developer.)" end
_creepy_music:
music_effect(2)
pause(30)
music_stop
"@There is a creepy beat playing inside!" wait_input_timeout(30)
music(0x85)
// 386 ticks that take 23.2727... milliseconds each will last for 8.983 seconds,
// or about 539 frames.
pause(60)
// Appease the mashers
wait_input_timeout(255)
wait_input_timeout(194)
_music_end:
music_effect(2)
linebreak
pause(30)
"@Huh." wait
music_resume
eob
_retro_music:
music_effect(2)
pause(30)
music_stop
"@There is a retro beat playing inside!" wait_input_timeout(30)
music(0x15)
// 1 tick of tempo $20 and 384*2 ticks of tempo $1D...
// comes out to 16ms + 13559.17ms = about 815 frames
pause(60)
// Appease the mashers
wait_input_timeout(255)
wait_input_timeout(255)
wait_input_timeout(215)
goto(_music_end)
_bomb: // There's no movement script with the Sky Runner explosion effect on its own,
// so this is gonna be a camera instead
"@There is a camera inside--"
window_closeall
sprite2_spawn(106, 452, 1)
wait_movement
window_open(1)
"@Wow.{pause(20)} Rude...| you couldn't even pose in time!" end
}
*/
/*
_example_party: {
swap
"@There is your friend {name(0)} inside!" next
"@{swap}{call(heshecapital)} was wondering when you would come..." promptw
window_closeall
store_registers
compare_result(5)
goto_if_true(_alt_music)
music(11)
pause(240)
goto(_join)
_alt_music:
music(123)
_join:
pause(180)
music_resume
load_registers
swap
window_open(1)
"@({name(0)} joins you.)" wait
party_add(0)
window_closeall
eob
heshecapital:
switch_goto(2)
switch_entry(_he) // Ness is he
switch_entry(_she) // Paula is she
// And everyone else is he
_he:
"He" eob
_she:
"She" eob
}
*/
// --------------------------------------------------------------------
// Chances are, you don't need/want to edit anything below this point.
// --------------------------------------------------------------------
// Edits to CHECK ($C1323B) to set up window registers for the modified present script
ROM[0xC132D5] = {
// Save the pointer to the end part of the NPC data
LDX_d (0x06)
PHX
LDX_d (0x08)
PHX
// Always set the argument register to the low word of this "pointer"
// (the specific item number, usually)
STA_d (0x0E)
STZ_d (0x10)
JSR (0x0489)
// Get the pointer to the high word in $06, and read the high word
PLA
STA_d (0x08)
PLA
INC
INC
STA_d (0x06)
LDA_dl (0x06)
// Set the result register to the high word of this "pointer" (the item mode)
STA_d (0x0E)
STZ_d (0x10)
JSR (0x045D)
// Continue on with the rest of the code
BRA (0x3A)
// Be polite to people who open the ROM wondering what the heck is going on :)
NOP NOP NOP NOP NOP NOP NOP NOP // 8
NOP NOP NOP NOP NOP NOP NOP NOP // 10
NOP NOP NOP NOP NOP NOP NOP NOP // 18
NOP NOP NOP NOP NOP NOP NOP NOP // 20
NOP NOP NOP NOP NOP NOP NOP NOP // 28
NOP NOP NOP NOP NOP NOP NOP NOP // 30
NOP NOP NOP NOP NOP NOP NOP NOP // 38
NOP NOP // 3A
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment