Files
dockipelago/worlds/earthbound/modules/psi_shuffle.py
PinkSwitch 55c70a5ba8 EarthBound: Implement New Game (#5159)
* Add the world

* doc update

* docs

* Fix Blast/Missile not clearing Reflect

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

remove unused import

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/dungeon_er.py

make bool optional

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/boss_shuffle.py

typing update

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/boss_shuffle.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Filter events out of item name to id

* we call it a glorp

* Update worlds/earthbound/Regions.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/Items.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/Regions.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Fix missing optional import

* hint stuff

* -Fix Apple Kid text being wrong
-Fix Slimy Pile text being wrong

* -Fix some sprite corruption if PSI was used when an enemy loaded another enemy
-Fixed a visible artifact tile during some cutscenes

* Update ver

* Update docs

* Fix some money scripting issues

* Add argument to PSI fakeout attack

* Updated monkey caves shop description

* Remove closing markdown from doc

* Add new flavors

* Make flavors actually work

* Update platforms

* Fix common gear getting duplicated

* Split region initialization

* Condense checks for start inventory + some other junk

* Fix some item groups - change receiver phone to warp pad

* wow that one was really bad :glorp:

* blah

* Fix cutoff option text

* switch start inventory concatenation to itertools

* Fix sky runner scripting bug - added some new comm suggestions

* Fix crash when generating with spoiler_only

* Fix happy-happy teleport not unlocking after beating carpainter

* Hint man hints can now use CreateHint packets to create hints in other games

* Adjust some filler rarity

* Update world to use CreateHints and deprecate old method

* Fix epilogue skip being offset

* Rearrange a couple regions

* Fix tendapants getting deleted in battle

* update doc

* i got scared and forgot i had multiple none checks and am worried about this triggering but tested and it works

* Fix mostly typing errors from silvris

* More type checks

* More typing

* Typema

* Type

* Fix enemy levels overwriting music

* Fix gihugic blunder

* Fix Lumine Hall enabling OSS

* del world

* Rel 4.2.7

* Remove some debug logs

* Fix vanilla bug with weird ambush detection

* Fix Starman Junior having an unscaled Freeze

* Change shop scaling

* Fix shops using the wrong thankful script

* Update some bosses in boss shuffle

* Loc group adjustment

* Update some boss shuffle stuff | Fix Enemizer attacks getting overwritten by Shuffle data | Fix flunkies not updating and still being used with enemizer

* Get rid of some debug stuff

* Get boss shuffle running, dont merge

* Fix json and get boss shuffle no plando back up

* Fix Magicant Boost not initializing to Ness if party count = 4

* Fix belch shop using wrong logic

* Don't re-send goal status

* EBitem

* remove :

* idk if this is whatvi wanted

* All client messagesnow only send when relevant instead of constantly

* Patch up the rest of boss plando

* Fix Giygas being not excluded from enemizer

* Fix epilogue again

* adjust the sphere scaling name

* add the things

* Fix Ness being placed onto monotoli when monotoli was in sea of eden

* Fix prefill properly

* Fix boss shuffle on vanilla slots.

* rename this, apparently

* Update archipelago.json

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-19 14:52:27 +01:00

516 lines
20 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import struct
from ..Options import PSIShuffle
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from . import EarthBoundWorld
from .Rom import LocalRom
def shuffle_psi(world: "EarthBoundWorld") -> None:
world.offensive_psi_slots = [
"Special",
"Flash",
"Fire",
"Freeze",
"Thunder",
"Starstorm",
"Blast",
"Missile"
]
world.assist_psi_slots = [
"Hypnosis",
"Paralysis",
"Offense Up",
"Defense Down",
"Brainshock",
"Defense up",
"Drain",
"Disable",
"Stop",
"Neutralize"
]
world.shield_slots = [
"Shield",
"PSI Shield"
]
world.jeff_offense_items = []
world.jeff_assist_items = []
world.psi_address = {
"Special": [0x158A5F, 4],
"Flash": [0x158B4F, 4],
"Fire": [0x158A9B, 4],
"Freeze": [0x158AD7, 4],
"Thunder": [0x158B13, 4],
"Starstorm": [0x3503FC, 4],
"Shield": [0x158C21, 4],
"PSI Shield": [0x158C5D, 4],
"Hypnosis": [0x158CD5, 2],
"Paralysis": [0x158D11, 2],
"Offense Up": [0x158C99, 2],
"Defense Down": [0x158CB7, 2],
"Brainshock": [0x158D2F, 2],
"Blast": [0x35041A, 4],
"Missile": [0x350456, 4],
"Defense up": [0x350492, 2],
"Drain": [0x3504B0, 2],
"Disable": [0x3504Ce, 2],
"Stop": [0x3504EC, 2],
"Neutralize": [0x35050A, 2],
}
if world.options.psi_shuffle:
world.random.shuffle(world.offensive_psi_slots)
if world.options.psi_shuffle != PSIShuffle.option_extended:
adjust_psi_list(world.offensive_psi_slots, "Blast", 7)
adjust_psi_list(world.offensive_psi_slots, "Missile", 7)
if not world.options.allow_flash_as_favorite_thing:
if world.offensive_psi_slots[0] == "Flash":
adjust_psi_list(world.offensive_psi_slots, "Flash", world.random.randint(1, 5)) # Randomize which slot gets Flash
world.random.shuffle(world.assist_psi_slots)
if world.options.psi_shuffle != PSIShuffle.option_extended:
adjust_psi_list(world.assist_psi_slots, "Defense up", 10)
adjust_psi_list(world.assist_psi_slots, "Drain", 10)
adjust_psi_list(world.assist_psi_slots, "Disable", 10)
adjust_psi_list(world.assist_psi_slots, "Stop", 10)
adjust_psi_list(world.assist_psi_slots, "Neutralize", 10)
world.jeff_offense_items.extend(world.offensive_psi_slots[-2:])
world.jeff_assist_items.extend(world.assist_psi_slots[-5:])
world.offensive_psi_slots = world.offensive_psi_slots[:-2]
world.assist_psi_slots = world.assist_psi_slots[:-5]
world.random.shuffle(world.shield_slots)
shield_data = {key: world.psi_address[key] for key in world.shield_slots}
assist_data = {key: world.psi_address[key] for key in world.assist_psi_slots}
assist_data_plus = {key: world.psi_address[key] for key in world.jeff_assist_items}
offense_data_plus = {key: world.psi_address[key] for key in world.jeff_offense_items}
world.psi_address = {key: world.psi_address[key] for key in world.offensive_psi_slots}
world.psi_address.update(shield_data)
world.psi_address.update(assist_data)
world.psi_address.update(offense_data_plus)
world.psi_address.update(assist_data_plus)
world.psi_slot_data = [
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Special
[[0x09, 0x01], [0x0B, 0x01], [0x0D, 0x01], [0x0F, 0x01]], # Flash
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Fire
[[0x09, 0x01], [0x0B, 0x01], [0x0D, 0x01], [0x0F, 0x01]], # Freeze
[[0x09, 0x02], [0x0B, 0x02], [0x0D, 0x02], [0x0F, 0x02]], # Thunder
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Starstorm
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Shield
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # PSI Shield
[[0x09, 0x01], [0x0B, 0x01]], # Hypnosis
[[0x09, 0x02], [0x0B, 0x02]], # Paralysis
[[0x09, 0x01], [0x0B, 0x01]], # Offense Up
[[0x09, 0x02], [0x0B, 0x02]], # Defense Down
[[0x09, 0x01], [0x0B, 0x01]], # Brainshock
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Blast
[[0x09, 0x00], [0x0B, 0x00], [0x0D, 0x00], [0x0F, 0x00]], # Missile
[[0x09, 0x01], [0x0B, 0x01]], # Defense up
[[0x09, 0x02], [0x0B, 0x02]], # Drain
[[0x09, 0x01], [0x0B, 0x01]], # Disable
[[0x09, 0x02], [0x0B, 0x02]], # Stop
[[0x09, 0x01], [0x0B, 0x01]], # Neutralize
]
world.psi_level_data = [
[[0x08, 0x00, 0x00], [0x16, 0x00, 0x00], [0x31, 0x00, 0x00], [0x4B, 0x00, 0x00]], # Special
[[0x12, 0x00, 0x00], [0x26, 0x00, 0x00], [0x3D, 0x00, 0x00], [0x43, 0x00, 0x00]], # Flash
[[0x00, 0x03, 0x00], [0x00, 0x13, 0x00], [0x00, 0x25, 0x00], [0x00, 0x40, 0x00]], # Fire
[[0x00, 0x01, 0x01], [0x00, 0x0B, 0x01], [0x00, 0x1F, 0x21], [0x00, 0x2E, 0x00]], # Freeze
[[0x00, 0x08, 0x01], [0x00, 0x19, 0x01], [0x00, 0x39, 0x29], [0x00, 0x00, 0x37]], # Thunder
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Starstorm
[[0x0C, 0x00, 0x0E], [0x00, 0x00, 0x0F], [0x22, 0x00, 0x10], [0x00, 0x00, 0x33]], # Shield
[[0x00, 0x06, 0x00], [0x00, 0x1B, 0x00], [0x00, 0x33, 0x00], [0x00, 0x3C, 0x00]], # PSI Shield
[[0x04, 0x00, 0x00], [0x1B, 0x00, 0x00]], # Hypnosis
[[0x0E, 0x00, 0x00], [0x1D, 0x00, 0x00]], # Paralysis
[[0x00, 0x15, 0x00], [0x00, 0x28, 0x00]], # Offense Up
[[0x00, 0x1D, 0x00], [0x00, 0x36, 0x00]], # Defense Down
[[0x00, 0x00, 0x18], [0x00, 0x00, 0x2C]], # Brainshock
# Level-up data needs to be zeroed out for these slots
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Blast
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Missile
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Defense up
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Drain
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Disable
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00]], # Stop
[[0x00, 0x00, 0x00], [0x00, 0x00, 0x00]] # Neutralize
]
world.bomb_names = {
"Special": ["Psycho bomb", "Mad psycho bomb", "Psywave emitter", "Psywave blaster", "Broken radio"],
"Flash": ["Smoke bomb", "Flashbang", "Flash pan", "Digital camera", "Broken camera"],
"Freeze": ["Ice bomb", "Dry ice bomb", "Frost ray", "Freeze ray", "Broken minifridge"],
"Fire": ["Fire bomb", "Napalm bomb", "Blowtorch", "Flamethrower", "Broken grill"],
"Thunder": ["Electric bomb", "EMP bomb", "Shock coil", "Tesla coil", "Broken spring"],
"Starstorm": ["Comet bomb", "Nova bomb", "Meteor radar", "Star radar", "Broken radar"],
"Blast": ["Bomb", "Super bomb", "Bazooka", "Heavy bazooka", "Broken bazooka"],
"Missile": ["Rocket", "Nitro rocket", "Missile launcher", "Nitro launcher", "Broken vacuum"]
}
world.rocket_names = {
"Special": ["Psionic shard", "Psionic orb", "Psionic crystal"],
"Flash": ["Flashbulb", "Bright bulb", "Magna bulb"],
"Freeze": ["LN2 bottle", "LN2 jug", "LN2 bucket"],
"Fire": ["Flare", "Big flare", "Blitz flare"],
"Thunder": ["Sparkler", "Big sparkler", "Mega sparkler"],
"Starstorm": ["Meteor missile", "Star missile", "Nova missile"],
"Blast": ["Firecracker", "Big firecracker", "Super firecracker"],
"Missile": ["Bottle rocket", "Big bottle rocket", "Multibottle rocket"]
}
world.spray_names = {
"Hypnosis": "Chloroform spray",
"Paralysis": "Nerve spray",
"Offense Up": "Offense spray",
"Defense Down": "Weakness spray",
"Brainshock": "Confusion spray",
"Defense up": "Defense spray",
"Drain": "HP-straw",
"Disable": "Distraction spray",
"Stop": "Slime spray",
"Neutralize": "Shield-off spray"
}
world.broken_gadgets = {
"Hypnosis": ["Broken watch", "Broken screen"],
"Paralysis": ["Broken razor", "Broken fan"],
"Offense Up": ["Broken faucet", "Broken tuba"],
"Defense Down": ["Broken sprinkler", "Broken trombone"],
"Brainshock": ["Broken toaster", "Broken fryer"],
"Defense up": ["Broken nozzle", "Broken trumpet"],
"Drain": ["Broken hose", "Broken tube"],
"Disable": ["Broken machine", "Broken device"],
"Stop": ["Broken iron", "Broken steamer"],
"Neutralize": ["Broken pipe", "Broken board"]
}
world.broken_desc = {
"Hypnosis": [0x00EEEBA4, 0x00EEEBCC],
"Paralysis": [0x00EEEC06, 0x00EEEC28],
"Offense Up": [0x00EEEC4D, 0x00EEEC75],
"Defense Down": [0x00EEECA5, 0x00EEECCB],
"Brainshock": [0x00EEED00, 0x00EEED2B],
"Defense up": [0x00EEED5A, 0x00C53929],
"Drain": [0x00EEED8A, 0x00C538E0],
"Disable": [0x00C53772, 0x00EEEDB2],
"Stop": [0x00C53870, 0x00EEEE03],
"Neutralize": [0x00C53897, 0x00EEEE2F]
}
world.gadget_names = {
"Hypnosis": ["Hypno pendulum", "Hypno screen"],
"Paralysis": ["Nerve taser", "Nerve ray"],
"Offense Up": ["Offensalizer", "Offense shower"],
"Defense Down": ["Weakalizer", "Weakness shower"],
"Brainshock": ["Mind jammer", "Mind fryer"],
"Defense up": ["Defensalizer", "Defense shower"],
"Drain": ["HP-sucker", "Hungry HP-sucker"],
"Disable": ["Counter-PSI unit", "PSI-nullifier unit"],
"Stop": ["Slime generator", "Slime blaster"],
"Neutralize": ["Shield killer", "Neutralizer"]
}
world.starstorm_address = {
"Special": [0x002D, 0x003C],
"Flash": [0x011D, 0x012C],
"Fire": [0x0069, 0x0078],
"Freeze": [0x00A5, 0x00B4],
"Thunder": [0x00E1, 0x00F0],
"Starstorm": [0x013B, 0x014A],
"Blast": [0x0438, 0x0447],
"Missile": [0x0474, 0x0483]
}
world.starstorm_spell_id = {
"Special": [0x03, 0x04],
"Flash": [0x13, 0x14],
"Fire": [0x07, 0x08],
"Freeze": [0x0B, 0x0C],
"Thunder": [0x0F, 0x10],
"Starstorm": [0x15, 0x16],
"Blast": [0x48, 0x49],
"Missile": [0x4C, 0x4D]
}
world.jeff_addresses = [
0x156665, # Bomb
0x15668C, # Super Bomb
0x156443, # Bazooka
0x15646A, # Heavy bazooka
0x1551FB, # broken bazooka
0x1565F0, # Bottle Rocket
0x156617, # Big Bottle Rocket
0x15663E, # multi Bottle Rocket
]
world.gadget_addresses = [
[0, 0x1567EB], # defense shower
[0x156491, 0x1564B8], # HP-Sucker
[0x1563F5], # Counter-PSI Unit
[0x156506], # Slime Generator
[0x15641C, 0x156DB5], # Shield Killer
]
world.broken_gadget_addresses = [
0x155222,
0x1551D4,
0x15509C,
0x15515F,
0x155186
]
world.bomb_desc = {
"Special": [0x00EED4D8, 0x00EED521, 0x00EEDA4F, 0x00EEDA6B, 0x00EEDCFB],
"Flash": [0x00EED538, 0x00EED5AB, 0x00EEDA87, 0x00EEDAD7, 0x00EEDD1D],
"Fire": [0x00EED659, 0x00EED6CC, 0x00EEDB37, 0x00EEDB68, 0x00EEDD40],
"Freeze": [0x00EED744, 0x00EED79D, 0x00EEDB85, 0x00EEDBA2, 0x00EEDD64],
"Thunder": [0x00EED822, 0x00EED88E, 0x00EEDBBF, 0x00EEDBE4, 0x00EEDDA0],
"Starstorm": [0x00EED4D8, 0x00EED521, 0x00EEDA4F, 0x00EEDCD2, 0x00EEDDC3],
"Blast": [0x00C54EA7, 0x00C54EF7, 0x00C54AA1, 0x00C54AF5, 0x00C53908],
"Missile": [0x00EED9A5, 0x00EED9FF, 0x00EEDC09, 0x00EEDC40, 0x00EEDDEE]
}
world.rocket_desc = {
"Special": [0x00EEDE25, 0x00EEDE41, 0x00EEDE80],
"Flash": [0x00EEDEDC, 0x00EEDF37, 0x00EEDFAE],
"Fire": [0x00EEE013, 0x00EEE031, 0x00EEE061],
"Freeze": [0x00EEE098, 0x00EEE0B5, 0x00EEE11E],
"Thunder": [0x00EEE190, 0x00EEE1B6, 0x00EEE220],
"Starstorm": [0x00EEE28B, 0x00EEE2A7, 0x00EEE2DB],
"Blast": [0x00EEE344, 0x00EEE35B, 0x00EEE36E],
"Missile": [0x00C54E01, 0x00C54E20, 0x00C54E54]
}
world.spray_desc = {
"Hypnosis": 0x00EEE653,
"Paralysis": 0x00EEE688,
"Offense Up": 0x00EEE6B9,
"Defense Down": 0x00EEE705,
"Brainshock": 0x00EEE751,
"Defense up": 0x00C2558D,
"Drain": 0x00EEE802,
"Disable": 0x00EEE838,
"Stop": 0x00EEE7D0,
"Neutralize": 0x00EEE78F
}
world.gadget_desc = {
"Hypnosis": [0x00EEE87B, 0x00EEE8AA],
"Paralysis": [0x00EEE8DA, 0x00EEE905],
"Offense Up": [0x00EEE933, 0x00EEE97F],
"Defense Down": [0x00EEE9C2, 0x00EEEA0E],
"Brainshock": [0x00EEEA9D, 0x00EEEAD2],
"Defense up": [0x00EEEA51, 0x00C5519F],
"Drain": [0x00C54B67, 0x00C54BB0],
"Disable": [0x00C54A3A, 0x00EEEB5E],
"Stop": [0x00C54C32, 0x00EEEB09],
"Neutralize": [0x00C54A6C, 0x00C559D9]
}
world.bomb_actions = {
"Special": [0x01AC, 0x01AD, 0x01CF, 0x01D0],
"Flash": [0x01AE, 0x01AF, 0x01D1, 0x01D2],
"Fire": [0x01B0, 0x01B1, 0x01D3, 0x01D4],
"Freeze": [0x01B2, 0x01B3, 0x01D5, 0x01D6],
"Thunder": [0x01B4, 0x01B5, 0x01D7, 0x01D8],
"Starstorm": [0x01B6, 0x01B7, 0x01D9, 0x01DA],
"Blast": [0x00A7, 0x00A8, 0x0136, 0x0137],
"Missile": [0x01B8, 0x01B9, 0x01DB, 0x01DC]
}
world.missile_actions = {
"Special": [0x01BA, 0x01BB, 0x01BC],
"Flash": [0x01BD, 0x01BE, 0x01BF],
"Fire": [0x01C0, 0x01C1, 0x01C2],
"Freeze": [0x01C3, 0x01C4, 0x01C5],
"Thunder": [0x01C6, 0x01C7, 0x01C8],
"Starstorm": [0x01C9, 0x01CA, 0x01CB],
"Blast": [0x01CC, 0x01CD, 0x01CE],
"Missile": [0x00A3, 0x00A4, 0x00A5]
}
world.gadget_actions = {
"Hypnosis": [0x01E7, 0x01E8],
"Paralysis": [0x01E9, 0x01EA],
"Offense Up": [0x01EB, 0x01EC],
"Defense Down": [0x01ED, 0x01EE],
"Brainshock": [0x01EF, 0x01F0],
"Defense up": [0x00B7, 0x00B8],
"Drain": [0x00A1, 0x00B0],
"Disable": [0x009F, 0x01F1],
"Stop": [0x00A9, 0x01F2],
"Neutralize": [0x00A0, 0x00F7]
}
world.jeff_item_counts = [
5, # Bomb
3 # Bottle Rocket
]
world.gadget_counts = [
1, # defense shower
2, # HP-Sucker
1, # Counter PSI unit
1, # Slime generator
2 # Neutralizer
]
world.gadget_ids = [
[0x00, 0x9D],
[0x87, 0x88],
[0x83],
[0x8A],
[0x84, 0xC3]
]
world.broken_gadget_ids = [
0x0E, # Broken trumpet
0x0C, # Broken tube
0x04, # Broken machine
0x09, # Broken iron
0x0A # Broken pipe
]
world.jeff_item_names = [
world.bomb_names,
world.rocket_names
]
world.jeff_help_text = [
world.bomb_desc,
world.rocket_desc
]
world.attack_types = [
world.bomb_actions,
world.missile_actions
]
def write_psi(world: "EarthBoundWorld", rom: "LocalRom") -> None:
from ..game_data.text_data import text_encoder
psi_num = 0
for spell, (address, levels) in world.psi_address.items():
for i in range(levels):
rom.write_bytes(address + 9, bytearray(world.psi_slot_data[psi_num][i]))
rom.write_bytes(address + 6, bytearray(world.psi_level_data[psi_num][i]))
if psi_num == 0:
rom.write_bytes(address, bytearray([0x01]))
elif psi_num == 5 and i > 1:
rom.write_bytes(0x01C4AB + (0x9E * (i - 2)), struct.pack("H", world.starstorm_address[spell][i - 2])) # Menu spells
rom.write_bytes(0x01C536 + (0x78 * (i - 2)), bytearray([world.starstorm_spell_id[spell][i - 2]])) # What spell is controlled by the PSI flags
rom.write_bytes(0x2E957F + (0x11 * (i - 2)), bytearray([world.starstorm_spell_id[spell][i - 2]])) # The global Poo PSI text
rom.write_bytes(address + 9, bytearray(world.psi_slot_data[psi_num][i - 2]))
if spell == "Special" and psi_num != 0:
rom.write_bytes(address, bytearray([0x12]))
address += 15
if spell == "Starstorm" and i == 1:
address = 0x158B8B
# todo; expanded psi
# todo; animation for Starstorm L/D
# todo; swap enemy actions for Special?
# todo; cleanup stuff
psi_num += 1
# rom.write_bytes(0x2E957F + (0x11 * (i - 2)), bytearray([world.starstorm_spell_id[spell][i - 2]]))
# Starstorm spell for the item locally
rom.write_bytes(0x2EAE2E, bytearray([world.starstorm_spell_id[world.offensive_psi_slots[5]][0]]))
rom.write_bytes(0x2EAE38, bytearray([world.starstorm_spell_id[world.offensive_psi_slots[5]][1]]))
jeff_item_num = 0
jeff_item_index = 0
for item in world.jeff_offense_items:
for i in range(world.jeff_item_counts[jeff_item_num]):
address = world.jeff_addresses[jeff_item_index]
jeff_item_index += 1
name = world.jeff_item_names[jeff_item_num][item][i]
description = world.jeff_help_text[jeff_item_num][item][i]
name_encoded = text_encoder(name, 22)
name_encoded.extend(([0x00]))
rom.write_bytes(address, name_encoded)
rom.write_bytes(address + 35, struct.pack("I", description))
if "Broken" not in name: # broken items don't need attack data
attack = world.attack_types[jeff_item_num][item][i]
rom.write_bytes(address + 29, struct.pack("H", attack))
jeff_item_num += 1
jeff_item_num = 0
name = world.spray_names[world.jeff_assist_items[0]]
name_encoded = text_encoder(name, 22)
name_encoded.extend(([0x00]))
description = world.spray_desc[world.jeff_assist_items[0]]
address = 0x156887
action = world.gadget_actions[world.jeff_assist_items[0]][0]
rom.write_bytes(address, name_encoded)
rom.write_bytes(address + 35, struct.pack("I", description))
rom.write_bytes(address + 29, struct.pack("H", action))
for item in world.jeff_assist_items:
for i in range(world.gadget_counts[jeff_item_num]):
if jeff_item_num == 0:
i = 1
name = world.gadget_names[item][i]
name_encoded = text_encoder(name, 22)
name_encoded.extend(([0x00]))
description = world.gadget_desc[item][i]
action = world.gadget_actions[world.jeff_assist_items[jeff_item_num]][i]
address = world.gadget_addresses[jeff_item_num][i]
rom.write_bytes(address, name_encoded)
rom.write_bytes(address + 35, struct.pack("I", description))
rom.write_bytes(address + 29, struct.pack("H", action))
rom.write_bytes(description - 0xC00000 + 5, bytearray([world.gadget_ids[jeff_item_num][i]]))
jeff_item_num += 1
for i in range(5):
item = world.jeff_assist_items[i]
if i < 2:
level = 1
else:
level = 0
address = world.broken_gadget_addresses[i]
name = world.broken_gadgets[item][level]
description = world.broken_desc[item][level]
name_encoded = text_encoder(name, 22)
name_encoded.extend(([0x00]))
rom.write_bytes(address, name_encoded)
rom.write_bytes(address + 35, struct.pack("I", description))
rom.write_bytes(description - 0xC00000 + 5, bytearray([world.broken_gadget_ids[i]]))
rom.write_bytes(0x15A8EB, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[4]][1])))
rom.write_bytes(0x15BB45, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[0]][0])))
rom.write_bytes(0x15BBA5, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[4]][0])))
rom.write_bytes(0x15DF41, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[4]][0])))
rom.write_bytes(0x15DF3F, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[4]][1])))
rom.write_bytes(0x15BA2B, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[1]][0])))
rom.write_bytes(0x15C06D, bytearray(struct.pack("H", world.gadget_actions[world.jeff_assist_items[1]][1])))
def adjust_psi_list(psi_input: list[str], spell: str, index: int) -> None:
"""Move a spell in the PSI table to a different entry/slot"""
psi_input.insert(index, (psi_input.pop(psi_input.index(spell))))