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
 | 
			
		||||
    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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										8
									
								
								Main.py
								
								
								
								
							| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										89
									
								
								Rom.py
								
								
								
								
							| 
						 | 
				
			
			@ -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.
										
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue