Random sprite on hit now part of basepatch. Other events possible too.

This commit is contained in:
CaitSith2 2020-10-04 10:57:30 -07:00
parent 104f780873
commit 38ac943a9c
5 changed files with 103 additions and 44 deletions

43
Gui.py
View File

@ -138,7 +138,10 @@ def guiMain(args=None):
sprite = None
def set_sprite(sprite_param):
nonlocal sprite
if sprite_param is None or not sprite_param.valid:
if isinstance(sprite_param, str):
sprite = sprite_param
spriteNameVar.set(sprite_param)
elif sprite_param is None or not sprite_param.valid:
sprite = None
spriteNameVar.set('(unchanged)')
else:
@ -1409,7 +1412,31 @@ class SpriteSelector(object):
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
button.pack(side=LEFT, padx=(0, 5))
button = Button(frame, text="Random sprite", command=self.use_random_sprite)
self.randomButtonText = StringVar()
button = Button(frame, textvariable=self.randomButtonText, command=self.use_random_sprite)
button.pack(side=LEFT, padx=(0, 5))
self.randomButtonText.set("Random")
self.randomOnEventText = StringVar()
self.randomOnHitVar = IntVar()
self.randomOnEnterVar = IntVar()
self.randomOnExitVar = IntVar()
self.randomOnSlashVar = IntVar()
self.randomOnItemVar = IntVar()
button = Checkbutton(frame, text="Hit", command=self.update_random_button, variable=self.randomOnHitVar)
button.pack(side=LEFT, padx=(0, 5))
button = Checkbutton(frame, text="Enter", command=self.update_random_button, variable=self.randomOnEnterVar)
button.pack(side=LEFT, padx=(0, 5))
button = Checkbutton(frame, text="Exit", command=self.update_random_button, variable=self.randomOnExitVar)
button.pack(side=LEFT, padx=(0, 5))
button = Checkbutton(frame, text="Slash", command=self.update_random_button, variable=self.randomOnSlashVar)
button.pack(side=LEFT, padx=(0, 5))
button = Checkbutton(frame, text="Item", command=self.update_random_button, variable=self.randomOnItemVar)
button.pack(side=LEFT, padx=(0, 5))
if adjuster:
@ -1574,8 +1601,18 @@ class SpriteSelector(object):
self.callback(Sprite.default_link_sprite())
self.window.destroy()
def update_random_button(self):
randomon = "-hit" if self.randomOnHitVar.get() else ""
randomon += "-enter" if self.randomOnEnterVar.get() else ""
randomon += "-exit" if self.randomOnExitVar.get() else ""
randomon += "-slash" if self.randomOnSlashVar.get() else ""
randomon += "-item" if self.randomOnItemVar.get() else ""
self.randomOnEventText.set(f"randomon{randomon}" if randomon else None)
self.randomButtonText.set("Random On Event" if randomon else "Random")
def use_random_sprite(self):
self.callback(random.choice(self.all_sprites) if self.all_sprites else None)
randomon = self.randomOnEventText.get()
self.callback(randomon if randomon else (random.choice(self.all_sprites) if self.all_sprites else None))
self.window.destroy()
def select_sprite(self, spritename):

View File

@ -177,10 +177,9 @@ def main(args, seed=None):
rom_names = []
def _gen_rom(team: int, player: int):
sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player]
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
or world.shufflepots[player] or sprite_random_on_hit or world.bush_shuffle[player]
or world.shufflepots[player] or world.bush_shuffle[player]
or world.killable_thieves[player] or world.tile_shuffle[player])
rom = LocalRom(args.rom)
@ -188,8 +187,7 @@ def main(args, seed=None):
patch_rom(world, rom, player, team, use_enemizer)
if use_enemizer:
patch_enemizer(world, player, rom, args.enemizercli,
sprite_random_on_hit)
patch_enemizer(world, player, rom, args.enemizercli)
if args.race:
patch_race_rom(rom)
@ -198,7 +196,7 @@ def main(args, seed=None):
apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player],
args.fastmenu[player], args.disablemusic[player], args.sprite[player],
args.ow_palettes[player], args.uw_palettes[player], world, player)
args.ow_palettes[player], args.uw_palettes[player], world, player, True)
mcsb_name = ''
if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],

