Enemizer support
This commit is contained in:
		
							parent
							
								
									0b9e144f8e
								
							
						
					
					
						commit
						16abf033c3
					
				| 
						 | 
				
			
			@ -11,3 +11,4 @@ README.html
 | 
			
		|||
.vs/
 | 
			
		||||
*multidata
 | 
			
		||||
*multisave
 | 
			
		||||
EnemizerCLI/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,14 +207,19 @@ def start():
 | 
			
		|||
                             ''')
 | 
			
		||||
    parser.add_argument('--suppress_rom', help='Do not create an output rom file.', action='store_true')
 | 
			
		||||
    parser.add_argument('--gui', help='Launch the GUI', action='store_true')
 | 
			
		||||
    # Deliberately not documented, only useful for vt site integration right now:
 | 
			
		||||
    parser.add_argument('--shufflebosses', help=argparse.SUPPRESS, default='none', const='none', nargs='?', choices=['none', 'basic', 'normal', 'chaos'])
 | 
			
		||||
    parser.add_argument('--jsonout', action='store_true', help='''\
 | 
			
		||||
                            Output .json patch to stdout instead of a patched rom. Used
 | 
			
		||||
                            for VT site integration, do not use otherwise.
 | 
			
		||||
                            ''')
 | 
			
		||||
    parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255))
 | 
			
		||||
    parser.add_argument('--skip_playthrough', action='store_true', default=False)
 | 
			
		||||
    parser.add_argument('--enemizercli', default='')
 | 
			
		||||
    parser.add_argument('--shufflebosses', default='none', choices=['none', 'basic', 'normal', 'chaos'])
 | 
			
		||||
    parser.add_argument('--shuffleenemies', default=False, action='store_true')
 | 
			
		||||
    parser.add_argument('--enemy_health', default='default', choices=['default', 'easy', 'normal', 'hard', 'expert'])
 | 
			
		||||
    parser.add_argument('--enemy_damage', default='default', choices=['default', 'shuffled', 'chaos'])
 | 
			
		||||
    parser.add_argument('--shufflepalette', default=False, action='store_true')
 | 
			
		||||
    parser.add_argument('--shufflepots', default=False, action='store_true')
 | 
			
		||||
    parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255))
 | 
			
		||||
 | 
			
		||||
    parser.add_argument('--outputpath')
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								Gui.py
								
								
								
								
							
							
						
						
									
										70
									
								
								Gui.py
								
								
								
								
							| 
						 | 
				
			
			@ -5,7 +5,7 @@ import json
 | 
			
		|||
import random
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
from tkinter import Checkbutton, OptionMenu, Toplevel, LabelFrame, PhotoImage, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, Entry, Spinbox, Button, filedialog, messagebox, ttk
 | 
			
		||||
from tkinter import Checkbutton, OptionMenu, Toplevel, LabelFrame, PhotoImage, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, BOTH, Entry, Spinbox, Button, filedialog, messagebox, ttk
 | 
			
		||||
from urllib.parse import urlparse
 | 
			
		||||
from urllib.request import urlopen
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -242,12 +242,67 @@ def guiMain(args=None):
 | 
			
		|||
    heartcolorFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    fastMenuFrame.pack(expand=True, anchor=E)
 | 
			
		||||
 | 
			
		||||
    bottomFrame = Frame(randomizerWindow)
 | 
			
		||||
    enemizerFrame = LabelFrame(randomizerWindow, text="Enemizer", padx=5, pady=5)
 | 
			
		||||
    enemizerFrame.columnconfigure(0, weight=1)
 | 
			
		||||
    enemizerFrame.columnconfigure(1, weight=1)
 | 
			
		||||
    enemizerFrame.columnconfigure(2, weight=1)
 | 
			
		||||
 | 
			
		||||
    enemizerPathFrame = Frame(enemizerFrame)
 | 
			
		||||
    enemizerPathFrame.grid(row=0, column=0, columnspan=3, sticky=W)
 | 
			
		||||
    enemizerCLIlabel = Label(enemizerPathFrame, text="EnemizerCLI path: ")
 | 
			
		||||
    enemizerCLIlabel.pack(side=LEFT)
 | 
			
		||||
    enemizerCLIpathVar = StringVar()
 | 
			
		||||
    enemizerCLIpathEntry = Entry(enemizerPathFrame, textvariable=enemizerCLIpathVar, width=80)
 | 
			
		||||
    enemizerCLIpathEntry.pack(side=LEFT)
 | 
			
		||||
    def EnemizerSelectPath():
 | 
			
		||||
        path = filedialog.askopenfilename(filetypes=[("EnemizerCLI executable", "*EnemizerCLI*")])
 | 
			
		||||
        if path:
 | 
			
		||||
            enemizerCLIpathVar.set(path)
 | 
			
		||||
    enemizerCLIbrowseButton = Button(enemizerPathFrame, text='...', command=EnemizerSelectPath)
 | 
			
		||||
    enemizerCLIbrowseButton.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    enemyShuffleVar = IntVar()
 | 
			
		||||
    enemyShuffleButton = Checkbutton(enemizerFrame, text="Enemy shuffle", variable=enemyShuffleVar)
 | 
			
		||||
    enemyShuffleButton.grid(row=1, column=0)
 | 
			
		||||
    paletteShuffleVar = IntVar()
 | 
			
		||||
    paletteShuffleButton = Checkbutton(enemizerFrame, text="Palette shuffle", variable=paletteShuffleVar)
 | 
			
		||||
    paletteShuffleButton.grid(row=1, column=1)
 | 
			
		||||
    potShuffleVar = IntVar()
 | 
			
		||||
    potShuffleButton = Checkbutton(enemizerFrame, text="Pot shuffle", variable=potShuffleVar)
 | 
			
		||||
    potShuffleButton.grid(row=1, column=2)
 | 
			
		||||
 | 
			
		||||
    enemizerBossFrame = Frame(enemizerFrame)
 | 
			
		||||
    enemizerBossFrame.grid(row=2, column=0)
 | 
			
		||||
    enemizerBossLabel = Label(enemizerBossFrame, text='Boss shuffle')
 | 
			
		||||
    enemizerBossLabel.pack(side=LEFT)
 | 
			
		||||
    enemizerBossVar = StringVar()
 | 
			
		||||
    enemizerBossVar.set('none')
 | 
			
		||||
    enemizerBossOption = OptionMenu(enemizerBossFrame, enemizerBossVar, 'none', 'basic', 'normal', 'chaos')
 | 
			
		||||
    enemizerBossOption.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    enemizerDamageFrame = Frame(enemizerFrame)
 | 
			
		||||
    enemizerDamageFrame.grid(row=2, column=1)
 | 
			
		||||
    enemizerDamageLabel = Label(enemizerDamageFrame, text='Enemy damage')
 | 
			
		||||
    enemizerDamageLabel.pack(side=LEFT)
 | 
			
		||||
    enemizerDamageVar = StringVar()
 | 
			
		||||
    enemizerDamageVar.set('default')
 | 
			
		||||
    enemizerDamageOption = OptionMenu(enemizerDamageFrame, enemizerDamageVar, 'default', 'shuffled', 'chaos')
 | 
			
		||||
    enemizerDamageOption.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    enemizerHealthFrame = Frame(enemizerFrame)
 | 
			
		||||
    enemizerHealthFrame.grid(row=2, column=2)
 | 
			
		||||
    enemizerHealthLabel = Label(enemizerHealthFrame, text='Enemy health')
 | 
			
		||||
    enemizerHealthLabel.pack(side=LEFT)
 | 
			
		||||
    enemizerHealthVar = StringVar()
 | 
			
		||||
    enemizerHealthVar.set('default')
 | 
			
		||||
    enemizerHealthOption = OptionMenu(enemizerHealthFrame, enemizerHealthVar, 'default', 'easy', 'normal', 'hard', 'expert')
 | 
			
		||||
    enemizerHealthOption.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    bottomFrame = Frame(randomizerWindow, pady=5)
 | 
			
		||||
 | 
			
		||||
    worldLabel = Label(bottomFrame, text='Worlds')
 | 
			
		||||
    worldVar = StringVar()
 | 
			
		||||
    worldSpinbox = Spinbox(bottomFrame, from_=1, to=100, width=5, textvariable=worldVar)
 | 
			
		||||
 | 
			
		||||
    seedLabel = Label(bottomFrame, text='Seed #')
 | 
			
		||||
    seedVar = StringVar()
 | 
			
		||||
    seedEntry = Entry(bottomFrame, width=15, textvariable=seedVar)
 | 
			
		||||
| 
						 | 
				
			
			@ -281,6 +336,13 @@ def guiMain(args=None):
 | 
			
		|||
        guiargs.disablemusic = bool(disableMusicVar.get())
 | 
			
		||||
        guiargs.shuffleganon = bool(shuffleGanonVar.get())
 | 
			
		||||
        guiargs.hints = bool(hintsVar.get())
 | 
			
		||||
        guiargs.enemizercli = enemizerCLIpathVar.get()
 | 
			
		||||
        guiargs.shufflebosses = enemizerBossVar.get()
 | 
			
		||||
        guiargs.shuffleenemies = bool(enemyShuffleVar.get())
 | 
			
		||||
        guiargs.enemy_health = enemizerHealthVar.get()
 | 
			
		||||
        guiargs.enemy_damage = enemizerDamageVar.get()
 | 
			
		||||
        guiargs.shufflepalette = bool(paletteShuffleVar.get())
 | 
			
		||||
        guiargs.shufflepots = bool(potShuffleVar.get())
 | 
			
		||||
        guiargs.custom = bool(customVar.get())
 | 
			
		||||
        guiargs.customitemarray = [int(bowVar.get()), int(silverarrowVar.get()), int(boomerangVar.get()), int(magicboomerangVar.get()), int(hookshotVar.get()), int(mushroomVar.get()), int(magicpowderVar.get()), int(firerodVar.get()),
 | 
			
		||||
                                   int(icerodVar.get()), int(bombosVar.get()), int(etherVar.get()), int(quakeVar.get()), int(lampVar.get()), int(hammerVar.get()), int(shovelVar.get()), int(fluteVar.get()), int(bugnetVar.get()),
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +353,6 @@ def guiMain(args=None):
 | 
			
		|||
                                   int(arrow1Var.get()), int(arrow10Var.get()), int(bomb1Var.get()), int(bomb3Var.get()), int(rupee1Var.get()), int(rupee5Var.get()), int(rupee20Var.get()), int(rupee50Var.get()), int(rupee100Var.get()),
 | 
			
		||||
                                   int(rupee300Var.get()), int(rupoorVar.get()), int(blueclockVar.get()), int(greenclockVar.get()), int(redclockVar.get()), int(triforcepieceVar.get()), int(triforcecountVar.get()),
 | 
			
		||||
                                   int(triforceVar.get()), int(rupoorcostVar.get()), int(universalkeyVar.get())]
 | 
			
		||||
        guiargs.shufflebosses = None
 | 
			
		||||
        guiargs.rom = romVar.get()
 | 
			
		||||
        guiargs.jsonout = None
 | 
			
		||||
        guiargs.sprite = sprite
 | 
			
		||||
| 
						 | 
				
			
			@ -326,6 +387,7 @@ def guiMain(args=None):
 | 
			
		|||
    rightHalfFrame.pack(side=RIGHT)
 | 
			
		||||
    topFrame.pack(side=TOP)
 | 
			
		||||
    bottomFrame.pack(side=BOTTOM)
 | 
			
		||||
    enemizerFrame.pack(side=BOTTOM, fill=BOTH)
 | 
			
		||||
 | 
			
		||||
    # Adjuster Controls
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										28
									
								
								Main.py
								
								
								
								
							| 
						 | 
				
			
			@ -3,13 +3,14 @@ import copy
 | 
			
		|||
from itertools import zip_longest
 | 
			
		||||
import json
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import random
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
from BaseClasses import World, CollectionState, Item, Region, Location, Shop
 | 
			
		||||
from Regions import create_regions, mark_light_world_regions
 | 
			
		||||
from EntranceShuffle import link_entrances
 | 
			
		||||
from Rom import patch_rom, Sprite, LocalRom, JsonRom
 | 
			
		||||
from Rom import patch_rom, get_enemizer_patch, apply_rom_settings, Sprite, 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
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +125,8 @@ def main(args, seed=None):
 | 
			
		|||
 | 
			
		||||
    outfilebase = 'ER_%s_%s-%s-%s%s_%s-%s%s%s%s%s_%s' % (world.logic, world.difficulty, world.mode, world.goal, "" if world.timer in ['none', 'display'] else "-" + world.timer, world.shuffle, world.algorithm, "-keysanity" if world.keysanity else "", "-retro" if world.retro else "", "-prog_" + world.progressive if world.progressive in ['off', 'random'] else "", "-nohints" if not world.hints else "", world.seed)
 | 
			
		||||
 | 
			
		||||
    use_enemizer = args.enemizercli and (args.shufflebosses != 'none' or args.shuffleenemies or args.enemy_health != 'default' or args.enemy_health != 'default' or args.enemy_damage or args.shufflepalette or args.shufflepots)
 | 
			
		||||
 | 
			
		||||
    jsonout = {}
 | 
			
		||||
    if not args.suppress_rom:
 | 
			
		||||
        if world.players > 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -131,17 +134,32 @@ def main(args, seed=None):
 | 
			
		|||
        else:
 | 
			
		||||
            player = 1
 | 
			
		||||
 | 
			
		||||
            local_rom = None
 | 
			
		||||
            if args.jsonout:
 | 
			
		||||
                rom = JsonRom()
 | 
			
		||||
            else:
 | 
			
		||||
                rom = LocalRom(args.rom)
 | 
			
		||||
            patch_rom(world, player, rom, bytearray(logic_hash), args.heartbeep, args.heartcolor, sprite, player_names)
 | 
			
		||||
                if use_enemizer:
 | 
			
		||||
                    local_rom = LocalRom(args.rom)
 | 
			
		||||
                    rom = JsonRom()
 | 
			
		||||
                else:
 | 
			
		||||
                    rom = LocalRom(args.rom)
 | 
			
		||||
 | 
			
		||||
            patch_rom(world, player, rom, bytearray(logic_hash))
 | 
			
		||||
 | 
			
		||||
            enemizer_patch = []
 | 
			
		||||
            if use_enemizer:
 | 
			
		||||
                enemizer_patch = get_enemizer_patch(world, player, rom, args.rom, args.enemizercli, args.shuffleenemies, args.enemy_health, args.enemy_damage, args.shufflepalette, args.shufflepots)
 | 
			
		||||
 | 
			
		||||
            if args.jsonout:
 | 
			
		||||
                jsonout['patch'] = rom.patches
 | 
			
		||||
 | 
			
		||||
                if use_enemizer:
 | 
			
		||||
                    jsonout['enemizer' % player] = enemizer_patch
 | 
			
		||||
            else:
 | 
			
		||||
                apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, sprite, player_names)
 | 
			
		||||
                if use_enemizer:
 | 
			
		||||
                    local_rom.patch_enemizer(rom.patches, os.path.join(os.path.dirname(args.enemizercli), "enemizerBasePatch.json"), enemizer_patch)
 | 
			
		||||
                    rom = local_rom
 | 
			
		||||
 | 
			
		||||
                apply_rom_settings(rom, args.heartbeep, args.heartcolor, world.quickswap, world.fastmenu, world.disable_music, sprite)
 | 
			
		||||
                rom.write_to_file(output_path('%s.sfc' % outfilebase))
 | 
			
		||||
 | 
			
		||||
    if args.create_spoiler and not args.jsonout:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										145
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										145
									
								
								Rom.py
								
								
								
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@ import hashlib
 | 
			
		|||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import struct
 | 
			
		||||
import subprocess
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
from BaseClasses import ShopType, Region, Location, Item
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +12,7 @@ from Dungeons import dungeon_music_addresses
 | 
			
		|||
from Text import MultiByteTextMapper, text_addresses, Credits, TextTable
 | 
			
		||||
from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts
 | 
			
		||||
from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts, LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
 | 
			
		||||
from Utils import local_path, int16_as_bytes, int32_as_bytes
 | 
			
		||||
from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes
 | 
			
		||||
from Items import ItemFactory, item_table
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +85,7 @@ class LocalRom(object):
 | 
			
		|||
            logging.getLogger('').warning('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] * (2097152 - len(self.buffer))))
 | 
			
		||||
        self.buffer.extend(bytearray([0x00] * (0x200000 - len(self.buffer))))
 | 
			
		||||
 | 
			
		||||
        # load randomizer patches
 | 
			
		||||
        with open(local_path('data/base2current.json'), 'r') as stream:
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +101,24 @@ class LocalRom(object):
 | 
			
		|||
        if RANDOMIZERBASEHASH != patchedmd5.hexdigest():
 | 
			
		||||
            raise RuntimeError('Provided Base Rom unsuitable for patching. Please provide a JAP(1.0) "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc" rom to use as a base.')
 | 
			
		||||
 | 
			
		||||
    def patch_enemizer(self, rando_patch, base_enemizer_patch_path, enemizer_patch):
 | 
			
		||||
        # extend to 4MB
 | 
			
		||||
        self.buffer.extend(bytearray([0x00] * (0x400000 - len(self.buffer))))
 | 
			
		||||
 | 
			
		||||
        # apply randomizer patches
 | 
			
		||||
        for address, values in rando_patch.items():
 | 
			
		||||
            self.write_bytes(int(address), values)
 | 
			
		||||
 | 
			
		||||
        # load base enemizer patches
 | 
			
		||||
        with open(base_enemizer_patch_path, 'r') as f:
 | 
			
		||||
            base_enemizer_patch = json.load(f)
 | 
			
		||||
        for patch in base_enemizer_patch:
 | 
			
		||||
            self.write_bytes(patch["address"], patch["patchData"])
 | 
			
		||||
 | 
			
		||||
        # apply enemizer patches
 | 
			
		||||
        for patch in enemizer_patch:
 | 
			
		||||
            self.write_bytes(patch["address"], patch["patchData"])
 | 
			
		||||
 | 
			
		||||
    def write_crc(self):
 | 
			
		||||
        crc = (sum(self.buffer[:0x7FDC] + self.buffer[0x7FE0:]) + 0x01FE) & 0xFFFF
 | 
			
		||||
        inv = crc ^ 0xFFFF
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +136,124 @@ def read_rom(stream):
 | 
			
		|||
        buffer = buffer[0x200:]
 | 
			
		||||
    return buffer
 | 
			
		||||
 | 
			
		||||
def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shuffleenemies, enemy_health, enemy_damage, shufflepalette, shufflepots):
 | 
			
		||||
    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'))
 | 
			
		||||
    options_path = os.path.abspath(output_path('enemizer_options.json'))
 | 
			
		||||
    enemizer_output_path = os.path.abspath(output_path('enemizer_output.json'))
 | 
			
		||||
 | 
			
		||||
    # write options file for enemizer
 | 
			
		||||
    options = {
 | 
			
		||||
        'RandomizeEnemies': shuffleenemies,
 | 
			
		||||
        'RandomizeEnemiesType': 3,
 | 
			
		||||
        'RandomizeBushEnemyChance': True,
 | 
			
		||||
        'RandomizeEnemyHealthRange': enemy_health != 'default',
 | 
			
		||||
        'RandomizeEnemyHealthType': {'default': 0, 'easy': 0, 'normal': 1, 'hard': 2, 'expert': 3}[enemy_health],
 | 
			
		||||
        'OHKO': False,
 | 
			
		||||
        'RandomizeEnemyDamage': enemy_damage != 'default',
 | 
			
		||||
        'AllowEnemyZeroDamage': True,
 | 
			
		||||
        'ShuffleEnemyDamageGroups': enemy_damage != 'default',
 | 
			
		||||
        'EnemyDamageChaosMode': enemy_damage == 'chaos',
 | 
			
		||||
        'EasyModeEscape': False,
 | 
			
		||||
        'EnemiesAbsorbable': False,
 | 
			
		||||
        'AbsorbableSpawnRate': 10,
 | 
			
		||||
        'AbsorbableTypes': {
 | 
			
		||||
            'FullMagic': True, 'SmallMagic': True, 'Bomb_1': True, 'BlueRupee': True, 'Heart': True, 'BigKey': True, 'Key': True,
 | 
			
		||||
            'Fairy': True, 'Arrow_10': True, 'Arrow_5': True, 'Bomb_8': True, 'Bomb_4': True, 'GreenRupee': True, 'RedRupee': True
 | 
			
		||||
        },
 | 
			
		||||
        'BossMadness': False,
 | 
			
		||||
        'RandomizeBosses': True,
 | 
			
		||||
        'RandomizeBossesType': 0,
 | 
			
		||||
        'RandomizeBossHealth': False,
 | 
			
		||||
        'RandomizeBossHealthMinAmount': 0,
 | 
			
		||||
        'RandomizeBossHealthMaxAmount': 300,
 | 
			
		||||
        'RandomizeBossDamage': False,
 | 
			
		||||
        'RandomizeBossDamageMinAmount': 0,
 | 
			
		||||
        'RandomizeBossDamageMaxAmount': 200,
 | 
			
		||||
        'RandomizeBossBehavior': False,
 | 
			
		||||
        'RandomizeDungeonPalettes': shufflepalette,
 | 
			
		||||
        'SetBlackoutMode': False,
 | 
			
		||||
        'RandomizeOverworldPalettes': shufflepalette,
 | 
			
		||||
        'RandomizeSpritePalettes': shufflepalette,
 | 
			
		||||
        'SetAdvancedSpritePalettes': False,
 | 
			
		||||
        'PukeMode': False,
 | 
			
		||||
        'NegativeMode': False,
 | 
			
		||||
        'GrayscaleMode': False,
 | 
			
		||||
        'GenerateSpoilers': False,
 | 
			
		||||
        'RandomizeLinkSpritePalette': False,
 | 
			
		||||
        'RandomizePots': shufflepots,
 | 
			
		||||
        'ShuffleMusic': False,
 | 
			
		||||
        'BootlegMagic': True,
 | 
			
		||||
        'CustomBosses': False,
 | 
			
		||||
        'AndyMode': False,
 | 
			
		||||
        'HeartBeepSpeed': 0,
 | 
			
		||||
        'AlternateGfx': False,
 | 
			
		||||
        'ShieldGraphics': "shield_gfx/normal.gfx",
 | 
			
		||||
        'SwordGraphics': "sword_gfx/normal.gfx",
 | 
			
		||||
        'BeeMizer': False,
 | 
			
		||||
        'BeesLevel': 0,
 | 
			
		||||
        'RandomizeTileTrapPattern': True,
 | 
			
		||||
        'RandomizeTileTrapFloorTile': False,
 | 
			
		||||
        'AllowKillableThief': shuffleenemies,
 | 
			
		||||
        'RandomizeSpriteOnHit': False,
 | 
			
		||||
        'DebugMode': False,
 | 
			
		||||
        'DebugForceEnemy': False,
 | 
			
		||||
        'DebugForceEnemyId': 0,
 | 
			
		||||
        'DebugForceBoss': False,
 | 
			
		||||
        'DebugForceBossId': 0,
 | 
			
		||||
        'DebugOpenShutterDoors': False,
 | 
			
		||||
        'DebugForceEnemyDamageZero': False,
 | 
			
		||||
        'DebugShowRoomIdInRupeeCounter': False,
 | 
			
		||||
        'UseManualBosses': True,
 | 
			
		||||
        'ManualBosses': {
 | 
			
		||||
            'EasternPalace': world.get_dungeon("Eastern Palace", player).boss.enemizer_name,
 | 
			
		||||
            'DesertPalace': world.get_dungeon("Desert Palace", player).boss.enemizer_name,
 | 
			
		||||
            'TowerOfHera': world.get_dungeon("Tower of Hera", player).boss.enemizer_name,
 | 
			
		||||
            'AgahnimsTower': 'Agahnim',
 | 
			
		||||
            'PalaceOfDarkness': world.get_dungeon("Palace of Darkness", player).boss.enemizer_name,
 | 
			
		||||
            'SwampPalace': world.get_dungeon("Swamp Palace", player).boss.enemizer_name,
 | 
			
		||||
            'SkullWoods': world.get_dungeon("Skull Woods", player).boss.enemizer_name,
 | 
			
		||||
            'ThievesTown': world.get_dungeon("Thieves Town", player).boss.enemizer_name,
 | 
			
		||||
            'IcePalace': world.get_dungeon("Ice Palace", player).boss.enemizer_name,
 | 
			
		||||
            'MiseryMire': world.get_dungeon("Misery Mire", player).boss.enemizer_name,
 | 
			
		||||
            'TurtleRock': world.get_dungeon("Turtle Rock", player).boss.enemizer_name,
 | 
			
		||||
            'GanonsTower1': world.get_dungeon('Ganons Tower', player).bosses['bottom'].enemizer_name,
 | 
			
		||||
            'GanonsTower2': world.get_dungeon('Ganons Tower', player).bosses['middle'].enemizer_name,
 | 
			
		||||
            'GanonsTower3': world.get_dungeon('Ganons Tower', player).bosses['top'].enemizer_name,
 | 
			
		||||
            'GanonsTower4': 'Agahnim2',
 | 
			
		||||
            'Ganon': 'Ganon',
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rom.write_to_file(randopatch_path)
 | 
			
		||||
 | 
			
		||||
    with open(options_path, 'w') as f:
 | 
			
		||||
        json.dump(options, f)
 | 
			
		||||
 | 
			
		||||
    subprocess.check_call([os.path.abspath(enemizercli),
 | 
			
		||||
                           '--rom', baserom_path,
 | 
			
		||||
                           '--seed', str(world.rom_seeds[player]),
 | 
			
		||||
                           '--base', basepatch_path,
 | 
			
		||||
                           '--randomizer', randopatch_path,
 | 
			
		||||
                           '--enemizer', options_path,
 | 
			
		||||
                           '--output', enemizer_output_path],
 | 
			
		||||
                          cwd=os.path.dirname(enemizercli), stdout=subprocess.DEVNULL)
 | 
			
		||||
 | 
			
		||||
    with open(enemizer_output_path, 'r') as f:
 | 
			
		||||
        ret = json.load(f)
 | 
			
		||||
 | 
			
		||||
    if os.path.exists(randopatch_path):
 | 
			
		||||
        os.remove(randopatch_path)
 | 
			
		||||
 | 
			
		||||
    if os.path.exists(options_path):
 | 
			
		||||
        os.remove(options_path)
 | 
			
		||||
 | 
			
		||||
    if os.path.exists(enemizer_output_path):
 | 
			
		||||
        os.remove(enemizer_output_path)
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
| 
						 | 
				
			
			@ -275,7 +412,7 @@ class Sprite(object):
 | 
			
		|||
        # split into palettes of 15 colors
 | 
			
		||||
        return array_chunk(palette_as_colors, 15)
 | 
			
		||||
 | 
			
		||||
def patch_rom(world, player, rom, hashtable, beep='normal', color='red', sprite=None):
 | 
			
		||||
def patch_rom(world, player, rom, hashtable):
 | 
			
		||||
    random.seed(world.rom_seeds[player])
 | 
			
		||||
    # patch items
 | 
			
		||||
    for location in world.get_locations():
 | 
			
		||||
| 
						 | 
				
			
			@ -852,8 +989,6 @@ def patch_rom(world, player, rom, hashtable, beep='normal', color='red', sprite=
 | 
			
		|||
    ]
 | 
			
		||||
    rom.write_bytes(0x180215, code)
 | 
			
		||||
 | 
			
		||||
    apply_rom_settings(rom, beep, color, world.quickswap, world.fastmenu, world.disable_music, sprite)
 | 
			
		||||
 | 
			
		||||
    return rom
 | 
			
		||||
 | 
			
		||||
def write_custom_shops(rom, world, player):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue