Created
October 4, 2024 04:22
-
-
Save PhoenixBound/f6d19ab63f7bbed28960be5cc2d57c03 to your computer and use it in GitHub Desktop.
More kinds of item boxes in EarthBound -- untested edition
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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