forked from mirror/Archipelago
* 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>
516 lines
20 KiB
Python
516 lines
20 KiB
Python
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", "Multi bottle 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))))
|