89
Rom.py
View File

@ -1,5 +1,5 @@
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '45a7732cfb056a251285fcb14e9bb8a7'
RANDOMIZERBASEHASH = 'f71376f57dfd3d69eaac96f2f391ff64'
import io
import json
@ -59,15 +59,6 @@ class LocalRom(object):
self.buffer[startaddress:startaddress + len(values)] = values
def write_to_file(self, file, hide_enemizer=False):
if hide_enemizer:
extra_zeroes = 0x400000 - len(self.buffer)
if extra_zeroes > 0:
buffer = self.buffer + bytes([0x00] * extra_zeroes)
with open(file, 'wb') as outfile:
outfile.write(buffer)
return
with open(file, 'wb') as outfile:
outfile.write(self.buffer)
@ -106,7 +97,7 @@ class LocalRom(object):
'Supplied Base Rom does not match known MD5 for JAP(1.0) release. Will try to patch anyway.')
# extend to 2MB
self.buffer.extend(bytearray([0x00]) * (0x200000 - len(self.buffer)))
self.buffer.extend(bytearray([0x00]) * (0x400000 - len(self.buffer)))
# load randomizer patches
with open(local_path('data', 'base2current.json')) as stream:
@ -196,7 +187,50 @@ def check_enemizer(enemizercli):
check_enemizer.done = True
def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite_on_hit: bool):
def apply_random_sprite_on_event(rom: LocalRom, sprite, local_random, allow_random_on_event):
onevent = onhit = 0
sprites = list()
if not allow_random_on_event:
allow_random_on_event = not rom.read_byte(0x186381) # Check if explicitly disabled in rom. If so, it stays that way.
if sprite and not isinstance(sprite, Sprite):
sprite = sprite.lower()
if sprite.startswith('randomon'):
onevent = onhit = 0x01 if 'hit' in sprite else 0x00
onevent += 0x02 if 'enter' in sprite else 0x00
onevent += 0x04 if 'exit' in sprite else 0x00
onevent += 0x08 if 'slash' in sprite else 0x00
onevent += 0x10 if 'item' in sprite else 0x00
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite, local_random)
# write link sprite if required
if sprite:
sprite.write_to_rom(rom)
if allow_random_on_event:
rom.write_int16(0x18637F, onevent)
rom.write_byte(0x186381, 0x00) # Enable usage of Random On Event.
if rom.read_byte(0x200000):
rom.write_byte(0x200103, onhit)
_populate_sprite_table()
if onevent:
sprites = list(set(_sprite_table.values())) # convert to list and remove dupes
else:
sprites.append(sprite)
if sprites:
while len(sprites) < 32:
sprites.extend(sprites)
local_random.shuffle(sprites)
for i, sprite in enumerate(sprites[:32]):
if not i and not onevent:
continue
rom.write_bytes(0x300000 + (i * 0x8000), sprite.sprite)
rom.write_bytes(0x307000 + (i * 0x8000), sprite.palette)
rom.write_bytes(0x307078 + (i * 0x8000), sprite.glove_palette)
def patch_enemizer(world, player: int, rom: LocalRom, enemizercli):
check_enemizer(enemizercli)
randopatch_path = os.path.abspath(output_path(f'enemizer_randopatch_{player}.sfc'))
options_path = os.path.abspath(output_path(f'enemizer_options_{player}.json'))
@ -258,7 +292,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
'RandomizeTileTrapPattern': world.tile_shuffle[player],
'RandomizeTileTrapFloorTile': False,
'AllowKillableThief': world.killable_thieves[player],
'RandomizeSpriteOnHit': random_sprite_on_hit,
'RandomizeSpriteOnHit': False,
'DebugMode': False,
'DebugForceEnemy': False,
'DebugForceEnemyId': 0,
@ -334,19 +368,6 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
rom.write_byte(0x04DE81, 6)
rom.write_byte(0x200101, 0) # Do not close boss room door on entry.
if random_sprite_on_hit:
_populate_sprite_table()
sprites = list(set(_sprite_table.values())) # convert to list and remove dupes
if sprites:
while len(sprites) < 32:
sprites.extend(sprites)
world.rom_seeds[player].shuffle(sprites)
for i, sprite in enumerate(sprites[:32]):
rom.write_bytes(0x300000 + (i * 0x8000), sprite.sprite)
rom.write_bytes(0x307000 + (i * 0x8000), sprite.palette)
rom.write_bytes(0x307078 + (i * 0x8000), sprite.glove_palette)
for used in (randopatch_path, options_path):
try:
os.remove(used)
@ -376,7 +397,7 @@ def _populate_sprite_table():
def get_sprite_from_name(name, local_random=random):
_populate_sprite_table()
name = name.lower()
if name in ['random', 'randomonhit']:
if name.startswith('random'):
return local_random.choice(list(_sprite_table.values()))
return _sprite_table.get(name, None)
@ -411,7 +432,7 @@ class Sprite(object):
self.sprite = filedata[:0x7000]
self.palette = filedata[0x7000:0x7078]
self.glove_palette = filedata[0x7078:]
elif len(filedata) in [0x100000, 0x200000]:
elif len(filedata) in [0x100000, 0x200000, 0x400000]:
# full rom with patched sprite, extract it
self.sprite = filedata[0x80000:0x87000]
self.palette = filedata[0xDD308:0xDD380]
@ -546,6 +567,9 @@ class Sprite(object):
rom.write_bytes(0x80000, self.sprite)
rom.write_bytes(0xDD308, self.palette)
rom.write_bytes(0xDEDF5, self.glove_palette)
rom.write_bytes(0x300000, self.sprite)
rom.write_bytes(0x307000, self.palette)
rom.write_bytes(0x307078, self.glove_palette)
def patch_rom(world, rom, player, team, enemized):
local_random = world.rom_seeds[player]
@ -1460,10 +1484,9 @@ def hud_format_text(text):
return output[:32]
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, ow_palettes, uw_palettes, world=None, player=1):
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, ow_palettes, uw_palettes, world=None, player=1, allow_random_on_event=False):
local_random = random if not world else world.rom_seeds[player]
if sprite and not isinstance(sprite, Sprite):
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite, local_random)
apply_random_sprite_on_event(rom, sprite, local_random, allow_random_on_event)
# enable instant item menu
if fastmenu == 'instant':
@ -1514,10 +1537,6 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
rom.write_byte(0x6FA30, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
rom.write_byte(0x65561, {'red': 0x05, 'blue': 0x0D, 'green': 0x19, 'yellow': 0x09}[color])
# write link sprite if required
if sprite:
sprite.write_to_rom(rom)
# reset palette if it was adjusted already
default_ow_palettes(rom)
default_uw_palettes(rom)

Binary file not shown.

View File

@ -288,7 +288,12 @@ debug: # Only available if the host uses the doors branch, it is ignored otherwi
rom:
sprite: # Enter the name of your preferred sprite and weight it appropriately
random: 0
randomonhit: 0
randomonhit: 0 # Random sprite on hit
randomonenter: 0 # Random sprite on entering the underworld.
randomonexit: 0 # Random sprite on exiting the underworld.
randomonslash: 0 # Random sprite on sword slashes
randomonitem: 0 # Random sprite on getting items.
# You can combine these events like this. randomonhit-enter-exit if you want it on hit, enter, exit.
Link: 50 # To add other sprites: open the gui/Creator, go to adjust, select a sprite and write down the name the gui calls it
disablemusic: # If "on", all in-game music will be disabled
on: 0