Sprites are now player specific, can be chosen from their sprite name rather than file path, support "random" choice and support "randomonhit" enemizer-only option
This commit is contained in:
parent
feb925d2b1
commit
5db7e066da
|
@ -6,6 +6,7 @@ import textwrap
|
|||
import sys
|
||||
|
||||
from AdjusterMain import adjust
|
||||
from Rom import get_sprite_from_name
|
||||
|
||||
class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
|
||||
|
||||
|
@ -48,8 +49,8 @@ def main():
|
|||
if not os.path.isfile(args.rom):
|
||||
input('Could not find valid rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom)
|
||||
sys.exit(1)
|
||||
if args.sprite is not None and not os.path.isfile(args.sprite):
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.' % args.sprite)
|
||||
if args.sprite is not None and not os.path.isfile(args.sprite) and not get_sprite_from_name(args.sprite):
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.')
|
||||
sys.exit(1)
|
||||
|
||||
# set up logger
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import os
|
||||
import re
|
||||
import time
|
||||
import logging
|
||||
|
||||
from Utils import output_path, parse_names_string
|
||||
from Rom import LocalRom, Sprite, apply_rom_settings
|
||||
from Rom import LocalRom, apply_rom_settings
|
||||
|
||||
|
||||
def adjust(args):
|
||||
|
@ -12,14 +11,6 @@ def adjust(args):
|
|||
logger = logging.getLogger('')
|
||||
logger.info('Patching ROM.')
|
||||
|
||||
if args.sprite is not None:
|
||||
if isinstance(args.sprite, Sprite):
|
||||
sprite = args.sprite
|
||||
else:
|
||||
sprite = Sprite(args.sprite)
|
||||
else:
|
||||
sprite = None
|
||||
|
||||
outfilebase = os.path.basename(args.rom)[:-4] + '_adjusted'
|
||||
|
||||
if os.stat(args.rom).st_size in (0x200000, 0x400000) and os.path.splitext(args.rom)[-1].lower() == '.sfc':
|
||||
|
@ -30,7 +21,7 @@ def adjust(args):
|
|||
else:
|
||||
raise RuntimeError('Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.')
|
||||
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, sprite, args.ow_palettes, args.uw_palettes, parse_names_string(args.names))
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, args.sprite, args.ow_palettes, args.uw_palettes, parse_names_string(args.names))
|
||||
|
||||
rom.write_to_file(output_path('%s.sfc' % outfilebase))
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import shlex
|
|||
import sys
|
||||
|
||||
from Main import main
|
||||
from Rom import get_sprite_from_name
|
||||
from Utils import is_bundled, close_console
|
||||
|
||||
|
||||
|
@ -289,7 +290,7 @@ def parse_arguments(argv, no_defaults=False):
|
|||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||
'retro', 'accessibility', 'hints', 'shufflepots', 'beemizer',
|
||||
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage',
|
||||
'ow_palettes', 'uw_palettes']:
|
||||
'ow_palettes', 'uw_palettes', 'sprite']:
|
||||
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
|
||||
if player == 1:
|
||||
setattr(ret, name, {1: value})
|
||||
|
@ -315,9 +316,9 @@ def start():
|
|||
if not args.jsonout and not os.path.isfile(args.rom):
|
||||
input('Could not find valid base rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom)
|
||||
sys.exit(1)
|
||||
if args.sprite is not None and not os.path.isfile(args.sprite):
|
||||
if any([sprite is not None and not os.path.isfile(sprite) and not get_sprite_from_name(sprite) for sprite in args.sprite.values()]):
|
||||
if not args.jsonout:
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.' % args.sprite)
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
raise IOError('Cannot find sprite file at %s' % args.sprite)
|
||||
|
|
29
Main.py
29
Main.py
|
@ -13,7 +13,7 @@ from Items import ItemFactory
|
|||
from Regions import create_regions, mark_light_world_regions
|
||||
from InvertedRegions import create_inverted_regions, mark_dark_world_regions
|
||||
from EntranceShuffle import link_entrances, link_inverted_entrances
|
||||
from Rom import patch_rom, get_race_rom_patches, get_enemizer_patch, apply_rom_settings, Sprite, LocalRom, JsonRom
|
||||
from Rom import patch_rom, get_race_rom_patches, get_enemizer_patch, apply_rom_settings, LocalRom, JsonRom
|
||||
from Rules import set_rules
|
||||
from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive
|
||||
from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items, balance_multiworld_progression
|
||||
|
@ -135,14 +135,6 @@ def main(args, seed=None):
|
|||
|
||||
logger.info('Patching ROM.')
|
||||
|
||||
if args.sprite is not None:
|
||||
if isinstance(args.sprite, Sprite):
|
||||
sprite = args.sprite
|
||||
else:
|
||||
sprite = Sprite(args.sprite)
|
||||
else:
|
||||
sprite = None
|
||||
|
||||
player_names = parse_names_string(args.names)
|
||||
outfilebase = 'ER_%s' % (args.outputname if args.outputname else world.seed)
|
||||
|
||||
|
@ -150,25 +142,20 @@ def main(args, seed=None):
|
|||
jsonout = {}
|
||||
if not args.suppress_rom:
|
||||
for player in range(1, world.players + 1):
|
||||
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] != 'none'
|
||||
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
|
||||
or args.shufflepots[player])
|
||||
or args.shufflepots[player] or sprite_random_on_hit)
|
||||
|
||||
rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom)
|
||||
local_rom = LocalRom(args.rom) if not args.jsonout and use_enemizer else None
|
||||
|
||||
local_rom = None
|
||||
if args.jsonout:
|
||||
rom = JsonRom()
|
||||
else:
|
||||
if use_enemizer:
|
||||
local_rom = LocalRom(args.rom)
|
||||
rom = JsonRom()
|
||||
else:
|
||||
rom = LocalRom(args.rom)
|
||||
patch_rom(world, player, rom, use_enemizer)
|
||||
rom_names.append((player, list(rom.name)))
|
||||
|
||||
enemizer_patch = []
|
||||
if use_enemizer and (args.enemizercli or not args.jsonout):
|
||||
enemizer_patch = get_enemizer_patch(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player])
|
||||
enemizer_patch = get_enemizer_patch(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player], sprite_random_on_hit)
|
||||
|
||||
if args.jsonout:
|
||||
jsonout[f'patch{player}'] = rom.patches
|
||||
|
@ -185,7 +172,7 @@ def main(args, seed=None):
|
|||
for addr, values in get_race_rom_patches(rom).items():
|
||||
rom.write_bytes(int(addr), values)
|
||||
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, sprite, args.ow_palettes[player], args.uw_palettes[player], player_names)
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, args.sprite[player], args.ow_palettes[player], args.uw_palettes[player], player_names)
|
||||
|
||||
mcsb_name = ''
|
||||
if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player], world.bigkeyshuffle[player]]):
|
||||
|
|
13
Plando.py
13
Plando.py
|
@ -10,7 +10,7 @@ import sys
|
|||
from BaseClasses import World
|
||||
from Regions import create_regions
|
||||
from EntranceShuffle import link_entrances, connect_entrance, connect_two_way, connect_exit
|
||||
from Rom import patch_rom, LocalRom, Sprite, write_string_to_rom, apply_rom_settings
|
||||
from Rom import patch_rom, LocalRom, write_string_to_rom, apply_rom_settings, get_sprite_from_name
|
||||
from Rules import set_rules
|
||||
from Dungeons import create_dungeons
|
||||
from Items import ItemFactory
|
||||
|
@ -68,15 +68,10 @@ def main(args):
|
|||
|
||||
logger.info('Patching ROM.')
|
||||
|
||||
if args.sprite is not None:
|
||||
sprite = Sprite(args.sprite)
|
||||
else:
|
||||
sprite = None
|
||||
|
||||
rom = LocalRom(args.rom)
|
||||
patch_rom(world, 1, rom, False)
|
||||
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, sprite, args.ow_palettes, args.uw_palettes)
|
||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, args.sprite, args.ow_palettes, args.uw_palettes)
|
||||
|
||||
for textname, texttype, text in text_patches:
|
||||
if texttype == 'text':
|
||||
|
@ -226,8 +221,8 @@ def start():
|
|||
if not os.path.isfile(args.plando):
|
||||
input('Could not find Plandomizer distribution at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.plando)
|
||||
sys.exit(1)
|
||||
if args.sprite is not None and not os.path.isfile(args.rom):
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.' % args.sprite)
|
||||
if args.sprite is not None and not os.path.isfile(args.sprite) and not get_sprite_from_name(args.sprite):
|
||||
input('Could not find link sprite sheet at given location. \nPress Enter to exit.')
|
||||
sys.exit(1)
|
||||
|
||||
# set up logger
|
||||
|
|
43
Rom.py
43
Rom.py
|
@ -37,8 +37,7 @@ class JsonRom(object):
|
|||
def write_bytes(self, startaddress, values):
|
||||
if not values:
|
||||
return
|
||||
if type(values) is not list:
|
||||
values = list(values)
|
||||
values = list(values)
|
||||
|
||||
pos = bisect.bisect_right(self.addresses, startaddress)
|
||||
intervalstart = self.addresses[pos-1] if pos else None
|
||||
|
@ -164,7 +163,7 @@ def read_rom(stream):
|
|||
buffer = buffer[0x200:]
|
||||
return buffer
|
||||
|
||||
def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shufflepots):
|
||||
def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shufflepots, random_sprite_on_hit):
|
||||
baserom_path = os.path.abspath(baserom_path)
|
||||
basepatch_path = os.path.abspath(local_path('data/base2current.json'))
|
||||
randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json'))
|
||||
|
@ -224,7 +223,7 @@ def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shufflepot
|
|||
'RandomizeTileTrapPattern': world.enemy_shuffle[player] == 'chaos',
|
||||
'RandomizeTileTrapFloorTile': False,
|
||||
'AllowKillableThief': bool(random.randint(0,1)) if world.enemy_shuffle[player] == 'chaos' else world.enemy_shuffle[player] != 'none',
|
||||
'RandomizeSpriteOnHit': False,
|
||||
'RandomizeSpriteOnHit': random_sprite_on_hit,
|
||||
'DebugMode': False,
|
||||
'DebugForceEnemy': False,
|
||||
'DebugForceEnemyId': 0,
|
||||
|
@ -260,7 +259,6 @@ def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shufflepot
|
|||
options['ManualBosses']['GanonsTower2'] = world.get_dungeon('Inverted Ganons Tower', player).bosses['middle'].enemizer_name
|
||||
options['ManualBosses']['GanonsTower3'] = world.get_dungeon('Inverted Ganons Tower', player).bosses['top'].enemizer_name
|
||||
|
||||
|
||||
rom.write_to_file(randopatch_path)
|
||||
|
||||
with open(options_path, 'w') as f:
|
||||
|
@ -287,8 +285,41 @@ def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shufflepot
|
|||
if os.path.exists(enemizer_output_path):
|
||||
os.remove(enemizer_output_path)
|
||||
|
||||
if random_sprite_on_hit:
|
||||
_populate_sprite_table()
|
||||
sprites = list(_sprite_table.values())
|
||||
if sprites:
|
||||
while len(sprites) < 32:
|
||||
sprites.extend(sprites)
|
||||
random.shuffle(sprites)
|
||||
|
||||
for i, path in enumerate(sprites[:32]):
|
||||
sprite = Sprite(path)
|
||||
ret.append({"address": 0x300000 + (i * 0x8000), "patchData": list(sprite.sprite)})
|
||||
ret.append({"address": 0x307000 + (i * 0x8000), "patchData": list(sprite.palette)})
|
||||
ret.append({"address": 0x307078 + (i * 0x8000), "patchData": list(sprite.glove_palette)})
|
||||
|
||||
return ret
|
||||
|
||||
_sprite_table = {}
|
||||
def _populate_sprite_table():
|
||||
if not _sprite_table:
|
||||
for dir in [local_path('data/sprites/official'), local_path('data/sprites/unofficial')]:
|
||||
for file in os.listdir(dir):
|
||||
filepath = os.path.join(dir, file)
|
||||
if not os.path.isfile(filepath):
|
||||
continue
|
||||
sprite = Sprite(filepath)
|
||||
if sprite.valid:
|
||||
_sprite_table[sprite.name.lower()] = filepath
|
||||
|
||||
def get_sprite_from_name(name):
|
||||
_populate_sprite_table()
|
||||
name = name.lower()
|
||||
if name in ['random', 'randomonhit']:
|
||||
return Sprite(random.choice(list(_sprite_table.values())))
|
||||
return Sprite(_sprite_table[name]) if name in _sprite_table else None
|
||||
|
||||
class Sprite(object):
|
||||
default_palette = [255, 127, 126, 35, 183, 17, 158, 54, 165, 20, 255, 1, 120, 16, 157,
|
||||
89, 71, 54, 104, 59, 74, 10, 239, 18, 92, 42, 113, 21, 24, 122,
|
||||
|
@ -1282,6 +1313,8 @@ def hud_format_text(text):
|
|||
|
||||
|
||||
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, ow_palettes, uw_palettes, names = None):
|
||||
if sprite and not isinstance(sprite, Sprite):
|
||||
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite)
|
||||
|
||||
# enable instant item menu
|
||||
if fastmenu == 'instant':
|
||||
|
|
Loading…
Reference in New Issue