Exemple #1
0
    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)
Exemple #2
0
    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
Exemple #3
0
    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)
Exemple #4
0
    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
Exemple #5
0
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)
Exemple #6
0
    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)
Exemple #7
0
    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)