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:
Bonta-kun 2020-01-09 02:30:00 +01:00
parent feb925d2b1
commit 5db7e066da
6 changed files with 59 additions and 51 deletions

View File

@ -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

View File

@ -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))

View File

@ -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
View File

@ -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]]):

View File

@ -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
View File

@ -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':