def __init__(self, args, rom): if rom.banks[0][7] == 0x01: raise RaceRomException() self.seed = rom.readHexSeed() self.testOnly = args.test self.accessibleItems = [] self.inaccessibleItems = None self.outputFormat = args.spoilerformat # Assume the broadest settings if we're dumping a seed we didn't just create if args.dump: # The witch flag causes trouble if we blindly turn it on if patches.witch.witchIsPatched(rom): args.witch = True args.boomerang = "gift" args.heartpiece = True args.seashells = True args.heartcontainers = True args.owlstatues = "both" self.world_setup = WorldSetup() self.world_setup.loadFromRom(rom) self._loadItems(args, rom)
def __init__(self, configuration_options, rnd=None, *, world_setups=None): assert rnd or world_setups self.worlds = [] self.start = Location() self.location_list = [self.start] self.iteminfo_list = [] for n in range(configuration_options.multiworld): options = configuration_options.multiworld_options[n] world = None if world_setups: world = Logic(options, world_setup=world_setups[n]) else: for cnt in range( 1000 ): # Try the world setup in case entrance randomization generates unsolvable logic world_setup = WorldSetup() world_setup.randomize(options, rnd) world = Logic(options, world_setup=world_setup) if options.entranceshuffle not in ( "advanced", "expert", "insanity") or len( world.iteminfo_list) == sum( itempool.ItemPool(options, rnd).toDict().values()): break for ii in world.iteminfo_list: ii.world = n req_done_set = set() for loc in world.location_list: loc.simple_connections = [ (target, addWorldIdToRequirements(req_done_set, n, req)) for target, req in loc.simple_connections ] loc.gated_connections = [ (target, addWorldIdToRequirements(req_done_set, n, req)) for target, req in loc.gated_connections ] loc.items = [ MultiworldItemInfoWrapper(n, options, ii) for ii in loc.items ] self.iteminfo_list += loc.items self.worlds.append(world) self.start.simple_connections += world.start.simple_connections self.start.gated_connections += world.start.gated_connections self.start.items += world.start.items world.start.items.clear() self.location_list += world.location_list self.entranceMapping = None
def __init__(self, args, roms): for rom in roms: if rom.banks[0][7] == 0x01: raise RaceRomException() self.seed = roms[0].readHexSeed() self.testOnly = args.test self.accessibleItems = [] self.inaccessibleItems = None self.outputFormat = args.spoilerformat self.args = vars(args) # Assume the broadest settings if we're dumping a seed we didn't just create if args.dump: # The witch flag causes trouble if we blindly turn it on if patches.witch.witchIsPatched(roms[0]): args.witch = True args.boomerang = "gift" args.heartpiece = True args.seashells = True args.heartcontainers = True args.owlstatues = "both" if len(roms) > 1: args.multiworld = len(roms) if not hasattr(args, "multiworld_options"): args.multiworld_options = [args] * args.multiworld world_setups = [] for rom in roms: world_setup = WorldSetup() world_setup.loadFromRom(rom) world_setups.append(world_setup) if len(world_setups) == 1: self.logic = logic.Logic(args, world_setup=world_setups[0]) else: self.logic = logic.MultiworldLogic(args, world_setups=world_setups) self._loadItems(args, roms)
def __init__(self, configuration_options, rnd): self.worlds = [] self.start = Location() self.location_list = [self.start] self.iteminfo_list = [] for n in range(configuration_options.multiworld): world_setup = WorldSetup() world_setup.randomize(configuration_options, rnd) world = Logic(configuration_options.multiworld_options[n], world_setup=world_setup) for ii in world.iteminfo_list: ii.world = n for loc in world.location_list: loc.simple_connections = [ (target, addWorldIdToRequirements(n, req)) for target, req in loc.simple_connections ] loc.gated_connections = [ (target, addWorldIdToRequirements(n, req)) for target, req in loc.gated_connections ] loc.items = [ MultiworldItemInfoWrapper(n, configuration_options.multiworld, ii) for ii in loc.items ] self.iteminfo_list += loc.items self.worlds.append(world) self.start.simple_connections += world.start.simple_connections self.start.gated_connections += world.start.gated_connections self.start.items += world.start.items world.start.items.clear() self.location_list += world.location_list self.entranceMapping = None
class SpoilerLog: def __init__(self, args, rom): if rom.banks[0][7] == 0x01: raise RaceRomException() self.seed = rom.readHexSeed() self.testOnly = args.test self.accessibleItems = [] self.inaccessibleItems = None self.outputFormat = args.spoilerformat # Assume the broadest settings if we're dumping a seed we didn't just create if args.dump: # The witch flag causes trouble if we blindly turn it on if patches.witch.witchIsPatched(rom): args.witch = True args.boomerang = "gift" args.heartpiece = True args.seashells = True args.heartcontainers = True args.owlstatues = "both" self.world_setup = WorldSetup() self.world_setup.loadFromRom(rom) self._loadItems(args, rom) def _loadItems(self, args, rom): my_logic = logic.Logic(args, world_setup=self.world_setup) remainingItems = set(my_logic.iteminfo_list) currentSphere = 0 lastAccessibleLocations = set() itemContents = {} for ii in my_logic.iteminfo_list: itemContents[ii] = ii.read(rom) # Feed the logic items one sphere at a time while remainingItems: e = explorer.Explorer() e.visit(my_logic.start) newLocations = e.getAccessableLocations() - lastAccessibleLocations if not newLocations: # Some locations must be inaccessible, stop counting spheres break for location in newLocations: for ii in location.items: ii.metadata.sphere = currentSphere ii.item = itemContents[ii] if ii in remainingItems: remainingItems.remove(ii) lastAccessibleLocations = e.getAccessableLocations() currentSphere += 1 for ii in remainingItems: ii.item = itemContents[ii] for location in e.getAccessableLocations(): for ii in location.items: self.accessibleItems.append( SpoilerItemInfo(ii, rom, args.multiworld)) if len(e.getAccessableLocations()) != len(my_logic.location_list): self.inaccessibleItems = [] for loc in my_logic.location_list: if loc not in e.getAccessableLocations(): for ii in loc.items: self.inaccessibleItems.append( SpoilerItemInfo(ii, rom, args.multiworld)) def output(self, filename=None, zipFile=None): if self.outputFormat == "text": self.outputTextFile(filename, zipFile) elif self.outputFormat == "json": self.outputJson(filename, zipFile) elif self.outputFormat == "console": print(self) def outputTextFile(self, filename=None, zipFile=None): if not filename: filename = "LADXR_%s.txt" % self.seed if zipFile: zipFile.writestr(filename, str(self)) else: with open(filename, 'w') as logFile: logFile.write(str(self)) print("Saved: %s" % filename) def outputJson(self, filename=None, zipFile=None): if not filename: filename = "LADXR_%s.json" % self.seed jsonContent = json.dumps(self, default=lambda x: x.__dict__) if zipFile: zipFile.writestr(filename, jsonContent) else: with open(filename, 'w') as logFile: logFile.write(jsonContent) print("Saved: %s" % filename) def __repr__(self): if not self.testOnly: lines = [ "Dungeon order:" + ", ".join( map(lambda n: "D%d:%d" % (n[0] + 1, n[1] + 1), enumerate(self.world_setup.dungeon_entrance_mapping))) ] lines += [ str(x) for x in sorted( self.accessibleItems, key=lambda x: (x.sphere if x.sphere is not None else sys. maxsize, x.area, x.locationName)) ] if self.inaccessibleItems: lines.append("Logic failure! Cannot access all locations.") lines.append("Failed to find:") lines += [ str(x) for x in sorted( self.inaccessibleItems, key=lambda x: (x.sphere if x.sphere is not None else sys. maxsize, x.area, x.locationName)) ] else: lines.append("Success! All locations can be accessed.") return '\n'.join(lines)
def __init__(self, options, *, seed=None): self.seed = seed self.plan = None if self.seed is None: self.seed = os.urandom(16) self.rnd = random.Random(self.seed) if options.race: self.rnd.random() # Just pull 1 random number so race seeds are different then from normal seeds but still stable. if options.goal == "random": options.goal = self.rnd.randint(-1, 8) if options.plan: assert options.multiworld is None self.plan = Plan(options.plan) if options.multiworld: self.__logic = logic.MultiworldLogic(options, self.rnd) else: world_setup = WorldSetup() world_setup.randomize(options, self.rnd) self.__logic = logic.Logic(options, world_setup=world_setup) if self.plan: for ii in self.__logic.iteminfo_list: item = self.plan.forced_items.get(ii.nameId.upper(), None) if isinstance(item, list): ii.OPTIONS = item else: ii.forced_item = item if not options.keysanity or options.forwardfactor: item_placer = ForwardItemPlacer(self.__logic, options.forwardfactor, options.accessibility_rule) else: item_placer = RandomItemPlacer(self.__logic, options.accessibility_rule) for item, count in self.readItemPool(options, item_placer).items(): if count > 0: item_placer.addItem(item, count) item_placer.run(self.rnd) if options.multiworld: z = None if options.output_filename is not None: z = zipfile.ZipFile(options.output_filename, "w") for n in range(options.multiworld): rom = generator.generateRom(options.multiworld_options[n], self.seed, self.__logic, multiworld=n) fname = "LADXR_Multiworld_%d_%d.gbc" % (options.multiworld, n + 1) if z: handle = z.open(fname, "w") rom.save(handle, name="LADXR") handle.close() else: rom.save(fname, name="LADXR") if options.spoilerformat != "none" and not options.race: extension = "json" if options.spoilerformat == "json" else "txt" sfname = "LADXR_Multiworld_%d_%d.%s" % (options.multiworld, n + 1, extension) log = spoilerLog.SpoilerLog(options, rom) log.output(sfname, z) else: rom = generator.generateRom(options, self.seed, self.__logic) filename = options.output_filename if filename is None: filename = "LADXR_%s.gbc" % (binascii.hexlify(self.seed).decode("ascii").upper()) rom.save(filename, name="LADXR") if options.spoilerformat != "none" and not options.race: log = spoilerLog.SpoilerLog(options, rom) log.output(options.spoiler_filename)
def __init__(self, options, *, seed=None): self.seed = seed self.plan = None if self.seed is None: self.seed = os.urandom(16) self.rnd = random.Random(self.seed) if options.race: self.rnd.random( ) # Just pull 1 random number so race seeds are different then from normal seeds but still stable. if isinstance(options.goal, range): options.goal = self.rnd.randint(min(options.goal), max(options.goal)) if options.plan: assert options.multiworld is None self.plan = Plan(options.plan) if options.multiworld: self.__logic = logic.MultiworldLogic(options, self.rnd) else: for n in range( 1000 ): # Try the world setup in case entrance randomization generates unsolvable logic world_setup = WorldSetup() world_setup.randomize(options, self.rnd) self.__logic = logic.Logic(options, world_setup=world_setup) if options.entranceshuffle not in ( "advanced", "expert", "insanity") or len( self.__logic.iteminfo_list) == sum( itempool.ItemPool(options, self.rnd).toDict().values()): break if self.plan: for ii in self.__logic.iteminfo_list: item = self.plan.forced_items.get(ii.nameId.upper(), None) if isinstance(item, list): ii.OPTIONS = item else: ii.forced_item = item if options.multiworld: item_placer = MultiworldItemPlacer( self.__logic, options.forwardfactor if options.forwardfactor else 0.5, options.accessibility_rule, options.multiworld) elif options.dungeon_items in ('standard', 'localkeys') or options.forwardfactor: item_placer = ForwardItemPlacer(self.__logic, options.forwardfactor, options.accessibility_rule) else: item_placer = RandomItemPlacer(self.__logic, options.accessibility_rule) for item, count in self.readItemPool(options, item_placer).items(): if count > 0: item_placer.addItem(item, count) item_placer.run(self.rnd) if options.multiworld: z = None if options.output_filename is not None: z = zipfile.ZipFile(options.output_filename, "w") z.write( os.path.join(os.path.dirname(__file__), "multiworld/bizhawkConnector.lua"), "bizhawkConnector.lua") z.write( os.path.join(os.path.dirname(__file__), "multiworld/socket.dll"), "socket.dll") roms = [] for n in range(options.multiworld): rom = generator.generateRom(options.multiworld_options[n], self.seed, self.__logic, rnd=self.rnd, multiworld=n) fname = "LADXR_Multiworld_%d_%d.gbc" % (options.multiworld, n + 1) if z: handle = z.open(fname, "w") rom.save(handle, name="LADXR") handle.close() else: rom.save(fname, name="LADXR") roms.append(rom) if (options.spoilerformat != "none" or options.log_directory) and not options.race: log = spoilerLog.SpoilerLog(options, roms) if options.log_directory: filename = "LADXR_Multiworld_%d_%s_%s.json" % ( options.multiworld, datetime.now().strftime("%Y-%m-%d_%H-%M-%S"), log.seed) log_path = os.path.join(options.log_directory, filename) log.outputJson(log_path) if options.spoilerformat != "none": extension = "json" if options.spoilerformat == "json" else "txt" sfname = "LADXR_Multiworld_%d.%s" % (options.multiworld, extension) log.output(sfname, z) else: rom = generator.generateRom(options, self.seed, self.__logic, rnd=self.rnd) filename = options.output_filename if filename is None: filename = "LADXR_%s.gbc" % (binascii.hexlify( self.seed).decode("ascii").upper()) rom.save(filename, name="LADXR") if (options.spoilerformat != "none" or options.log_directory) and not options.race: log = spoilerLog.SpoilerLog(options, [rom]) if options.log_directory: filename = "LADXR_%s_%s.json" % ( datetime.now().strftime("%Y-%m-%d_%H-%M-%S"), log.seed) log_path = os.path.join(options.log_directory, filename) log.outputJson(log_path) if options.spoilerformat != "none": log.output(options.spoiler_filename)