Random sprite on hit now part of basepatch. Other events possible too.
This commit is contained in:
parent
104f780873
commit
38ac943a9c
43
Gui.py
43
Gui.py
|
@ -138,7 +138,10 @@ def guiMain(args=None):
|
||||||
sprite = None
|
sprite = None
|
||||||
def set_sprite(sprite_param):
|
def set_sprite(sprite_param):
|
||||||
nonlocal sprite
|
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
|
sprite = None
|
||||||
spriteNameVar.set('(unchanged)')
|
spriteNameVar.set('(unchanged)')
|
||||||
else:
|
else:
|
||||||
|
@ -1409,7 +1412,31 @@ class SpriteSelector(object):
|
||||||
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
|
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
|
||||||
button.pack(side=LEFT, padx=(0, 5))
|
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))
|
button.pack(side=LEFT, padx=(0, 5))
|
||||||
|
|
||||||
if adjuster:
|
if adjuster:
|
||||||
|
@ -1574,8 +1601,18 @@ class SpriteSelector(object):
|
||||||
self.callback(Sprite.default_link_sprite())
|
self.callback(Sprite.default_link_sprite())
|
||||||
self.window.destroy()
|
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):
|
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()
|
self.window.destroy()
|
||||||
|
|
||||||
def select_sprite(self, spritename):
|
def select_sprite(self, spritename):
|
||||||
|
|
8
Main.py
8
Main.py
|
@ -177,10 +177,9 @@ def main(args, seed=None):
|
||||||
rom_names = []
|
rom_names = []
|
||||||
|
|
||||||
def _gen_rom(team: int, player: int):
|
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]
|
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.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])
|
or world.killable_thieves[player] or world.tile_shuffle[player])
|
||||||
|
|
||||||
rom = LocalRom(args.rom)
|
rom = LocalRom(args.rom)
|
||||||
|
@ -188,8 +187,7 @@ def main(args, seed=None):
|
||||||
patch_rom(world, rom, player, team, use_enemizer)
|
patch_rom(world, rom, player, team, use_enemizer)
|
||||||
|
|
||||||
if use_enemizer:
|
if use_enemizer:
|
||||||
patch_enemizer(world, player, rom, args.enemizercli,
|
patch_enemizer(world, player, rom, args.enemizercli)
|
||||||
sprite_random_on_hit)
|
|
||||||
|
|
||||||
if args.race:
|
if args.race:
|
||||||
patch_race_rom(rom)
|
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],
|
apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player],
|
||||||
args.fastmenu[player], args.disablemusic[player], args.sprite[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 = ''
|
mcsb_name = ''
|
||||||
if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],
|
if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],
|
||||||
|
|
89
Rom.py
89
Rom.py
|
@ -1,5 +1,5 @@
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = '45a7732cfb056a251285fcb14e9bb8a7'
|
RANDOMIZERBASEHASH = 'f71376f57dfd3d69eaac96f2f391ff64'
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
|
@ -59,15 +59,6 @@ class LocalRom(object):
|
||||||
self.buffer[startaddress:startaddress + len(values)] = values
|
self.buffer[startaddress:startaddress + len(values)] = values
|
||||||
|
|
||||||
def write_to_file(self, file, hide_enemizer=False):
|
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:
|
with open(file, 'wb') as outfile:
|
||||||
outfile.write(self.buffer)
|
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.')
|
'Supplied Base Rom does not match known MD5 for JAP(1.0) release. Will try to patch anyway.')
|
||||||
|
|
||||||
# extend to 2MB
|
# extend to 2MB
|
||||||
self.buffer.extend(bytearray([0x00]) * (0x200000 - len(self.buffer)))
|
self.buffer.extend(bytearray([0x00]) * (0x400000 - len(self.buffer)))
|
||||||
|
|
||||||
# load randomizer patches
|
# load randomizer patches
|
||||||
with open(local_path('data', 'base2current.json')) as stream:
|
with open(local_path('data', 'base2current.json')) as stream:
|
||||||
|
@ -196,7 +187,50 @@ def check_enemizer(enemizercli):
|
||||||
check_enemizer.done = True
|
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)
|
check_enemizer(enemizercli)
|
||||||
randopatch_path = os.path.abspath(output_path(f'enemizer_randopatch_{player}.sfc'))
|
randopatch_path = os.path.abspath(output_path(f'enemizer_randopatch_{player}.sfc'))
|
||||||
options_path = os.path.abspath(output_path(f'enemizer_options_{player}.json'))
|
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],
|
'RandomizeTileTrapPattern': world.tile_shuffle[player],
|
||||||
'RandomizeTileTrapFloorTile': False,
|
'RandomizeTileTrapFloorTile': False,
|
||||||
'AllowKillableThief': world.killable_thieves[player],
|
'AllowKillableThief': world.killable_thieves[player],
|
||||||
'RandomizeSpriteOnHit': random_sprite_on_hit,
|
'RandomizeSpriteOnHit': False,
|
||||||
'DebugMode': False,
|
'DebugMode': False,
|
||||||
'DebugForceEnemy': False,
|
'DebugForceEnemy': False,
|
||||||
'DebugForceEnemyId': 0,
|
'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(0x04DE81, 6)
|
||||||
rom.write_byte(0x200101, 0) # Do not close boss room door on entry.
|
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):
|
for used in (randopatch_path, options_path):
|
||||||
try:
|
try:
|
||||||
os.remove(used)
|
os.remove(used)
|
||||||
|
@ -376,7 +397,7 @@ def _populate_sprite_table():
|
||||||
def get_sprite_from_name(name, local_random=random):
|
def get_sprite_from_name(name, local_random=random):
|
||||||
_populate_sprite_table()
|
_populate_sprite_table()
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
if name in ['random', 'randomonhit']:
|
if name.startswith('random'):
|
||||||
return local_random.choice(list(_sprite_table.values()))
|
return local_random.choice(list(_sprite_table.values()))
|
||||||
return _sprite_table.get(name, None)
|
return _sprite_table.get(name, None)
|
||||||
|
|
||||||
|
@ -411,7 +432,7 @@ class Sprite(object):
|
||||||
self.sprite = filedata[:0x7000]
|
self.sprite = filedata[:0x7000]
|
||||||
self.palette = filedata[0x7000:0x7078]
|
self.palette = filedata[0x7000:0x7078]
|
||||||
self.glove_palette = filedata[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
|
# full rom with patched sprite, extract it
|
||||||
self.sprite = filedata[0x80000:0x87000]
|
self.sprite = filedata[0x80000:0x87000]
|
||||||
self.palette = filedata[0xDD308:0xDD380]
|
self.palette = filedata[0xDD308:0xDD380]
|
||||||
|
@ -546,6 +567,9 @@ class Sprite(object):
|
||||||
rom.write_bytes(0x80000, self.sprite)
|
rom.write_bytes(0x80000, self.sprite)
|
||||||
rom.write_bytes(0xDD308, self.palette)
|
rom.write_bytes(0xDD308, self.palette)
|
||||||
rom.write_bytes(0xDEDF5, self.glove_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):
|
def patch_rom(world, rom, player, team, enemized):
|
||||||
local_random = world.rom_seeds[player]
|
local_random = world.rom_seeds[player]
|
||||||
|
@ -1460,10 +1484,9 @@ def hud_format_text(text):
|
||||||
return output[:32]
|
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]
|
local_random = random if not world else world.rom_seeds[player]
|
||||||
if sprite and not isinstance(sprite, Sprite):
|
apply_random_sprite_on_event(rom, sprite, local_random, allow_random_on_event)
|
||||||
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite, local_random)
|
|
||||||
|
|
||||||
# enable instant item menu
|
# enable instant item menu
|
||||||
if fastmenu == 'instant':
|
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(0x6FA30, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
rom.write_byte(0x65561, {'red': 0x05, 'blue': 0x0D, 'green': 0x19, 'yellow': 0x09}[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
|
# reset palette if it was adjusted already
|
||||||
default_ow_palettes(rom)
|
default_ow_palettes(rom)
|
||||||
default_uw_palettes(rom)
|
default_uw_palettes(rom)
|
||||||
|
|
Binary file not shown.
|
@ -288,7 +288,12 @@ debug: # Only available if the host uses the doors branch, it is ignored otherwi
|
||||||
rom:
|
rom:
|
||||||
sprite: # Enter the name of your preferred sprite and weight it appropriately
|
sprite: # Enter the name of your preferred sprite and weight it appropriately
|
||||||
random: 0
|
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
|
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
|
disablemusic: # If "on", all in-game music will be disabled
|
||||||
on: 0
|
on: 0
|
||||||
|
|
Loading…
Reference in New Issue