Zork Grand Inquisitor: Implement New Game (#2539)
Adds Archipelago support for Zork Grand Inquisitor, the 1997 point-and-click PC adventure game. The client (based on `CommonClient`), on top of its regular Archipelago duties, fully handles the randomization of the game and the monitoring / modification of the game state. No game modding needed at all; the player is ready to play an Archipelago seed if they can play the vanilla game through ScummVM. The "reverse engineering" (there's likely a better term for this...) of the game is my own original work and I included an MIT license at the root of my world directory. A PopTracker pack was also created to help people learn the game: https://github.com/SerpentAI/ZorkGrandInquisitorAPTracker
This commit is contained in:
		
							parent
							
								
									e0e9fdd86a
								
							
						
					
					
						commit
						2a8784ef72
					
				| 
						 | 
					@ -61,6 +61,7 @@ Currently, the following games are supported:
 | 
				
			||||||
* TUNIC
 | 
					* TUNIC
 | 
				
			||||||
* Kirby's Dream Land 3
 | 
					* Kirby's Dream Land 3
 | 
				
			||||||
* Celeste 64
 | 
					* Celeste 64
 | 
				
			||||||
 | 
					* Zork Grand Inquisitor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
 | 
					For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
 | 
				
			||||||
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
 | 
					Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,6 +188,9 @@
 | 
				
			||||||
# Zillion
 | 
					# Zillion
 | 
				
			||||||
/worlds/zillion/ @beauxq
 | 
					/worlds/zillion/ @beauxq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Zork Grand Inquisitor
 | 
				
			||||||
 | 
					/worlds/zork_grand_inquisitor/ @nbrochu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##################################
 | 
					##################################
 | 
				
			||||||
## Disabled Unmaintained Worlds ##
 | 
					## Disabled Unmaintained Worlds ##
 | 
				
			||||||
##################################
 | 
					##################################
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					MIT License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2023 Serpent.AI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					import worlds.LauncherComponents as LauncherComponents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .world import ZorkGrandInquisitorWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def launch_client() -> None:
 | 
				
			||||||
 | 
					    from .client import main
 | 
				
			||||||
 | 
					    LauncherComponents.launch_subprocess(main, name="ZorkGrandInquisitorClient")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LauncherComponents.components.append(
 | 
				
			||||||
 | 
					    LauncherComponents.Component(
 | 
				
			||||||
 | 
					        "Zork Grand Inquisitor Client",
 | 
				
			||||||
 | 
					        func=launch_client,
 | 
				
			||||||
 | 
					        component_type=LauncherComponents.Type.CLIENT
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,188 @@
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import CommonClient
 | 
				
			||||||
 | 
					import NetUtils
 | 
				
			||||||
 | 
					import Utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import Any, Dict, List, Optional, Set, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .data_funcs import item_names_to_id, location_names_to_id, id_to_items, id_to_locations, id_to_goals
 | 
				
			||||||
 | 
					from .enums import ZorkGrandInquisitorItems, ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					from .game_controller import GameController
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorCommandProcessor(CommonClient.ClientCommandProcessor):
 | 
				
			||||||
 | 
					    def _cmd_zork(self) -> None:
 | 
				
			||||||
 | 
					        """Attach to an open Zork Grand Inquisitor process."""
 | 
				
			||||||
 | 
					        result: bool = self.ctx.game_controller.open_process_handle()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if result:
 | 
				
			||||||
 | 
					            self.ctx.process_attached_at_least_once = True
 | 
				
			||||||
 | 
					            self.output("Successfully attached to Zork Grand Inquisitor process.")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.output("Failed to attach to Zork Grand Inquisitor process.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _cmd_brog(self) -> None:
 | 
				
			||||||
 | 
					        """List received Brog items."""
 | 
				
			||||||
 | 
					        self.ctx.game_controller.list_received_brog_items()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _cmd_griff(self) -> None:
 | 
				
			||||||
 | 
					        """List received Griff items."""
 | 
				
			||||||
 | 
					        self.ctx.game_controller.list_received_griff_items()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _cmd_lucy(self) -> None:
 | 
				
			||||||
 | 
					        """List received Lucy items."""
 | 
				
			||||||
 | 
					        self.ctx.game_controller.list_received_lucy_items()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _cmd_hotspots(self) -> None:
 | 
				
			||||||
 | 
					        """List received Hotspots."""
 | 
				
			||||||
 | 
					        self.ctx.game_controller.list_received_hotspots()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorContext(CommonClient.CommonContext):
 | 
				
			||||||
 | 
					    tags: Set[str] = {"AP"}
 | 
				
			||||||
 | 
					    game: str = "Zork Grand Inquisitor"
 | 
				
			||||||
 | 
					    command_processor: CommonClient.ClientCommandProcessor = ZorkGrandInquisitorCommandProcessor
 | 
				
			||||||
 | 
					    items_handling: int = 0b111
 | 
				
			||||||
 | 
					    want_slot_data: bool = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item_name_to_id: Dict[str, int] = item_names_to_id()
 | 
				
			||||||
 | 
					    location_name_to_id: Dict[str, int] = location_names_to_id()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    id_to_items: Dict[int, ZorkGrandInquisitorItems] = id_to_items()
 | 
				
			||||||
 | 
					    id_to_locations: Dict[int, ZorkGrandInquisitorLocations] = id_to_locations()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    game_controller: GameController
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    controller_task: Optional[asyncio.Task]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process_attached_at_least_once: bool
 | 
				
			||||||
 | 
					    can_display_process_message: bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, server_address: Optional[str], password: Optional[str]) -> None:
 | 
				
			||||||
 | 
					        super().__init__(server_address, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.game_controller = GameController(logger=CommonClient.logger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.controller_task = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.process_attached_at_least_once = False
 | 
				
			||||||
 | 
					        self.can_display_process_message = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run_gui(self) -> None:
 | 
				
			||||||
 | 
					        from kvui import GameManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TextManager(GameManager):
 | 
				
			||||||
 | 
					            logging_pairs: List[Tuple[str, str]] = [("Client", "Archipelago")]
 | 
				
			||||||
 | 
					            base_title: str = "Archipelago Zork Grand Inquisitor Client"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui = TextManager(self)
 | 
				
			||||||
 | 
					        self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def server_auth(self, password_requested: bool = False):
 | 
				
			||||||
 | 
					        if password_requested and not self.password:
 | 
				
			||||||
 | 
					            await super().server_auth(password_requested)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await self.get_username()
 | 
				
			||||||
 | 
					        await self.send_connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_package(self, cmd: str, _args: Any) -> None:
 | 
				
			||||||
 | 
					        if cmd == "Connected":
 | 
				
			||||||
 | 
					            self.game = self.slot_info[self.slot].game
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Options
 | 
				
			||||||
 | 
					            self.game_controller.option_goal = id_to_goals()[_args["slot_data"]["goal"]]
 | 
				
			||||||
 | 
					            self.game_controller.option_deathsanity = _args["slot_data"]["deathsanity"] == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.game_controller.option_grant_missable_location_checks = (
 | 
				
			||||||
 | 
					                _args["slot_data"]["grant_missable_location_checks"] == 1
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def controller(self):
 | 
				
			||||||
 | 
					        while not self.exit_event.is_set():
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Enqueue Received Item Delta
 | 
				
			||||||
 | 
					            network_item: NetUtils.NetworkItem
 | 
				
			||||||
 | 
					            for network_item in self.items_received:
 | 
				
			||||||
 | 
					                item: ZorkGrandInquisitorItems = self.id_to_items[network_item.item]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if item not in self.game_controller.received_items:
 | 
				
			||||||
 | 
					                    if item not in self.game_controller.received_items_queue:
 | 
				
			||||||
 | 
					                        self.game_controller.received_items_queue.append(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Game Controller Update
 | 
				
			||||||
 | 
					            if self.game_controller.is_process_running():
 | 
				
			||||||
 | 
					                self.game_controller.update()
 | 
				
			||||||
 | 
					                self.can_display_process_message = True
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                process_message: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if self.process_attached_at_least_once:
 | 
				
			||||||
 | 
					                    process_message = (
 | 
				
			||||||
 | 
					                        "Lost connection to Zork Grand Inquisitor process. Please restart the game and use the /zork "
 | 
				
			||||||
 | 
					                        "command to reattach."
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    process_message = (
 | 
				
			||||||
 | 
					                        "Please use the /zork command to attach to a running Zork Grand Inquisitor process."
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if self.can_display_process_message:
 | 
				
			||||||
 | 
					                    CommonClient.logger.info(process_message)
 | 
				
			||||||
 | 
					                    self.can_display_process_message = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Send Checked Locations
 | 
				
			||||||
 | 
					            checked_location_ids: List[int] = list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while len(self.game_controller.completed_locations_queue) > 0:
 | 
				
			||||||
 | 
					                location: ZorkGrandInquisitorLocations = self.game_controller.completed_locations_queue.popleft()
 | 
				
			||||||
 | 
					                location_id: int = self.location_name_to_id[location.value]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                checked_location_ids.append(location_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await self.send_msgs([
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "cmd": "LocationChecks",
 | 
				
			||||||
 | 
					                    "locations": checked_location_ids
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Check for Goal Completion
 | 
				
			||||||
 | 
					            if self.game_controller.goal_completed:
 | 
				
			||||||
 | 
					                await self.send_msgs([
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "cmd": "StatusUpdate",
 | 
				
			||||||
 | 
					                        "status": CommonClient.ClientStatus.CLIENT_GOAL
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main() -> None:
 | 
				
			||||||
 | 
					    Utils.init_logging("ZorkGrandInquisitorClient", exception_logger="Client")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def _main():
 | 
				
			||||||
 | 
					        ctx: ZorkGrandInquisitorContext = ZorkGrandInquisitorContext(None, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.server_task = asyncio.create_task(CommonClient.server_loop(ctx), name="server loop")
 | 
				
			||||||
 | 
					        ctx.controller_task = asyncio.create_task(ctx.controller(), name="ZorkGrandInquisitorController")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if CommonClient.gui_enabled:
 | 
				
			||||||
 | 
					            ctx.run_gui()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.run_cli()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await ctx.exit_event.wait()
 | 
				
			||||||
 | 
					        await ctx.shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    import colorama
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    colorama.init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    asyncio.run(_main())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    colorama.deinit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,419 @@
 | 
				
			||||||
 | 
					from typing import Dict, Tuple, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorEvents, ZorkGrandInquisitorItems, ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					entrance_rule_data: Dict[
 | 
				
			||||||
 | 
					    Tuple[
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Union[
 | 
				
			||||||
 | 
					        Tuple[
 | 
				
			||||||
 | 
					            Tuple[
 | 
				
			||||||
 | 
					                Union[
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                ...,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            ...,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        None,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					] = {
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.DM_LAIR): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SWORD,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_DUNGEON_MASTERS_LAIR_ENTRANCE,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_DM_LAIR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.GUE_TECH): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_REZROV,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_IN_MAGIC_WE_TRUST_DOOR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_GUE_TECH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_HADES,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.PORT_FOOZLE): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_SPELL_LAB,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SUBWAY_TOKEN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_SUBWAY_TOKEN_SLOT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_MONASTERY,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.DOOR_SMOKED_CIGAR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.DOOR_DRANK_MEAD,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_GUE_TECH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_HADES,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_SPELL_LAB,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_MONASTERY,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR, ZorkGrandInquisitorRegions.DM_LAIR): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR, ZorkGrandInquisitorRegions.WALKING_CASTLE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_BLINDS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.KNOWS_OBIDIL,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR, ZorkGrandInquisitorRegions.WHITE_HOUSE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_CLOSET_DOOR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_NARWILE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.KNOWS_YASTARD,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO, ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_GRIFF,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_DRAGON_CLAW,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO, ZorkGrandInquisitorRegions.HADES_BEYOND_GATES): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON, ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON, ZorkGrandInquisitorRegions.ENDGAME): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_AIR_PUMP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_RAFT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_SEA_CAPTAIN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_DRAGON_NOSTRILS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_DRAGON_TOOTH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_1,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_2,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_3,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_4,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TAVERN_FLY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_ALPINES_QUANDRY_CARD_SLOTS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.WHITE_HOUSE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_BROG,  # Needed here since White House is not broken down in 2 regions
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_FLICKERING_TORCH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_GRUE_EGG,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_COOKING_POT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_PLANK,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_SKULL_CAGE,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH, ZorkGrandInquisitorRegions.CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH, ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_IGRAM,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_PURPLE_WORDS,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH, ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.HOTSPOT_GUE_TECH_DOOR,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY, ZorkGrandInquisitorRegions.GUE_TECH): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.STUDENT_ID,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_STUDENT_ID_MACHINE,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.CROSSROADS): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.MAP,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.DM_LAIR): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_DM_LAIR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.GUE_TECH): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_HADES,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_SPELL_LAB,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_MONASTERY,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES, ZorkGrandInquisitorRegions.HADES_BEYOND_GATES): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.KNOWS_SNAVIG,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_BROG,  # Visually hiding this totem is tied to owning it; no choice
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.POUCH_OF_ZORKMIDS,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_BEYOND_GATES, ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_NARWILE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.KNOWS_YASTARD,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_BEYOND_GATES, ZorkGrandInquisitorRegions.HADES): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.CROSSROADS): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.MAP,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.DM_LAIR): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_DM_LAIR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_GUE_TECH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.HADES): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_HADES_PHONE_RECEIVER,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_HADES_PHONE_BUTTONS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.POUCH_OF_ZORKMIDS,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_SPELL_LAB,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_FLOOD_CONTROL_DAM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_MONASTERY,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MENU, ZorkGrandInquisitorRegions.PORT_FOOZLE): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MONASTERY, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_STRAIGHT_TO_HELL,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_WHEELS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_SWITCH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MONASTERY, ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_HALL_OF_INQUISITION,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_WHEELS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_SWITCH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MONASTERY, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT, ZorkGrandInquisitorRegions.MONASTERY): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT, ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_CLOSING_THE_TIME_TUNNELS_LEVER,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_CLOSING_THE_TIME_TUNNELS_HAMMER_SLOT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LARGE_TELEGRAPH_HAMMER,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_NARWILE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.KNOWS_YASTARD,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE, ZorkGrandInquisitorRegions.CROSSROADS): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.LANTERN_DALBOZ_ACCESSIBLE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.ROPE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_WELL,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE, ZorkGrandInquisitorRegions.PORT_FOOZLE_JACKS_SHOP): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.CIGAR_ACCESSIBLE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_GRAND_INQUISITOR_DOLL,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE_JACKS_SHOP, ZorkGrandInquisitorRegions.PORT_FOOZLE): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST, ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST, ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_LUCY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_PORT_FOOZLE_PAST_TAVERN_DOOR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN, ZorkGrandInquisitorRegions.ENDGAME): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_1,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_2,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_3,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_4,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TAVERN_FLY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_ALPINES_QUANDRY_CARD_SLOTS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_AIR_PUMP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_RAFT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_SEA_CAPTAIN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_DRAGON_NOSTRILS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_DRAGON_TOOTH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.WHITE_HOUSE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_BROG,  # Needed here since White House is not broken down in 2 regions
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_FLICKERING_TORCH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_GRUE_EGG,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_COOKING_POT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_PLANK,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_SKULL_CAGE,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN, ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB, ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.CROSSROADS): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.MAP,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.DM_LAIR): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_DM_LAIR,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_GUE_TECH,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_HADES,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.SPELL_LAB): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SWORD,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_ROPE_BRIDGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.DAM_DESTROYED,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_GOLGATEM,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_SPELL_LAB_CHASM,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.MAP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_MONASTERY,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS, ZorkGrandInquisitorRegions.CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_KENDALL,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SUBWAY_DESTINATION_HADES,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS, ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_KENDALL,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SUBWAY_DESTINATION_FLOOD_CONTROL_DAM,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SPELL_KENDALL,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SUBWAY_DESTINATION_MONASTERY,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_HADES,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM, ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM, ZorkGrandInquisitorRegions.SUBWAY_MONASTERY): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_MONASTERY,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_MONASTERY, ZorkGrandInquisitorRegions.HADES_SHORE): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_HADES,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_MONASTERY, ZorkGrandInquisitorRegions.MONASTERY): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.SWORD,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents.ROPE_GLORFABLE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_MONASTERY_VENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_MONASTERY, ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.SUBWAY_MONASTERY, ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM): (
 | 
				
			||||||
 | 
					        (ZorkGrandInquisitorItems.SUBWAY_DESTINATION_FLOOD_CONTROL_DAM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.WALKING_CASTLE, ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.WHITE_HOUSE, ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR): None,
 | 
				
			||||||
 | 
					    (ZorkGrandInquisitorRegions.WHITE_HOUSE, ZorkGrandInquisitorRegions.ENDGAME): (
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.TOTEM_BROG,  # Needed here since White House is not broken down in 2 regions
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_FLICKERING_TORCH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_GRUE_EGG,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_COOKING_POT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.BROGS_PLANK,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_SKULL_CAGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_AIR_PUMP,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_RAFT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_SEA_CAPTAIN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_DRAGON_NOSTRILS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.GRIFFS_DRAGON_TOOTH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_1,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_2,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_3,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_4,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_TAVERN_FLY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems.HOTSPOT_ALPINES_QUANDRY_CARD_SLOTS,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,792 @@
 | 
				
			||||||
 | 
					from typing import Dict, NamedTuple, Optional, Tuple, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from BaseClasses import ItemClassification
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorItems, ZorkGrandInquisitorTags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorItemData(NamedTuple):
 | 
				
			||||||
 | 
					    statemap_keys: Optional[Tuple[int, ...]]
 | 
				
			||||||
 | 
					    archipelago_id: Optional[int]
 | 
				
			||||||
 | 
					    classification: ItemClassification
 | 
				
			||||||
 | 
					    tags: Tuple[ZorkGrandInquisitorTags, ...]
 | 
				
			||||||
 | 
					    maximum_quantity: Optional[int] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ITEM_OFFSET = 9758067000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					item_data: Dict[ZorkGrandInquisitorItems, ZorkGrandInquisitorItemData] = {
 | 
				
			||||||
 | 
					    # Inventory Items
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.BROGS_BICKERING_TORCH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(67,),  # Extinguished = 103
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.BROGS_FLICKERING_TORCH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(68,),  # Extinguished = 104
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.BROGS_GRUE_EGG: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(70,),  # Boiled = 71
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.BROGS_PLANK: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(69,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FLATHEADIA_FUDGE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(54,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 4,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.GRIFFS_AIR_PUMP: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(86,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 5,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.GRIFFS_DRAGON_TOOTH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(84,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 6,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_RAFT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 7,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.GRIFFS_INFLATABLE_SEA_CAPTAIN: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(16,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 8,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HAMMER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(23,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 9,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HUNGUS_LARD: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(55,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 10,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.JAR_OF_HOTBUGS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(56,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 11,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LANTERN: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 12,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LARGE_TELEGRAPH_HAMMER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(88,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 13,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_1: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(116,),  # With fly = 120
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 14,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_2: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(117,),  # With fly = 121
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 15,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_3: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(118,),  # With fly = 122
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 16,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.LUCYS_PLAYING_CARD_4: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(119,),  # With fly = 123
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 17,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.MAP: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(6,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 18,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.MEAD_LIGHT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(2,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 19,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.MOSS_OF_MAREILON: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(57,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 20,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.MUG: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(35,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 21,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.OLD_SCRATCH_CARD: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(17,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 22,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.PERMA_SUCK_MACHINE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(36,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 23,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.PLASTIC_SIX_PACK_HOLDER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(3,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 24,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.POUCH_OF_ZORKMIDS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(5827,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 25,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.PROZORK_TABLET: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(65,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 26,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.QUELBEE_HONEYCOMB: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(53,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 27,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.ROPE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(83,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 28,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SCROLL_FRAGMENT_ANS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(101,),  # SNA = 41
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 29,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SCROLL_FRAGMENT_GIV: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(102,),  # VIG = 48
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 30,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SHOVEL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(49,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 31,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SNAPDRAGON: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(50,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 32,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.STUDENT_ID: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(39,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 33,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SUBWAY_TOKEN: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(20,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 34,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SWORD: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(21,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 35,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.ZIMDOR_SCROLL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(25,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 36,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.ZORK_ROCKS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(37,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 37,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.INVENTORY_ITEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Hotspots
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_666_MAILBOX: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9116,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_ALPINES_QUANDRY_CARD_SLOTS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(15434, 15436, 15438, 15440),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_BLANK_SCROLL_BOX: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12096,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_BLINDS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4799,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CANDY_MACHINE_BUTTONS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12691, 12692, 12693, 12694, 12695, 12696, 12697, 12698, 12699, 12700, 12701),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 4,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CANDY_MACHINE_COIN_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12702,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 5,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CANDY_MACHINE_VACUUM_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12909,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 6,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CHANGE_MACHINE_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12900,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 7,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CLOSET_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(5010,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 8,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CLOSING_THE_TIME_TUNNELS_HAMMER_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9539,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 9,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_CLOSING_THE_TIME_TUNNELS_LEVER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(19712,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 10,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_COOKING_POT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(2586,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 11,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DENTED_LOCKER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(11878,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 12,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DIRT_MOUND: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(11751,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 13,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DOCK_WINCH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(15147, 15153),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 14,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DRAGON_CLAW: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(1705,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 15,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DRAGON_NOSTRILS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(1425, 1426),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 16,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_DUNGEON_MASTERS_LAIR_ENTRANCE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13106,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 17,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_FLOOD_CONTROL_BUTTONS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13219, 13220, 13221, 13222),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 18,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_FLOOD_CONTROL_DOORS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(14327, 14332, 14337, 14342),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 19,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_FROZEN_TREAT_MACHINE_COIN_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12528,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 20,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_FROZEN_TREAT_MACHINE_DOORS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12523, 12524, 12525),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 21,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_GLASS_CASE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13002,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 22,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_GRAND_INQUISITOR_DOLL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(10726,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 23,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_GUE_TECH_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12280,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 24,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_GUE_TECH_GRASS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(
 | 
				
			||||||
 | 
					            17694,
 | 
				
			||||||
 | 
					            17695,
 | 
				
			||||||
 | 
					            17696,
 | 
				
			||||||
 | 
					            17697,
 | 
				
			||||||
 | 
					            18200,
 | 
				
			||||||
 | 
					            17703,
 | 
				
			||||||
 | 
					            17704,
 | 
				
			||||||
 | 
					            17705,
 | 
				
			||||||
 | 
					            17710,
 | 
				
			||||||
 | 
					            17711,
 | 
				
			||||||
 | 
					            17712,
 | 
				
			||||||
 | 
					            17713,
 | 
				
			||||||
 | 
					            17714,
 | 
				
			||||||
 | 
					            17715,
 | 
				
			||||||
 | 
					            17716,
 | 
				
			||||||
 | 
					            17722,
 | 
				
			||||||
 | 
					            17723,
 | 
				
			||||||
 | 
					            17724,
 | 
				
			||||||
 | 
					            17725,
 | 
				
			||||||
 | 
					            17726,
 | 
				
			||||||
 | 
					            17727
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 25,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_HADES_PHONE_BUTTONS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(8448, 8449, 8450, 8451, 8452, 8453, 8454, 8455, 8456, 8457, 8458, 8459),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 26,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_HADES_PHONE_RECEIVER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(8446,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 27,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_HARRY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4260,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 28,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_HARRYS_ASHTRAY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(18026,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 29,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_HARRYS_BIRD_BATH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(17623,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 30,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_IN_MAGIC_WE_TRUST_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13140,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 31,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_JACKS_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(10441,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 32,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_LOUDSPEAKER_VOLUME_BUTTONS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(19632, 19627),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 33,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_MAILBOX_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(3025,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 34,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_MAILBOX_FLAG: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(3036,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 35,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_MIRROR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(5031,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 36,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_MONASTERY_VENT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13597,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 37,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_MOSSY_GRATE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13390,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 38,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_PORT_FOOZLE_PAST_TAVERN_DOOR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(2455, 2447),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 39,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_PURPLE_WORDS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12389, 12390),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 40,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_QUELBEE_HIVE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4302,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 41,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_ROPE_BRIDGE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(16383, 16384),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 42,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SKULL_CAGE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(2769,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 43,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SNAPDRAGON: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4149,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 44,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SODA_MACHINE_BUTTONS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12584, 12585, 12586, 12587),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 45,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SODA_MACHINE_COIN_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12574,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 46,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SOUVENIR_COIN_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13412,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 47,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SPELL_CHECKER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(12170,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 48,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SPELL_LAB_CHASM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(16382,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 49,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SPRING_MUSHROOM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4209,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 50,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_STUDENT_ID_MACHINE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(11973,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 51,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_SUBWAY_TOKEN_SLOT: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13168,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 52,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_TAVERN_FLY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(15396,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 53,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_SWITCH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9706,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 54,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_TOTEMIZER_WHEELS: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9728, 9729, 9730),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 55,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.HOTSPOT_WELL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(10314,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 100 + 56,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.HOTSPOT,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Spells
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_GLORF: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(202,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_GOLGATEM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(192,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_IGRAM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(199,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_KENDALL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(196,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_NARWILE: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(197,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 4,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_REZROV: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(195,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 5,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_THROCK: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(200,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 6,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SPELL_VOXAM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(191,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 200 + 7,
 | 
				
			||||||
 | 
					        classification=ItemClassification.useful,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SPELL,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Subway Destinations
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SUBWAY_DESTINATION_FLOOD_CONTROL_DAM: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13757, 13297, 13486, 13625),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 300 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SUBWAY_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SUBWAY_DESTINATION_HADES: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13758, 13309, 13498, 13637),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 300 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SUBWAY_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.SUBWAY_DESTINATION_MONASTERY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(13759, 13316, 13505, 13644),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 300 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.SUBWAY_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Teleporter Destinations
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_DM_LAIR: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(2203,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 400 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TELEPORTER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_GUE_TECH: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(7132,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 400 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TELEPORTER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_HADES: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(7119,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 400 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TELEPORTER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_MONASTERY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(7148,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 400 + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TELEPORTER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TELEPORTER_DESTINATION_SPELL_LAB: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(16545,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 400 + 4,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TELEPORTER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Totemizer Destinations
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_HALL_OF_INQUISITION: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9660,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 500 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEMIZER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_INFINITY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9666,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 500 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEMIZER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_STRAIGHT_TO_HELL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9668,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 500 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEMIZER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEMIZER_DESTINATION_SURFACE_OF_MERZ: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(9662,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 500 + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEMIZER_DESTINATION,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Totems
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEM_BROG: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4853,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 600 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEM_GRIFF: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(4315,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 600 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.TOTEM_LUCY: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=(5223,),
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 600 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.progression,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.TOTEM,),
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    # Filler
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FILLER_INQUISITION_PROPAGANDA_FLYER: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=None,
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 700 + 0,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.FILLER,),
 | 
				
			||||||
 | 
					        maximum_quantity=None,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FILLER_UNREADABLE_SPELL_SCROLL: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=None,
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 700 + 1,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.FILLER,),
 | 
				
			||||||
 | 
					        maximum_quantity=None,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FILLER_MAGIC_CONTRABAND: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=None,
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 700 + 2,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.FILLER,),
 | 
				
			||||||
 | 
					        maximum_quantity=None,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FILLER_FROBOZZ_ELECTRIC_GADGET: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=None,
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 700 + 3,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.FILLER,),
 | 
				
			||||||
 | 
					        maximum_quantity=None,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems.FILLER_NONSENSICAL_INQUISITION_PAPERWORK: ZorkGrandInquisitorItemData(
 | 
				
			||||||
 | 
					        statemap_keys=None,
 | 
				
			||||||
 | 
					        archipelago_id=ITEM_OFFSET + 700 + 4,
 | 
				
			||||||
 | 
					        classification=ItemClassification.filler,
 | 
				
			||||||
 | 
					        tags=(ZorkGrandInquisitorTags.FILLER,),
 | 
				
			||||||
 | 
					        maximum_quantity=None,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -0,0 +1,200 @@
 | 
				
			||||||
 | 
					from typing import Dict, NamedTuple, Optional, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorItems, ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorMissableLocationGrantConditionsData(NamedTuple):
 | 
				
			||||||
 | 
					    location_condition: ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					    item_conditions: Optional[Tuple[ZorkGrandInquisitorItems, ...]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					missable_location_grant_conditions_data: Dict[
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations, ZorkGrandInquisitorMissableLocationGrantConditionsData
 | 
				
			||||||
 | 
					] = {
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.BOING_BOING_BOING:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FLYING_SNAPDRAGON,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.BONK:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.PROZORKED,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.HAMMER,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_ARRESTED_WITH_JACK:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.ARREST_THE_VANDAL,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_ATTACKED_THE_QUELBEES:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.OUTSMART_THE_QUELBEES,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_EATEN_BY_A_GRUE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.MAGIC_FOREVER,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_LOST_GAME_OF_STRIP_GRUE_FIRE_WATER:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.STRIP_GRUE_FIRE_WATER,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_LOST_SOUL_TO_OLD_SCRATCH:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.OLD_SCRATCH_WINNER,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_OUTSMARTED_BY_THE_QUELBEES:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.OUTSMART_THE_QUELBEES,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_SLICED_UP_BY_THE_INVISIBLE_GUARD:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.YOU_GAINED_86_EXPERIENCE_POINTS,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_STEPPED_INTO_THE_INFINITE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.A_SMALLWAY,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_SWALLOWED_BY_A_DRAGON:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.THAR_SHE_BLOWS,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_YOURE_NOT_CHARON:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.OPEN_THE_GATES_OF_HELL,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DEATH_ZORK_ROCKS_EXPLODED:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.CRISIS_AVERTED,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.DENIED_BY_THE_LAKE_MONSTER:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.WOW_IVE_NEVER_GONE_INSIDE_HIM_BEFORE,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SPELL_GOLGATEM,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.EMERGENCY_MAGICATRONIC_MESSAGE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.ARTIFACTS_EXPLAINED,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.FAT_LOT_OF_GOOD_THATLL_DO_YA:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.YOU_GAINED_86_EXPERIENCE_POINTS,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SPELL_IGRAM,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.I_DONT_THINK_YOU_WOULDVE_WANTED_THAT_TO_WORK_ANYWAY:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.PROZORKED,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SPELL_THROCK,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.I_SPIT_ON_YOUR_FILTHY_COINAGE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.YOU_GAINED_86_EXPERIENCE_POINTS,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.POUCH_OF_ZORKMIDS,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.MEAD_LIGHT:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FIRE_FIRE,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.MEAD_LIGHT,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.MUSHROOM_HAMMERED:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.THROCKED_MUSHROOM_HAMMERED,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.NO_AUTOGRAPHS:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FIRE_FIRE,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.NO_BONDAGE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.HELP_ME_CANT_BREATHE,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.ROPE,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.TALK_TO_ME_GRAND_INQUISITOR:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FIRE_FIRE,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.THATS_A_ROPE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FIRE_FIRE,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.ROPE,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.THATS_IT_JUST_KEEP_HITTING_THOSE_BUTTONS:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.ENJOY_YOUR_TRIP,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.THATS_STILL_A_ROPE:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.YOU_GAINED_86_EXPERIENCE_POINTS,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SPELL_GLORF,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.WHAT_ARE_YOU_STUPID:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.FIRE_FIRE,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.PLASTIC_SIX_PACK_HOLDER,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.YAD_GOHDNUORGREDNU_3_YRAUBORF:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.REASSEMBLE_SNAVIG,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.YOUR_PUNY_WEAPONS_DONT_PHASE_ME_BABY:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.WANT_SOME_RYE_COURSE_YA_DO,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SWORD, ZorkGrandInquisitorItems.HOTSPOT_HARRY),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.YOU_DONT_GO_MESSING_WITH_A_MANS_ZIPPER:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.YOU_GAINED_86_EXPERIENCE_POINTS,
 | 
				
			||||||
 | 
					            item_conditions=(ZorkGrandInquisitorItems.SPELL_REZROV,),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations.YOU_WANT_A_PIECE_OF_ME_DOCK_BOY:
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorMissableLocationGrantConditionsData(
 | 
				
			||||||
 | 
					            location_condition=ZorkGrandInquisitorLocations.HELP_ME_CANT_BREATHE,
 | 
				
			||||||
 | 
					            item_conditions=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,183 @@
 | 
				
			||||||
 | 
					from typing import Dict, NamedTuple, Optional, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorRegionData(NamedTuple):
 | 
				
			||||||
 | 
					    exits: Optional[Tuple[ZorkGrandInquisitorRegions, ...]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					region_data: Dict[ZorkGrandInquisitorRegions, ZorkGrandInquisitorRegionData] = {
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.CROSSROADS: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.DM_LAIR: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.WALKING_CASTLE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.WHITE_HOUSE,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_BEYOND_GATES,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.ENDGAME,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.ENDGAME: ZorkGrandInquisitorRegionData(exits=None),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.GUE_TECH: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.HADES: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_BEYOND_GATES,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.HADES_BEYOND_GATES: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.HADES_SHORE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.MENU: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(ZorkGrandInquisitorRegions.PORT_FOOZLE,)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.MONASTERY: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.MONASTERY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.PORT_FOOZLE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_JACKS_SHOP,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.PORT_FOOZLE_JACKS_SHOP: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(ZorkGrandInquisitorRegions.PORT_FOOZLE,)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.MONASTERY_EXHIBIT,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST_TAVERN: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.ENDGAME,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.PORT_FOOZLE_PAST,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.SPELL_LAB: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE,)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.SPELL_LAB_BRIDGE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.GUE_TECH_HALLWAY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SPELL_LAB,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_MONASTERY,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.SUBWAY_MONASTERY: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.HADES_SHORE,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.MONASTERY,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_CROSSROADS,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.SUBWAY_FLOOD_CONTROL_DAM,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.WALKING_CASTLE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR,)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions.WHITE_HOUSE: ZorkGrandInquisitorRegionData(
 | 
				
			||||||
 | 
					        exits=(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions.ENDGAME,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,247 @@
 | 
				
			||||||
 | 
					from typing import Dict, Set, Tuple, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .data.entrance_rule_data import entrance_rule_data
 | 
				
			||||||
 | 
					from .data.item_data import item_data, ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					from .data.location_data import location_data, ZorkGrandInquisitorLocationData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .enums import (
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorGoals,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorTags,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def item_names_to_id() -> Dict[str, int]:
 | 
				
			||||||
 | 
					    return {item.value: data.archipelago_id for item, data in item_data.items()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def item_names_to_item() -> Dict[str, ZorkGrandInquisitorItems]:
 | 
				
			||||||
 | 
					    return {item.value: item for item in item_data}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def location_names_to_id() -> Dict[str, int]:
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        location.value: data.archipelago_id
 | 
				
			||||||
 | 
					        for location, data in location_data.items()
 | 
				
			||||||
 | 
					        if data.archipelago_id is not None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def location_names_to_location() -> Dict[str, ZorkGrandInquisitorLocations]:
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        location.value: location
 | 
				
			||||||
 | 
					        for location, data in location_data.items()
 | 
				
			||||||
 | 
					        if data.archipelago_id is not None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def id_to_goals() -> Dict[int, ZorkGrandInquisitorGoals]:
 | 
				
			||||||
 | 
					    return {goal.value: goal for goal in ZorkGrandInquisitorGoals}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def id_to_items() -> Dict[int, ZorkGrandInquisitorItems]:
 | 
				
			||||||
 | 
					    return {data.archipelago_id: item for item, data in item_data.items()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def id_to_locations() -> Dict[int, ZorkGrandInquisitorLocations]:
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        data.archipelago_id: location
 | 
				
			||||||
 | 
					        for location, data in location_data.items()
 | 
				
			||||||
 | 
					        if data.archipelago_id is not None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def item_groups() -> Dict[str, Set[str]]:
 | 
				
			||||||
 | 
					    groups: Dict[str, Set[str]] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item: ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					    for item, data in item_data.items():
 | 
				
			||||||
 | 
					        if data.tags is not None:
 | 
				
			||||||
 | 
					            for tag in data.tags:
 | 
				
			||||||
 | 
					                groups.setdefault(tag.value, set()).add(item.value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {k: v for k, v in groups.items() if len(v)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def items_with_tag(tag: ZorkGrandInquisitorTags) -> Set[ZorkGrandInquisitorItems]:
 | 
				
			||||||
 | 
					    items: Set[ZorkGrandInquisitorItems] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item: ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					    for item, data in item_data.items():
 | 
				
			||||||
 | 
					        if data.tags is not None and tag in data.tags:
 | 
				
			||||||
 | 
					            items.add(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def game_id_to_items() -> Dict[int, ZorkGrandInquisitorItems]:
 | 
				
			||||||
 | 
					    mapping: Dict[int, ZorkGrandInquisitorItems] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item: ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					    for item, data in item_data.items():
 | 
				
			||||||
 | 
					        if data.statemap_keys is not None:
 | 
				
			||||||
 | 
					            for key in data.statemap_keys:
 | 
				
			||||||
 | 
					                mapping[key] = item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def location_groups() -> Dict[str, Set[str]]:
 | 
				
			||||||
 | 
					    groups: Dict[str, Set[str]] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tag: ZorkGrandInquisitorTags
 | 
				
			||||||
 | 
					    for tag in ZorkGrandInquisitorTags:
 | 
				
			||||||
 | 
					        groups[tag.value] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    location: ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorLocationData
 | 
				
			||||||
 | 
					    for location, data in location_data.items():
 | 
				
			||||||
 | 
					        if data.tags is not None:
 | 
				
			||||||
 | 
					            for tag in data.tags:
 | 
				
			||||||
 | 
					                groups[tag.value].add(location.value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {k: v for k, v in groups.items() if len(v)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def locations_by_region(include_deathsanity: bool = False) -> Dict[
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions, Set[ZorkGrandInquisitorLocations]
 | 
				
			||||||
 | 
					]:
 | 
				
			||||||
 | 
					    mapping: Dict[ZorkGrandInquisitorRegions, Set[ZorkGrandInquisitorLocations]] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    region: ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					    for region in ZorkGrandInquisitorRegions:
 | 
				
			||||||
 | 
					        mapping[region] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    location: ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorLocationData
 | 
				
			||||||
 | 
					    for location, data in location_data.items():
 | 
				
			||||||
 | 
					        if not include_deathsanity and ZorkGrandInquisitorTags.DEATHSANITY in (
 | 
				
			||||||
 | 
					            data.tags or tuple()
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mapping[data.region].add(location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def locations_with_tag(tag: ZorkGrandInquisitorTags) -> Set[ZorkGrandInquisitorLocations]:
 | 
				
			||||||
 | 
					    location: ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorLocationData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {location for location, data in location_data.items() if data.tags is not None and tag in data.tags}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def location_access_rule_for(location: ZorkGrandInquisitorLocations, player: int) -> str:
 | 
				
			||||||
 | 
					    data: ZorkGrandInquisitorLocationData = location_data[location]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if data.requirements is None:
 | 
				
			||||||
 | 
					        return "lambda state: True"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lambda_string: str = "lambda state: "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i: int
 | 
				
			||||||
 | 
					    requirement: Union[
 | 
				
			||||||
 | 
					        Tuple[
 | 
				
			||||||
 | 
					            Union[
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            ...,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					        ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for i, requirement in enumerate(data.requirements):
 | 
				
			||||||
 | 
					        if isinstance(requirement, tuple):
 | 
				
			||||||
 | 
					            lambda_string += "("
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ii: int
 | 
				
			||||||
 | 
					            sub_requirement: Union[ZorkGrandInquisitorEvents, ZorkGrandInquisitorItems]
 | 
				
			||||||
 | 
					            for ii, sub_requirement in enumerate(requirement):
 | 
				
			||||||
 | 
					                lambda_string += f"state.has(\"{sub_requirement.value}\", {player})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if ii < len(requirement) - 1:
 | 
				
			||||||
 | 
					                    lambda_string += " or "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lambda_string += ")"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            lambda_string += f"state.has(\"{requirement.value}\", {player})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if i < len(data.requirements) - 1:
 | 
				
			||||||
 | 
					            lambda_string += " and "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return lambda_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def entrance_access_rule_for(
 | 
				
			||||||
 | 
					    region_origin: ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					    region_destination: ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					    player: int
 | 
				
			||||||
 | 
					) -> str:
 | 
				
			||||||
 | 
					    data: Union[
 | 
				
			||||||
 | 
					        Tuple[
 | 
				
			||||||
 | 
					            Tuple[
 | 
				
			||||||
 | 
					                Union[
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                ...,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            ...,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        None,
 | 
				
			||||||
 | 
					    ] = entrance_rule_data[(region_origin, region_destination)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if data is None:
 | 
				
			||||||
 | 
					        return "lambda state: True"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lambda_string: str = "lambda state: "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i: int
 | 
				
			||||||
 | 
					    requirement_group: Tuple[
 | 
				
			||||||
 | 
					        Union[
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        ...,
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    for i, requirement_group in enumerate(data):
 | 
				
			||||||
 | 
					        lambda_string += "("
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ii: int
 | 
				
			||||||
 | 
					        requirement: Union[
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        for ii, requirement in enumerate(requirement_group):
 | 
				
			||||||
 | 
					            requirement_type: Union[
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					            ] = type(requirement)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if requirement_type in (ZorkGrandInquisitorEvents, ZorkGrandInquisitorItems):
 | 
				
			||||||
 | 
					                lambda_string += f"state.has(\"{requirement.value}\", {player})"
 | 
				
			||||||
 | 
					            elif requirement_type == ZorkGrandInquisitorRegions:
 | 
				
			||||||
 | 
					                lambda_string += f"state.can_reach(\"{requirement.value}\", \"Region\", {player})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ii < len(requirement_group) - 1:
 | 
				
			||||||
 | 
					                lambda_string += " and "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lambda_string += ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if i < len(data) - 1:
 | 
				
			||||||
 | 
					            lambda_string += " or "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return lambda_string
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					# Zork Grand Inquisitor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Where is the options page?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The [player options page for this game](../player-options) contains all the options you need to configure and export a
 | 
				
			||||||
 | 
					configuration file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Is a tracker available for this game?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yes! You can download the latest PopTracker pack for Zork Grand Inquisitor [here](https://github.com/SerpentAI/ZorkGrandInquisitorAPTracker/releases/latest).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What does randomization do to this game?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A majority of inventory items you can normally pick up are completely removed from the game (e.g. the lantern won't be 
 | 
				
			||||||
 | 
					in the crate, the mead won't be at the fish market, etc.). Instead, these items will be distributed in the multiworld.
 | 
				
			||||||
 | 
					This means that you can expect to access areas and be in a position to solve certain puzzles in a completely different 
 | 
				
			||||||
 | 
					order than you normally would.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Subway, teleporter and totemizer destinations are initially locked and need to be unlocked by receiving the 
 | 
				
			||||||
 | 
					corresponding item in the multiworld. This alone enables creative routing in a game that would otherwise be rather 
 | 
				
			||||||
 | 
					linear. The Crossroads destination is always unlocked for both the subway and teleporter to prevent softlocks. Until you
 | 
				
			||||||
 | 
					receive your first totemizer destination, it will be locked to Newark, New Jersey. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Important hotspots are also randomized. This means that you will be unable to interact with certain objects until you 
 | 
				
			||||||
 | 
					receive the corresponding item in the multiworld. This can be a bit confusing at first, but it adds depth to the
 | 
				
			||||||
 | 
					randomization and makes the game more interesting to play.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can travel back to the surface without dying by looking inside the bucket. This will work as long as the rope is
 | 
				
			||||||
 | 
					still attached to the well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Attempting to cast VOXAM will teleport you back to the Crossroads. Fast Travel!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What item types are distributed in the multiworld?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Inventory items
 | 
				
			||||||
 | 
					- Pouch of Zorkmids
 | 
				
			||||||
 | 
					- Spells
 | 
				
			||||||
 | 
					- Totems
 | 
				
			||||||
 | 
					- Subway destinations
 | 
				
			||||||
 | 
					- Teleporter destinations
 | 
				
			||||||
 | 
					- Totemizer destinations
 | 
				
			||||||
 | 
					- Hotspots (with option to start with the items enabling them instead if you prefer not playing with the randomization 
 | 
				
			||||||
 | 
					  of hotspots)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## When the player receives an item, what happens?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **Inventory items**: Directly added to the player's inventory.
 | 
				
			||||||
 | 
					- **Pouch of Zorkmids**: Appears on the inventory screen. The player can then pick up Zorkmid coins from it.
 | 
				
			||||||
 | 
					- **Spells**: Learned and directly added to the spell book.
 | 
				
			||||||
 | 
					- **Totems**: Appears on the inventory screen.
 | 
				
			||||||
 | 
					- **Subway destinations**: The destination button on the subway map becomes functional.
 | 
				
			||||||
 | 
					- **Teleporter destinations**: The destination can show up on the teleporter screen.
 | 
				
			||||||
 | 
					- **Totemizer destinations**: The destination button on the panel becomes functional.
 | 
				
			||||||
 | 
					- **Hotspots**: The hotspot becomes interactable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What is considered a location check in Zork Grand Inquisitor?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Solving puzzles
 | 
				
			||||||
 | 
					- Accessing certain areas for the first time
 | 
				
			||||||
 | 
					- Triggering certain interactions, even if they aren't puzzles per se
 | 
				
			||||||
 | 
					- Dying in unique ways (Optional; Deathsanity option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## The location check names are fun but don't always convey well what's needed to unlock them. Is there a guide?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yes! You can find a complete guide for the location checks [here](https://gist.github.com/nbrochu/f7bed7a1fef4e2beb67ad6ddbf18b970).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What is the victory condition?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Victory is achieved when the 3 artifacts of magic are retrieved and placed inside the walking castle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Can I use the save system without a problem?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Absolutely! The save system is fully supported (and its use is in fact strongly encouraged!). You can save and load your 
 | 
				
			||||||
 | 
					game as you normally would and the client will automatically sync your items and hotspots with what you should have in 
 | 
				
			||||||
 | 
					that game state. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Depending on how your game progresses, there's a chance that certain location checks might become missable. This 
 | 
				
			||||||
 | 
					presents an excellent opportunity to utilize the save system. Simply make it a habit to save before undertaking 
 | 
				
			||||||
 | 
					irreversible actions, ensuring you can revert to a previous state if necessary. If you prefer not to depend on the save 
 | 
				
			||||||
 | 
					system for accessing missable location checks, there's an option to automatically unlock them as they become 
 | 
				
			||||||
 | 
					unavailable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Unique Local Commands
 | 
				
			||||||
 | 
					The following commands are only available when using the Zork Grand Inquisitor Client to play the game with Archipelago.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `/zork` Attempts to attach to a running instance of Zork Grand Inquisitor. If successful, the client will then be able 
 | 
				
			||||||
 | 
					   to read and control the state of the game.
 | 
				
			||||||
 | 
					- `/brog` Lists received items for Brog.
 | 
				
			||||||
 | 
					- `/griff` Lists received items for Griff.
 | 
				
			||||||
 | 
					- `/lucy` Lists received items for Lucy.
 | 
				
			||||||
 | 
					- `/hotspots` Lists received hotspots.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Known issues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- You will get a second rope right after using GLORF (one in your inventory and one on your cursor). This is a harmless
 | 
				
			||||||
 | 
					  side effect that will go away after you store it in your inventory as duplicates are actively removed.
 | 
				
			||||||
 | 
					- After climbing up to the Monastery for the first time, a rope will forever remain in place in the vent. When you come
 | 
				
			||||||
 | 
					  back to the Monastery, you will be able to climb up without needing to combine the sword and rope again. However, when
 | 
				
			||||||
 | 
					  arriving at the top, you will receive a duplicate sword on a rope. This is a harmless side effect that will go away
 | 
				
			||||||
 | 
					  after you store it in your inventory as duplicates are actively removed.
 | 
				
			||||||
 | 
					- Since the client is reading and manipulating the game's memory, rare game crashes can happen. If you encounter one, 
 | 
				
			||||||
 | 
					  simply restart the game, load your latest save and use the `/zork` command again in the client. Nothing will be lost.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					# Zork Grand Inquisitor Randomizer Setup Guide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Windows OS (Hard required. Client is using memory reading / writing through Win32 API)
 | 
				
			||||||
 | 
					- A copy of Zork Grand Inquisitor. Only the GOG version is supported. The Steam version can work with some tinkering but
 | 
				
			||||||
 | 
					  is not officially supported.
 | 
				
			||||||
 | 
					- ScummVM 2.7.1 64-bit (Important: Will not work with any other version. [Direct Download](https://downloads.scummvm.org/frs/scummvm/2.7.1/scummvm-2.7.1-win32-x86_64.zip))
 | 
				
			||||||
 | 
					- Archipelago 0.4.4+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Game Setup Instructions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					No game modding is required to play Zork Grand Inquisitor with Archipelago. The client does all the work by attaching to
 | 
				
			||||||
 | 
					the game process and reading and manipulating the game state in real-time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This being said, the game does need to be played through ScummVM 2.7.1, so some configuration is required around that.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### GOG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Open the directory where you installed Zork Grand Inquisitor. You should see a `Launch Zork Grand Inquisitor`
 | 
				
			||||||
 | 
					  shortcut.
 | 
				
			||||||
 | 
					- Open the `scummvm` directory. Delete the entire contents of that directory.
 | 
				
			||||||
 | 
					- Still inside the `scummvm` directory, unzip the contents of the ScummVM 2.7.1 zip file you downloaded earlier.
 | 
				
			||||||
 | 
					- Go back to the directory where you installed Zork Grand Inquisitor.
 | 
				
			||||||
 | 
					- Verify that the game still launches when using the `Launch Zork Grand Inquisitor` shortcut.
 | 
				
			||||||
 | 
					- Your game is now ready to be played with Archipelago. From now on, you can use the `Launch Zork Grand Inquisitor`
 | 
				
			||||||
 | 
					  shortcut to launch the game.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Joining a Multiworld Game
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Launch Zork Grand Inquisitor and start a new game.
 | 
				
			||||||
 | 
					- Open the Archipelago Launcher and click `Zork Grand Inquisitor Client`.
 | 
				
			||||||
 | 
					- Using the `Zork Grand Inquisitor Client`:
 | 
				
			||||||
 | 
					  - Enter the room's hostname and port number (e.g. `archipelago.gg:54321`) in the top box and press `Connect`.
 | 
				
			||||||
 | 
					  - Input your player name at the bottom when prompted and press `Enter`.
 | 
				
			||||||
 | 
					  - You should now be connected to the Archipelago room.
 | 
				
			||||||
 | 
					  - Next, input `/zork` at the bottom and press `Enter`. This will attach the client to the game process.
 | 
				
			||||||
 | 
					  - If the command is successful, you are now ready to play Zork Grand Inquisitor with Archipelago.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Continuing a Multiworld Game
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Perform the same steps as above, but instead of starting a new game, load your latest save file.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,350 @@
 | 
				
			||||||
 | 
					import enum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorEvents(enum.Enum):
 | 
				
			||||||
 | 
					    CHARON_CALLED = "Event: Charon Called"
 | 
				
			||||||
 | 
					    CIGAR_ACCESSIBLE = "Event: Cigar Accessible"
 | 
				
			||||||
 | 
					    DALBOZ_LOCKER_OPENABLE = "Event: Dalboz Locker Openable"
 | 
				
			||||||
 | 
					    DAM_DESTROYED = "Event: Dam Destroyed"
 | 
				
			||||||
 | 
					    DOOR_DRANK_MEAD = "Event: Door Drank Mead"
 | 
				
			||||||
 | 
					    DOOR_SMOKED_CIGAR = "Event: Door Smoked Cigar"
 | 
				
			||||||
 | 
					    DUNCE_LOCKER_OPENABLE = "Event: Dunce Locker Openable"
 | 
				
			||||||
 | 
					    HAS_REPAIRABLE_OBIDIL = "Event: Has Repairable OBIDIL"
 | 
				
			||||||
 | 
					    HAS_REPAIRABLE_SNAVIG = "Event: Has Repairable SNAVIG"
 | 
				
			||||||
 | 
					    KNOWS_BEBURTT = "Event: Knows BEBURTT"
 | 
				
			||||||
 | 
					    KNOWS_OBIDIL = "Event: Knows OBIDIL"
 | 
				
			||||||
 | 
					    KNOWS_SNAVIG = "Event: Knows SNAVIG"
 | 
				
			||||||
 | 
					    KNOWS_YASTARD = "Event: Knows YASTARD"
 | 
				
			||||||
 | 
					    LANTERN_DALBOZ_ACCESSIBLE = "Event: Lantern (Dalboz) Accessible"
 | 
				
			||||||
 | 
					    ROPE_GLORFABLE = "Event: Rope GLORFable"
 | 
				
			||||||
 | 
					    VICTORY = "Victory"
 | 
				
			||||||
 | 
					    WHITE_HOUSE_LETTER_MAILABLE = "Event: White House Letter Mailable"
 | 
				
			||||||
 | 
					    ZORKMID_BILL_ACCESSIBLE = "Event: 500 Zorkmid Bill Accessible"
 | 
				
			||||||
 | 
					    ZORK_ROCKS_ACTIVATED = "Event: Zork Rocks Activated"
 | 
				
			||||||
 | 
					    ZORK_ROCKS_SUCKABLE = "Event: Zork Rocks Suckable"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorGoals(enum.Enum):
 | 
				
			||||||
 | 
					    THREE_ARTIFACTS = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorItems(enum.Enum):
 | 
				
			||||||
 | 
					    BROGS_BICKERING_TORCH = "Brog's Bickering Torch"
 | 
				
			||||||
 | 
					    BROGS_FLICKERING_TORCH = "Brog's Flickering Torch"
 | 
				
			||||||
 | 
					    BROGS_GRUE_EGG = "Brog's Grue Egg"
 | 
				
			||||||
 | 
					    BROGS_PLANK = "Brog's Plank"
 | 
				
			||||||
 | 
					    FILLER_FROBOZZ_ELECTRIC_GADGET = "Frobozz Electric Gadget"
 | 
				
			||||||
 | 
					    FILLER_INQUISITION_PROPAGANDA_FLYER = "Inquisition Propaganda Flyer"
 | 
				
			||||||
 | 
					    FILLER_MAGIC_CONTRABAND = "Magic Contraband"
 | 
				
			||||||
 | 
					    FILLER_NONSENSICAL_INQUISITION_PAPERWORK = "Nonsensical Inquisition Paperwork"
 | 
				
			||||||
 | 
					    FILLER_UNREADABLE_SPELL_SCROLL = "Unreadable Spell Scroll"
 | 
				
			||||||
 | 
					    FLATHEADIA_FUDGE = "Flatheadia Fudge"
 | 
				
			||||||
 | 
					    GRIFFS_AIR_PUMP = "Griff's Air Pump"
 | 
				
			||||||
 | 
					    GRIFFS_DRAGON_TOOTH = "Griff's Dragon Tooth"
 | 
				
			||||||
 | 
					    GRIFFS_INFLATABLE_RAFT = "Griff's Inflatable Raft"
 | 
				
			||||||
 | 
					    GRIFFS_INFLATABLE_SEA_CAPTAIN = "Griff's Inflatable Sea Captain"
 | 
				
			||||||
 | 
					    HAMMER = "Hammer"
 | 
				
			||||||
 | 
					    HOTSPOT_666_MAILBOX = "Hotspot: 666 Mailbox"
 | 
				
			||||||
 | 
					    HOTSPOT_ALPINES_QUANDRY_CARD_SLOTS = "Hotspot: Alpine's Quandry Card Slots"
 | 
				
			||||||
 | 
					    HOTSPOT_BLANK_SCROLL_BOX = "Hotspot: Blank Scroll Box"
 | 
				
			||||||
 | 
					    HOTSPOT_BLINDS = "Hotspot: Blinds"
 | 
				
			||||||
 | 
					    HOTSPOT_CANDY_MACHINE_BUTTONS = "Hotspot: Candy Machine Buttons"
 | 
				
			||||||
 | 
					    HOTSPOT_CANDY_MACHINE_COIN_SLOT = "Hotspot: Candy Machine Coin Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_CANDY_MACHINE_VACUUM_SLOT = "Hotspot: Candy Machine Vacuum Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_CHANGE_MACHINE_SLOT = "Hotspot: Change Machine Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_CLOSET_DOOR = "Hotspot: Closet Door"
 | 
				
			||||||
 | 
					    HOTSPOT_CLOSING_THE_TIME_TUNNELS_HAMMER_SLOT = "Hotspot: Closing the Time Tunnels Hammer Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_CLOSING_THE_TIME_TUNNELS_LEVER = "Hotspot: Closing the Time Tunnels Lever"
 | 
				
			||||||
 | 
					    HOTSPOT_COOKING_POT = "Hotspot: Cooking Pot"
 | 
				
			||||||
 | 
					    HOTSPOT_DENTED_LOCKER = "Hotspot: Dented Locker"
 | 
				
			||||||
 | 
					    HOTSPOT_DIRT_MOUND = "Hotspot: Dirt Mound"
 | 
				
			||||||
 | 
					    HOTSPOT_DOCK_WINCH = "Hotspot: Dock Winch"
 | 
				
			||||||
 | 
					    HOTSPOT_DRAGON_CLAW = "Hotspot: Dragon Claw"
 | 
				
			||||||
 | 
					    HOTSPOT_DRAGON_NOSTRILS = "Hotspot: Dragon Nostrils"
 | 
				
			||||||
 | 
					    HOTSPOT_DUNGEON_MASTERS_LAIR_ENTRANCE = "Hotspot: Dungeon Master's Lair Entrance"
 | 
				
			||||||
 | 
					    HOTSPOT_FLOOD_CONTROL_BUTTONS = "Hotspot: Flood Control Buttons"
 | 
				
			||||||
 | 
					    HOTSPOT_FLOOD_CONTROL_DOORS = "Hotspot: Flood Control Doors"
 | 
				
			||||||
 | 
					    HOTSPOT_FROZEN_TREAT_MACHINE_COIN_SLOT = "Hotspot: Frozen Treat Machine Coin Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_FROZEN_TREAT_MACHINE_DOORS = "Hotspot: Frozen Treat Machine Doors"
 | 
				
			||||||
 | 
					    HOTSPOT_GLASS_CASE = "Hotspot: Glass Case"
 | 
				
			||||||
 | 
					    HOTSPOT_GRAND_INQUISITOR_DOLL = "Hotspot: Grand Inquisitor Doll"
 | 
				
			||||||
 | 
					    HOTSPOT_GUE_TECH_DOOR = "Hotspot: GUE Tech Door"
 | 
				
			||||||
 | 
					    HOTSPOT_GUE_TECH_GRASS = "Hotspot: GUE Tech Grass"
 | 
				
			||||||
 | 
					    HOTSPOT_HADES_PHONE_BUTTONS = "Hotspot: Hades Phone Buttons"
 | 
				
			||||||
 | 
					    HOTSPOT_HADES_PHONE_RECEIVER = "Hotspot: Hades Phone Receiver"
 | 
				
			||||||
 | 
					    HOTSPOT_HARRY = "Hotspot: Harry"
 | 
				
			||||||
 | 
					    HOTSPOT_HARRYS_ASHTRAY = "Hotspot: Harry's Ashtray"
 | 
				
			||||||
 | 
					    HOTSPOT_HARRYS_BIRD_BATH = "Hotspot: Harry's Bird Bath"
 | 
				
			||||||
 | 
					    HOTSPOT_IN_MAGIC_WE_TRUST_DOOR = "Hotspot: In Magic We Trust Door"
 | 
				
			||||||
 | 
					    HOTSPOT_JACKS_DOOR = "Hotspot: Jack's Door"
 | 
				
			||||||
 | 
					    HOTSPOT_LOUDSPEAKER_VOLUME_BUTTONS = "Hotspot: Loudspeaker Volume Buttons"
 | 
				
			||||||
 | 
					    HOTSPOT_MAILBOX_DOOR = "Hotspot: Mailbox Door"
 | 
				
			||||||
 | 
					    HOTSPOT_MAILBOX_FLAG = "Hotspot: Mailbox Flag"
 | 
				
			||||||
 | 
					    HOTSPOT_MIRROR = "Hotspot: Mirror"
 | 
				
			||||||
 | 
					    HOTSPOT_MONASTERY_VENT = "Hotspot: Monastery Vent"
 | 
				
			||||||
 | 
					    HOTSPOT_MOSSY_GRATE = "Hotspot: Mossy Grate"
 | 
				
			||||||
 | 
					    HOTSPOT_PORT_FOOZLE_PAST_TAVERN_DOOR = "Hotspot: Port Foozle Past Tavern Door"
 | 
				
			||||||
 | 
					    HOTSPOT_PURPLE_WORDS = "Hotspot: Purple Words"
 | 
				
			||||||
 | 
					    HOTSPOT_QUELBEE_HIVE = "Hotspot: Quelbee Hive"
 | 
				
			||||||
 | 
					    HOTSPOT_ROPE_BRIDGE = "Hotspot: Rope Bridge"
 | 
				
			||||||
 | 
					    HOTSPOT_SKULL_CAGE = "Hotspot: Skull Cage"
 | 
				
			||||||
 | 
					    HOTSPOT_SNAPDRAGON = "Hotspot: Snapdragon"
 | 
				
			||||||
 | 
					    HOTSPOT_SODA_MACHINE_BUTTONS = "Hotspot: Soda Machine Buttons"
 | 
				
			||||||
 | 
					    HOTSPOT_SODA_MACHINE_COIN_SLOT = "Hotspot: Soda Machine Coin Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_SOUVENIR_COIN_SLOT = "Hotspot: Souvenir Coin Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_SPELL_CHECKER = "Hotspot: Spell Checker"
 | 
				
			||||||
 | 
					    HOTSPOT_SPELL_LAB_CHASM = "Hotspot: Spell Lab Chasm"
 | 
				
			||||||
 | 
					    HOTSPOT_SPRING_MUSHROOM = "Hotspot: Spring Mushroom"
 | 
				
			||||||
 | 
					    HOTSPOT_STUDENT_ID_MACHINE = "Hotspot: Student ID Machine"
 | 
				
			||||||
 | 
					    HOTSPOT_SUBWAY_TOKEN_SLOT = "Hotspot: Subway Token Slot"
 | 
				
			||||||
 | 
					    HOTSPOT_TAVERN_FLY = "Hotspot: Tavern Fly"
 | 
				
			||||||
 | 
					    HOTSPOT_TOTEMIZER_SWITCH = "Hotspot: Totemizer Switch"
 | 
				
			||||||
 | 
					    HOTSPOT_TOTEMIZER_WHEELS = "Hotspot: Totemizer Wheels"
 | 
				
			||||||
 | 
					    HOTSPOT_WELL = "Hotspot: Well"
 | 
				
			||||||
 | 
					    HUNGUS_LARD = "Hungus Lard"
 | 
				
			||||||
 | 
					    JAR_OF_HOTBUGS = "Jar of Hotbugs"
 | 
				
			||||||
 | 
					    LANTERN = "Lantern"
 | 
				
			||||||
 | 
					    LARGE_TELEGRAPH_HAMMER = "Large Telegraph Hammer"
 | 
				
			||||||
 | 
					    LUCYS_PLAYING_CARD_1 = "Lucy's Playing Card: 1 Pip"
 | 
				
			||||||
 | 
					    LUCYS_PLAYING_CARD_2 = "Lucy's Playing Card: 2 Pips"
 | 
				
			||||||
 | 
					    LUCYS_PLAYING_CARD_3 = "Lucy's Playing Card: 3 Pips"
 | 
				
			||||||
 | 
					    LUCYS_PLAYING_CARD_4 = "Lucy's Playing Card: 4 Pips"
 | 
				
			||||||
 | 
					    MAP = "Map"
 | 
				
			||||||
 | 
					    MEAD_LIGHT = "Mead Light"
 | 
				
			||||||
 | 
					    MOSS_OF_MAREILON = "Moss of Mareilon"
 | 
				
			||||||
 | 
					    MUG = "Mug"
 | 
				
			||||||
 | 
					    OLD_SCRATCH_CARD = "Old Scratch Card"
 | 
				
			||||||
 | 
					    PERMA_SUCK_MACHINE = "Perma-Suck Machine"
 | 
				
			||||||
 | 
					    PLASTIC_SIX_PACK_HOLDER = "Plastic Six-Pack Holder"
 | 
				
			||||||
 | 
					    POUCH_OF_ZORKMIDS = "Pouch of Zorkmids"
 | 
				
			||||||
 | 
					    PROZORK_TABLET = "Prozork Tablet"
 | 
				
			||||||
 | 
					    QUELBEE_HONEYCOMB = "Quelbee Honeycomb"
 | 
				
			||||||
 | 
					    ROPE = "Rope"
 | 
				
			||||||
 | 
					    SCROLL_FRAGMENT_ANS = "Scroll Fragment: ANS"
 | 
				
			||||||
 | 
					    SCROLL_FRAGMENT_GIV = "Scroll Fragment: GIV"
 | 
				
			||||||
 | 
					    SHOVEL = "Shovel"
 | 
				
			||||||
 | 
					    SNAPDRAGON = "Snapdragon"
 | 
				
			||||||
 | 
					    SPELL_GLORF = "Spell: GLORF"
 | 
				
			||||||
 | 
					    SPELL_GOLGATEM = "Spell: GOLGATEM"
 | 
				
			||||||
 | 
					    SPELL_IGRAM = "Spell: IGRAM"
 | 
				
			||||||
 | 
					    SPELL_KENDALL = "Spell: KENDALL"
 | 
				
			||||||
 | 
					    SPELL_NARWILE = "Spell: NARWILE"
 | 
				
			||||||
 | 
					    SPELL_REZROV = "Spell: REZROV"
 | 
				
			||||||
 | 
					    SPELL_THROCK = "Spell: THROCK"
 | 
				
			||||||
 | 
					    SPELL_VOXAM = "Spell: VOXAM"
 | 
				
			||||||
 | 
					    STUDENT_ID = "Student ID"
 | 
				
			||||||
 | 
					    SUBWAY_DESTINATION_FLOOD_CONTROL_DAM = "Subway Destination: Flood Control Dam #3"
 | 
				
			||||||
 | 
					    SUBWAY_DESTINATION_HADES = "Subway Destination: Hades"
 | 
				
			||||||
 | 
					    SUBWAY_DESTINATION_MONASTERY = "Subway Destination: Monastery"
 | 
				
			||||||
 | 
					    SUBWAY_TOKEN = "Subway Token"
 | 
				
			||||||
 | 
					    SWORD = "Sword"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION_DM_LAIR = "Teleporter Destination: Dungeon Master's Lair"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION_GUE_TECH = "Teleporter Destination: GUE Tech"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION_HADES = "Teleporter Destination: Hades"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION_MONASTERY = "Teleporter Destination: Monastery Station"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION_SPELL_LAB = "Teleporter Destination: Spell Lab"
 | 
				
			||||||
 | 
					    TOTEM_BROG = "Totem: Brog"
 | 
				
			||||||
 | 
					    TOTEM_GRIFF = "Totem: Griff"
 | 
				
			||||||
 | 
					    TOTEM_LUCY = "Totem: Lucy"
 | 
				
			||||||
 | 
					    TOTEMIZER_DESTINATION_HALL_OF_INQUISITION = "Totemizer Destination: Hall of Inquisition"
 | 
				
			||||||
 | 
					    TOTEMIZER_DESTINATION_INFINITY = "Totemizer Destination: Infinity"
 | 
				
			||||||
 | 
					    TOTEMIZER_DESTINATION_STRAIGHT_TO_HELL = "Totemizer Destination: Straight to Hell"
 | 
				
			||||||
 | 
					    TOTEMIZER_DESTINATION_SURFACE_OF_MERZ = "Totemizer Destination: Surface of Merz"
 | 
				
			||||||
 | 
					    ZIMDOR_SCROLL = "ZIMDOR Scroll"
 | 
				
			||||||
 | 
					    ZORK_ROCKS = "Zork Rocks"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorLocations(enum.Enum):
 | 
				
			||||||
 | 
					    ALARM_SYSTEM_IS_DOWN = "Alarm System is Down"
 | 
				
			||||||
 | 
					    ARREST_THE_VANDAL = "Arrest the Vandal!"
 | 
				
			||||||
 | 
					    ARTIFACTS_EXPLAINED = "Artifacts, Explained"
 | 
				
			||||||
 | 
					    A_BIG_FAT_SASSY_2_HEADED_MONSTER = "A Big, Fat, SASSY 2-Headed Monster"
 | 
				
			||||||
 | 
					    A_LETTER_FROM_THE_WHITE_HOUSE = "A Letter from the White House"
 | 
				
			||||||
 | 
					    A_SMALLWAY = "A Smallway"
 | 
				
			||||||
 | 
					    BEAUTIFUL_THATS_PLENTY = "Beautiful, That's Plenty!"
 | 
				
			||||||
 | 
					    BEBURTT_DEMYSTIFIED = "BEBURTT, Demystified"
 | 
				
			||||||
 | 
					    BETTER_SPELL_MANUFACTURING_IN_UNDER_10_MINUTES = "Better Spell Manufacturing in Under 10 Minutes"
 | 
				
			||||||
 | 
					    BOING_BOING_BOING = "Boing, Boing, Boing"
 | 
				
			||||||
 | 
					    BONK = "Bonk!"
 | 
				
			||||||
 | 
					    BRAVE_SOULS_WANTED = "Brave Souls Wanted"
 | 
				
			||||||
 | 
					    BROG_DO_GOOD = "Brog Do Good!"
 | 
				
			||||||
 | 
					    BROG_EAT_ROCKS = "Brog Eat Rocks"
 | 
				
			||||||
 | 
					    BROG_KNOW_DUMB_THAT_DUMB = "Brog Know Dumb. That Dumb"
 | 
				
			||||||
 | 
					    BROG_MUCH_BETTER_AT_THIS_GAME = "Brog Much Better at This Game"
 | 
				
			||||||
 | 
					    CASTLE_WATCHING_A_FIELD_GUIDE = "Castle Watching: A Field Guide"
 | 
				
			||||||
 | 
					    CAVES_NOTES = "Cave's Notes"
 | 
				
			||||||
 | 
					    CLOSING_THE_TIME_TUNNELS = "Closing the Time Tunnels"
 | 
				
			||||||
 | 
					    CRISIS_AVERTED = "Crisis Averted"
 | 
				
			||||||
 | 
					    CUT_THAT_OUT_YOU_LITTLE_CREEP = "Cut That Out You Little Creep!"
 | 
				
			||||||
 | 
					    DEATH_ARRESTED_WITH_JACK = "Death: Arrested With Jack"
 | 
				
			||||||
 | 
					    DEATH_ATTACKED_THE_QUELBEES = "Death: Attacked the Quelbees"
 | 
				
			||||||
 | 
					    DEATH_CLIMBED_OUT_OF_THE_WELL = "Death: Climbed Out of the Well"
 | 
				
			||||||
 | 
					    DEATH_EATEN_BY_A_GRUE = "Death: Eaten by a Grue"
 | 
				
			||||||
 | 
					    DEATH_JUMPED_IN_BOTTOMLESS_PIT = "Death: Jumped in Bottomless Pit"
 | 
				
			||||||
 | 
					    DEATH_LOST_GAME_OF_STRIP_GRUE_FIRE_WATER = "Death: Lost Game of Strip Grue, Fire, Water"
 | 
				
			||||||
 | 
					    DEATH_LOST_SOUL_TO_OLD_SCRATCH = "Death: Lost Soul to Old Scratch"
 | 
				
			||||||
 | 
					    DEATH_OUTSMARTED_BY_THE_QUELBEES = "Death: Outsmarted by the Quelbees"
 | 
				
			||||||
 | 
					    DEATH_SLICED_UP_BY_THE_INVISIBLE_GUARD = "Death: Sliced up by the Invisible Guard"
 | 
				
			||||||
 | 
					    DEATH_STEPPED_INTO_THE_INFINITE = "Death: Step Into the Infinite"
 | 
				
			||||||
 | 
					    DEATH_SWALLOWED_BY_A_DRAGON = "Death: Swallowed by a Dragon"
 | 
				
			||||||
 | 
					    DEATH_THROCKED_THE_GRASS = "Death: THROCKed the Grass"
 | 
				
			||||||
 | 
					    DEATH_TOTEMIZED = "Death: Totemized?"
 | 
				
			||||||
 | 
					    DEATH_TOTEMIZED_PERMANENTLY = "Death: Totemized... Permanently"
 | 
				
			||||||
 | 
					    DEATH_YOURE_NOT_CHARON = "Death: You're Not Charon!?"
 | 
				
			||||||
 | 
					    DEATH_ZORK_ROCKS_EXPLODED = "Death: Zork Rocks Exploded"
 | 
				
			||||||
 | 
					    DENIED_BY_THE_LAKE_MONSTER = "Denied by the Lake Monster"
 | 
				
			||||||
 | 
					    DESPERATELY_SEEKING_TUTOR = "Desperately Seeking Tutor"
 | 
				
			||||||
 | 
					    DONT_EVEN_START_WITH_US_SPARKY = "Don't Even Start With Us, Sparky"
 | 
				
			||||||
 | 
					    DOOOOOOWN = "Doooooown"
 | 
				
			||||||
 | 
					    DOWN = "Down"
 | 
				
			||||||
 | 
					    DRAGON_ARCHIPELAGO_TIME_TUNNEL = "Dragon Archipelago Time Tunnel"
 | 
				
			||||||
 | 
					    DUNCE_LOCKER = "Dunce Locker"
 | 
				
			||||||
 | 
					    EGGPLANTS = "Eggplants"
 | 
				
			||||||
 | 
					    ELSEWHERE = "Elsewhere"
 | 
				
			||||||
 | 
					    EMERGENCY_MAGICATRONIC_MESSAGE = "Emergency Magicatronic Message"
 | 
				
			||||||
 | 
					    ENJOY_YOUR_TRIP = "Enjoy Your Trip!"
 | 
				
			||||||
 | 
					    FAT_LOT_OF_GOOD_THATLL_DO_YA = "Fat Lot of Good That'll Do Ya"
 | 
				
			||||||
 | 
					    FIRE_FIRE = "Fire! Fire!"
 | 
				
			||||||
 | 
					    FLOOD_CONTROL_DAM_3_THE_NOT_REMOTELY_BORING_TALE = "Flood Control Dam #3: The Not Remotely Boring Tale"
 | 
				
			||||||
 | 
					    FLYING_SNAPDRAGON = "Flying Snapdragon"
 | 
				
			||||||
 | 
					    FROBUARY_3_UNDERGROUNDHOG_DAY = "Frobruary 3 - Undergroundhog Day"
 | 
				
			||||||
 | 
					    GETTING_SOME_CHANGE = "Getting Some Change"
 | 
				
			||||||
 | 
					    GO_AWAY = "GO AWAY!"
 | 
				
			||||||
 | 
					    GUE_TECH_DEANS_LIST = "GUE Tech Dean's List"
 | 
				
			||||||
 | 
					    GUE_TECH_ENTRANCE_EXAM = "GUE Tech Entrance Exam"
 | 
				
			||||||
 | 
					    GUE_TECH_HEALTH_MEMO = "GUE Tech Health Memo"
 | 
				
			||||||
 | 
					    GUE_TECH_MAGEMEISTERS = "GUE Tech Magemeisters"
 | 
				
			||||||
 | 
					    HAVE_A_HELL_OF_A_DAY = "Have a Hell of a Day!"
 | 
				
			||||||
 | 
					    HELLO_THIS_IS_SHONA_FROM_GURTH_PUBLISHING = "Hello, This is Shona from Gurth Publishing"
 | 
				
			||||||
 | 
					    HELP_ME_CANT_BREATHE = "Help... Me. Can't... Breathe"
 | 
				
			||||||
 | 
					    HEY_FREE_DIRT = "Hey, Free Dirt!"
 | 
				
			||||||
 | 
					    HI_MY_NAME_IS_DOUG = "Hi, My Name is Doug"
 | 
				
			||||||
 | 
					    HMMM_INFORMATIVE_YET_DEEPLY_DISTURBING = "Hmmm. Informative. Yet Deeply Disturbing"
 | 
				
			||||||
 | 
					    HOLD_ON_FOR_AN_IMPORTANT_MESSAGE = "Hold on for an Important Message"
 | 
				
			||||||
 | 
					    HOW_TO_HYPNOTIZE_YOURSELF = "How to Hypnotize Yourself"
 | 
				
			||||||
 | 
					    HOW_TO_WIN_AT_DOUBLE_FANUCCI = "How to Win at Double Fanucci"
 | 
				
			||||||
 | 
					    IMBUE_BEBURTT = "Imbue BEBURTT"
 | 
				
			||||||
 | 
					    IM_COMPLETELY_NUDE = "I'm Completely Nude"
 | 
				
			||||||
 | 
					    INTO_THE_FOLIAGE = "Into the Foliage"
 | 
				
			||||||
 | 
					    INVISIBLE_FLOWERS = "Invisible Flowers"
 | 
				
			||||||
 | 
					    IN_CASE_OF_ADVENTURE = "In Case of Adventure, Break Glass!"
 | 
				
			||||||
 | 
					    IN_MAGIC_WE_TRUST = "In Magic We Trust"
 | 
				
			||||||
 | 
					    ITS_ONE_OF_THOSE_ADVENTURERS_AGAIN = "It's One of Those Adventurers Again..."
 | 
				
			||||||
 | 
					    I_DONT_THINK_YOU_WOULDVE_WANTED_THAT_TO_WORK_ANYWAY = "I Don't Think You Would've Wanted That to Work Anyway"
 | 
				
			||||||
 | 
					    I_DONT_WANT_NO_TROUBLE = "I Don't Want No Trouble!"
 | 
				
			||||||
 | 
					    I_HOPE_YOU_CAN_CLIMB_UP_THERE = "I Hope You Can Climb Up There With All This Junk"
 | 
				
			||||||
 | 
					    I_LIKE_YOUR_STYLE = "I Like Your Style!"
 | 
				
			||||||
 | 
					    I_SPIT_ON_YOUR_FILTHY_COINAGE = "I Spit on Your Filthy Coinage"
 | 
				
			||||||
 | 
					    LIT_SUNFLOWERS = "Lit Sunflowers"
 | 
				
			||||||
 | 
					    MAGIC_FOREVER = "Magic Forever!"
 | 
				
			||||||
 | 
					    MAILED_IT_TO_HELL = "Mailed it to Hell"
 | 
				
			||||||
 | 
					    MAKE_LOVE_NOT_WAR = "Make Love, Not War"
 | 
				
			||||||
 | 
					    MEAD_LIGHT = "Mead Light?"
 | 
				
			||||||
 | 
					    MIKES_PANTS = "Mike's Pants"
 | 
				
			||||||
 | 
					    MUSHROOM_HAMMERED = "Mushroom, Hammered"
 | 
				
			||||||
 | 
					    NATIONAL_TREASURE = "300 Year Old National Treasure"
 | 
				
			||||||
 | 
					    NATURAL_AND_SUPERNATURAL_CREATURES_OF_QUENDOR = "Natural and Supernatural Creatures of Quendor"
 | 
				
			||||||
 | 
					    NOOOOOOOOOOOOO = "NOOOOOOOOOOOOO!"
 | 
				
			||||||
 | 
					    NOTHIN_LIKE_A_GOOD_STOGIE = "Nothin' Like a Good Stogie"
 | 
				
			||||||
 | 
					    NOW_YOU_LOOK_LIKE_US_WHICH_IS_AN_IMPROVEMENT = "Now You Look Like Us, Which is an Improvement"
 | 
				
			||||||
 | 
					    NO_AUTOGRAPHS = "No Autographs"
 | 
				
			||||||
 | 
					    NO_BONDAGE = "No Bondage"
 | 
				
			||||||
 | 
					    OBIDIL_DRIED_UP = "OBIDIL, Dried Up"
 | 
				
			||||||
 | 
					    OH_DEAR_GOD_ITS_A_DRAGON = "Oh Dear God, It's a Dragon!"
 | 
				
			||||||
 | 
					    OH_VERY_FUNNY_GUYS = "Oh, Very Funny Guys"
 | 
				
			||||||
 | 
					    OH_WOW_TALK_ABOUT_DEJA_VU = "Oh, Wow! Talk About Deja Vu"
 | 
				
			||||||
 | 
					    OLD_SCRATCH_WINNER = "Old Scratch Winner!"
 | 
				
			||||||
 | 
					    ONLY_YOU_CAN_PREVENT_FOOZLE_FIRES = "Only You Can Prevent Foozle Fires"
 | 
				
			||||||
 | 
					    OPEN_THE_GATES_OF_HELL = "Open the Gates of Hell"
 | 
				
			||||||
 | 
					    OUTSMART_THE_QUELBEES = "Outsmart the Quelbees"
 | 
				
			||||||
 | 
					    PERMASEAL = "PermaSeal"
 | 
				
			||||||
 | 
					    PLANETFALL = "Planetfall"
 | 
				
			||||||
 | 
					    PLEASE_DONT_THROCK_THE_GRASS = "Please Don't THROCK the Grass"
 | 
				
			||||||
 | 
					    PORT_FOOZLE_TIME_TUNNEL = "Port Foozle Time Tunnel"
 | 
				
			||||||
 | 
					    PROZORKED = "Prozorked"
 | 
				
			||||||
 | 
					    REASSEMBLE_SNAVIG = "Reassemble SNAVIG"
 | 
				
			||||||
 | 
					    RESTOCKED_ON_GRUESDAY = "Restocked on Gruesday"
 | 
				
			||||||
 | 
					    RIGHT_HELLO_YES_UH_THIS_IS_SNEFFLE = "Right. Hello. Yes. Uh, This is Sneffle"
 | 
				
			||||||
 | 
					    RIGHT_UH_SORRY_ITS_ME_AGAIN_SNEFFLE = "Right. Uh, Sorry. It's Me Again. Sneffle"
 | 
				
			||||||
 | 
					    SNAVIG_REPAIRED = "SNAVIG, Repaired"
 | 
				
			||||||
 | 
					    SOUVENIR = "Souvenir"
 | 
				
			||||||
 | 
					    STRAIGHT_TO_HELL = "Straight to Hell"
 | 
				
			||||||
 | 
					    STRIP_GRUE_FIRE_WATER = "Strip Grue, Fire, Water"
 | 
				
			||||||
 | 
					    SUCKING_ROCKS = "Sucking Rocks"
 | 
				
			||||||
 | 
					    TALK_TO_ME_GRAND_INQUISITOR = "Talk to Me Grand Inquisitor"
 | 
				
			||||||
 | 
					    TAMING_YOUR_SNAPDRAGON = "Taming Your Snapdragon"
 | 
				
			||||||
 | 
					    THAR_SHE_BLOWS = "Thar She Blows!"
 | 
				
			||||||
 | 
					    THATS_A_ROPE = "That's a Rope"
 | 
				
			||||||
 | 
					    THATS_IT_JUST_KEEP_HITTING_THOSE_BUTTONS = "That's it! Just Keep Hitting Those Buttons"
 | 
				
			||||||
 | 
					    THATS_STILL_A_ROPE = "That's Still a Rope"
 | 
				
			||||||
 | 
					    THATS_THE_SPIRIT = "That's the Spirit!"
 | 
				
			||||||
 | 
					    THE_ALCHEMICAL_DEBACLE = "The Alchemical Debacle"
 | 
				
			||||||
 | 
					    THE_ENDLESS_FIRE = "The Endless Fire"
 | 
				
			||||||
 | 
					    THE_FLATHEADIAN_FUDGE_FIASCO = "The Flatheadian Fudge Fiasco"
 | 
				
			||||||
 | 
					    THE_PERILS_OF_MAGIC = "The Perils of Magic"
 | 
				
			||||||
 | 
					    THE_UNDERGROUND_UNDERGROUND = "The Underground Underground"
 | 
				
			||||||
 | 
					    THIS_DOESNT_LOOK_ANYTHING_LIKE_THE_BROCHURE = "This Doesn't Look Anything Like the Brochure"
 | 
				
			||||||
 | 
					    THROCKED_MUSHROOM_HAMMERED = "THROCKed Mushroom, Hammered"
 | 
				
			||||||
 | 
					    TIME_TRAVEL_FOR_DUMMIES = "Time Travel for Dummies"
 | 
				
			||||||
 | 
					    TOTEMIZED_DAILY_BILLBOARD = "Totemized Daily Billboard Functioning Correctly"
 | 
				
			||||||
 | 
					    UH_OH_BROG_CANT_SWIM = "Uh-Oh. Brog Can't Swim"
 | 
				
			||||||
 | 
					    UMBRELLA_FLOWERS = "Umbrella Flowers"
 | 
				
			||||||
 | 
					    UP = "Up"
 | 
				
			||||||
 | 
					    USELESS_BUT_FUN = "Useless, But Fun"
 | 
				
			||||||
 | 
					    UUUUUP = "Uuuuup"
 | 
				
			||||||
 | 
					    VOYAGE_OF_CAPTAIN_ZAHAB = "Voyage of Captain Zahab"
 | 
				
			||||||
 | 
					    WANT_SOME_RYE_COURSE_YA_DO = "Want Some Rye? Course Ya Do!"
 | 
				
			||||||
 | 
					    WE_DONT_SERVE_YOUR_KIND_HERE = "We Don't Serve Your Kind Here"
 | 
				
			||||||
 | 
					    WE_GOT_A_HIGH_ROLLER = "We Got a High Roller!"
 | 
				
			||||||
 | 
					    WHAT_ARE_YOU_STUPID = "What Are You, Stupid?"
 | 
				
			||||||
 | 
					    WHITE_HOUSE_TIME_TUNNEL = "White House Time Tunnel"
 | 
				
			||||||
 | 
					    WOW_IVE_NEVER_GONE_INSIDE_HIM_BEFORE = "Wow! I've Never Gone Inside Him Before!"
 | 
				
			||||||
 | 
					    YAD_GOHDNUORGREDNU_3_YRAUBORF = "yaD gohdnuorgrednU - 3 yrauborF"
 | 
				
			||||||
 | 
					    YOUR_PUNY_WEAPONS_DONT_PHASE_ME_BABY = "Your Puny Weapons Don't Phase Me, Baby!"
 | 
				
			||||||
 | 
					    YOU_DONT_GO_MESSING_WITH_A_MANS_ZIPPER = "You Don't Go Messing With a Man's Zipper"
 | 
				
			||||||
 | 
					    YOU_GAINED_86_EXPERIENCE_POINTS = "You Gained 86 Experience Points"
 | 
				
			||||||
 | 
					    YOU_ONE_OF_THEM_AGITATORS_AINT_YA = "You One of Them Agitators, Ain't Ya?"
 | 
				
			||||||
 | 
					    YOU_WANT_A_PIECE_OF_ME_DOCK_BOY = "You Want a Piece of Me, Dock Boy? or Girl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorRegions(enum.Enum):
 | 
				
			||||||
 | 
					    CROSSROADS = "Crossroads"
 | 
				
			||||||
 | 
					    DM_LAIR = "Dungeon Master's Lair"
 | 
				
			||||||
 | 
					    DM_LAIR_INTERIOR = "Dungeon Master's Lair - Interior"
 | 
				
			||||||
 | 
					    DRAGON_ARCHIPELAGO = "Dragon Archipelago"
 | 
				
			||||||
 | 
					    DRAGON_ARCHIPELAGO_DRAGON = "Dragon Archipelago - Dragon"
 | 
				
			||||||
 | 
					    ENDGAME = "Endgame"
 | 
				
			||||||
 | 
					    GUE_TECH = "GUE Tech"
 | 
				
			||||||
 | 
					    GUE_TECH_HALLWAY = "GUE Tech - Hallway"
 | 
				
			||||||
 | 
					    GUE_TECH_OUTSIDE = "GUE Tech - Outside"
 | 
				
			||||||
 | 
					    HADES = "Hades"
 | 
				
			||||||
 | 
					    HADES_BEYOND_GATES = "Hades - Beyond Gates"
 | 
				
			||||||
 | 
					    HADES_SHORE = "Hades - Shore"
 | 
				
			||||||
 | 
					    MENU = "Menu"
 | 
				
			||||||
 | 
					    MONASTERY = "Monastery"
 | 
				
			||||||
 | 
					    MONASTERY_EXHIBIT = "Monastery - Exhibit"
 | 
				
			||||||
 | 
					    PORT_FOOZLE = "Port Foozle"
 | 
				
			||||||
 | 
					    PORT_FOOZLE_JACKS_SHOP = "Port Foozle - Jack's Shop"
 | 
				
			||||||
 | 
					    PORT_FOOZLE_PAST = "Port Foozle Past"
 | 
				
			||||||
 | 
					    PORT_FOOZLE_PAST_TAVERN = "Port Foozle Past - Tavern"
 | 
				
			||||||
 | 
					    SPELL_LAB = "Spell Lab"
 | 
				
			||||||
 | 
					    SPELL_LAB_BRIDGE = "Spell Lab - Bridge"
 | 
				
			||||||
 | 
					    SUBWAY_CROSSROADS = "Subway Platform - Crossroads"
 | 
				
			||||||
 | 
					    SUBWAY_FLOOD_CONTROL_DAM = "Subway Platform - Flood Control Dam #3"
 | 
				
			||||||
 | 
					    SUBWAY_MONASTERY = "Subway Platform - Monastery"
 | 
				
			||||||
 | 
					    WALKING_CASTLE = "Walking Castle"
 | 
				
			||||||
 | 
					    WHITE_HOUSE = "White House"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorTags(enum.Enum):
 | 
				
			||||||
 | 
					    CORE = "Core"
 | 
				
			||||||
 | 
					    DEATHSANITY = "Deathsanity"
 | 
				
			||||||
 | 
					    FILLER = "Filler"
 | 
				
			||||||
 | 
					    HOTSPOT = "Hotspot"
 | 
				
			||||||
 | 
					    INVENTORY_ITEM = "Inventory Item"
 | 
				
			||||||
 | 
					    MISSABLE = "Missable"
 | 
				
			||||||
 | 
					    SPELL = "Spell"
 | 
				
			||||||
 | 
					    SUBWAY_DESTINATION = "Subway Destination"
 | 
				
			||||||
 | 
					    TELEPORTER_DESTINATION = "Teleporter Destination"
 | 
				
			||||||
 | 
					    TOTEMIZER_DESTINATION = "Totemizer Destination"
 | 
				
			||||||
 | 
					    TOTEM = "Totem"
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -0,0 +1,370 @@
 | 
				
			||||||
 | 
					from typing import Optional, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from pymem import Pymem
 | 
				
			||||||
 | 
					from pymem.process import close_handle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GameStateManager:
 | 
				
			||||||
 | 
					    process_name = "scummvm.exe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process: Optional[Pymem]
 | 
				
			||||||
 | 
					    is_process_running: bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    script_manager_struct_address: int
 | 
				
			||||||
 | 
					    render_manager_struct_address: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    game_location: Optional[str]
 | 
				
			||||||
 | 
					    game_location_offset: Optional[int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self) -> None:
 | 
				
			||||||
 | 
					        self.process = None
 | 
				
			||||||
 | 
					        self.is_process_running = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.script_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					        self.render_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.game_location = None
 | 
				
			||||||
 | 
					        self.game_location_offset = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_state_storage_pointer_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x88
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_state_storage_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.process.read_longlong(self.game_state_storage_pointer_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_state_hashmap_size_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x90
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_state_key_count_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x94
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_state_deleted_key_count_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x98
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_flags_storage_pointer_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x120
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_flags_storage_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.process.read_longlong(self.game_flags_storage_pointer_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_flags_hashmap_size_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_flags_key_count_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x12C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def game_flags_deleted_key_count_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x130
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def current_location_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def current_location_offset_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x404
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def next_location_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x408
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def next_location_offset_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.script_manager_struct_address + 0x40C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def panorama_reversed_address(self) -> int:
 | 
				
			||||||
 | 
					        return self.render_manager_struct_address + 0x1C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_process_handle(self) -> bool:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.process = Pymem(self.process_name)
 | 
				
			||||||
 | 
					            self.is_process_running = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.script_manager_struct_address = self._resolve_address(0x5276600, (0xC8, 0x0))
 | 
				
			||||||
 | 
					            self.render_manager_struct_address = self._resolve_address(0x5276600, (0xD0, 0x120))
 | 
				
			||||||
 | 
					        except Exception:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_process_handle(self) -> bool:
 | 
				
			||||||
 | 
					        if close_handle(self.process.process_handle):
 | 
				
			||||||
 | 
					            self.is_process_running = False
 | 
				
			||||||
 | 
					            self.process = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.script_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					            self.render_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_process_still_running(self) -> bool:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.process.read_int(self.process.base_address)
 | 
				
			||||||
 | 
					        except Exception:
 | 
				
			||||||
 | 
					            self.is_process_running = False
 | 
				
			||||||
 | 
					            self.process = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.script_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					            self.render_manager_struct_address = 0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read_game_state_value_for(self, key: int) -> Optional[int]:
 | 
				
			||||||
 | 
					        return self.read_statemap_value_for(key, scope="game_state")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read_game_flags_value_for(self, key: int) -> Optional[int]:
 | 
				
			||||||
 | 
					        return self.read_statemap_value_for(key, scope="game_flags")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read_statemap_value_for(self, key: int, scope: str = "game_state") -> Optional[int]:
 | 
				
			||||||
 | 
					        if self.is_process_running:
 | 
				
			||||||
 | 
					            offset: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            address: int
 | 
				
			||||||
 | 
					            address_value: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if scope == "game_state":
 | 
				
			||||||
 | 
					                offset = self._get_game_state_address_read_offset_for(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                address = self.game_state_storage_address + offset
 | 
				
			||||||
 | 
					                address_value = self.process.read_longlong(address)
 | 
				
			||||||
 | 
					            elif scope == "game_flags":
 | 
				
			||||||
 | 
					                offset = self._get_game_flags_address_read_offset_for(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                address = self.game_flags_storage_address + offset
 | 
				
			||||||
 | 
					                address_value = self.process.read_longlong(address)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise ValueError(f"Invalid scope: {scope}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if address_value == 0:
 | 
				
			||||||
 | 
					                return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            statemap_value: int = self.process.read_int(address_value + 0x0)
 | 
				
			||||||
 | 
					            statemap_key: int = self.process.read_int(address_value + 0x4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assert statemap_key == key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return statemap_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write_game_state_value_for(self, key: int, value: int) -> Optional[bool]:
 | 
				
			||||||
 | 
					        return self.write_statemap_value_for(key, value, scope="game_state")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write_game_flags_value_for(self, key: int, value: int) -> Optional[bool]:
 | 
				
			||||||
 | 
					        return self.write_statemap_value_for(key, value, scope="game_flags")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write_statemap_value_for(self, key: int, value: int, scope: str = "game_state") -> Optional[bool]:
 | 
				
			||||||
 | 
					        if self.is_process_running:
 | 
				
			||||||
 | 
					            offset: int
 | 
				
			||||||
 | 
					            is_existing_node: bool
 | 
				
			||||||
 | 
					            is_reused_dummy_node: bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            key_count_address: int
 | 
				
			||||||
 | 
					            deleted_key_count_address: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            storage_address: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if scope == "game_state":
 | 
				
			||||||
 | 
					                offset, is_existing_node, is_reused_dummy_node = self._get_game_state_address_write_offset_for(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                key_count_address = self.game_state_key_count_address
 | 
				
			||||||
 | 
					                deleted_key_count_address = self.game_state_deleted_key_count_address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                storage_address = self.game_state_storage_address
 | 
				
			||||||
 | 
					            elif scope == "game_flags":
 | 
				
			||||||
 | 
					                offset, is_existing_node, is_reused_dummy_node = self._get_game_flags_address_write_offset_for(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                key_count_address = self.game_flags_key_count_address
 | 
				
			||||||
 | 
					                deleted_key_count_address = self.game_flags_deleted_key_count_address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                storage_address = self.game_flags_storage_address
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise ValueError(f"Invalid scope: {scope}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            statemap_key_count: int = self.process.read_int(key_count_address)
 | 
				
			||||||
 | 
					            statemap_deleted_key_count: int = self.process.read_int(deleted_key_count_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if value == 0:
 | 
				
			||||||
 | 
					                if not is_existing_node:
 | 
				
			||||||
 | 
					                    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.process.write_longlong(storage_address + offset, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.process.write_int(key_count_address, statemap_key_count - 1)
 | 
				
			||||||
 | 
					                self.process.write_int(deleted_key_count_address, statemap_deleted_key_count + 1)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if is_existing_node:
 | 
				
			||||||
 | 
					                    address_value: int = self.process.read_longlong(storage_address + offset)
 | 
				
			||||||
 | 
					                    self.process.write_int(address_value + 0x0, value)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    write_address: int = self.process.allocate(0x8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self.process.write_int(write_address + 0x0, value)
 | 
				
			||||||
 | 
					                    self.process.write_int(write_address + 0x4, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self.process.write_longlong(storage_address + offset, write_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self.process.write_int(key_count_address, statemap_key_count + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if is_reused_dummy_node:
 | 
				
			||||||
 | 
					                        self.process.write_int(deleted_key_count_address, statemap_deleted_key_count - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def refresh_game_location(self) -> Optional[bool]:
 | 
				
			||||||
 | 
					        if self.is_process_running:
 | 
				
			||||||
 | 
					            game_location_bytes: bytes = self.process.read_bytes(self.current_location_address, 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.game_location = game_location_bytes.decode("ascii")
 | 
				
			||||||
 | 
					            self.game_location_offset = self.process.read_int(self.current_location_offset_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_game_location(self, game_location: str, offset: int) -> Optional[bool]:
 | 
				
			||||||
 | 
					        if self.is_process_running:
 | 
				
			||||||
 | 
					            game_location_bytes: bytes = game_location.encode("ascii")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.process.write_bytes(self.next_location_address, game_location_bytes, 4)
 | 
				
			||||||
 | 
					            self.process.write_int(self.next_location_offset_address, offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_panorama_reversed(self, is_reversed: bool) -> Optional[bool]:
 | 
				
			||||||
 | 
					        if self.is_process_running:
 | 
				
			||||||
 | 
					            self.process.write_int(self.panorama_reversed_address, 1 if is_reversed else 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _resolve_address(self, base_offset: int, offsets: Tuple[int, ...]):
 | 
				
			||||||
 | 
					        address: int = self.process.read_longlong(self.process.base_address + base_offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for offset in offsets[:-1]:
 | 
				
			||||||
 | 
					            address = self.process.read_longlong(address + offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return address + offsets[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_game_state_address_read_offset_for(self, key: int):
 | 
				
			||||||
 | 
					        return self._get_statemap_address_read_offset_for(key, scope="game_state")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_game_flags_address_read_offset_for(self, key: int):
 | 
				
			||||||
 | 
					        return self._get_statemap_address_read_offset_for(key, scope="game_flags")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_statemap_address_read_offset_for(self, key: int, scope: str = "game_state") -> int:
 | 
				
			||||||
 | 
					        hashmap_size_address: int
 | 
				
			||||||
 | 
					        storage_address: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if scope == "game_state":
 | 
				
			||||||
 | 
					            hashmap_size_address = self.game_state_hashmap_size_address
 | 
				
			||||||
 | 
					            storage_address = self.game_state_storage_address
 | 
				
			||||||
 | 
					        elif scope == "game_flags":
 | 
				
			||||||
 | 
					            hashmap_size_address = self.game_flags_hashmap_size_address
 | 
				
			||||||
 | 
					            storage_address = self.game_flags_storage_address
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise ValueError(f"Invalid scope: {scope}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        statemap_hashmap_size: int = self.process.read_int(hashmap_size_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        perturb: int = key
 | 
				
			||||||
 | 
					        perturb_shift: int = 0x5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        index: int = key & statemap_hashmap_size
 | 
				
			||||||
 | 
					        offset: int = index * 0x8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while True:
 | 
				
			||||||
 | 
					            offset_value: int = self.process.read_longlong(storage_address + offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if offset_value == 0:  # Null Pointer
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            elif offset_value == 1:  # Dummy Node
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            elif offset_value > 1:  # Existing Node
 | 
				
			||||||
 | 
					                if self.process.read_int(offset_value + 0x4) == key:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            index = ((0x5 * index) + perturb + 0x1) & statemap_hashmap_size
 | 
				
			||||||
 | 
					            offset = index * 0x8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            perturb >>= perturb_shift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_game_state_address_write_offset_for(self, key: int) -> Tuple[int, bool, bool]:
 | 
				
			||||||
 | 
					        return self._get_statemap_address_write_offset_for(key, scope="game_state")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_game_flags_address_write_offset_for(self, key: int) -> Tuple[int, bool, bool]:
 | 
				
			||||||
 | 
					        return self._get_statemap_address_write_offset_for(key, scope="game_flags")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_statemap_address_write_offset_for(self, key: int, scope: str = "game_state") -> Tuple[int, bool, bool]:
 | 
				
			||||||
 | 
					        hashmap_size_address: int
 | 
				
			||||||
 | 
					        storage_address: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if scope == "game_state":
 | 
				
			||||||
 | 
					            hashmap_size_address = self.game_state_hashmap_size_address
 | 
				
			||||||
 | 
					            storage_address = self.game_state_storage_address
 | 
				
			||||||
 | 
					        elif scope == "game_flags":
 | 
				
			||||||
 | 
					            hashmap_size_address = self.game_flags_hashmap_size_address
 | 
				
			||||||
 | 
					            storage_address = self.game_flags_storage_address
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise ValueError(f"Invalid scope: {scope}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        statemap_hashmap_size: int = self.process.read_int(hashmap_size_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        perturb: int = key
 | 
				
			||||||
 | 
					        perturb_shift: int = 0x5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        index: int = key & statemap_hashmap_size
 | 
				
			||||||
 | 
					        offset: int = index * 0x8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node_found: bool = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dummy_node_found: bool = False
 | 
				
			||||||
 | 
					        dummy_node_offset: Optional[int] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while True:
 | 
				
			||||||
 | 
					            offset_value: int = self.process.read_longlong(storage_address + offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if offset_value == 0:  # Null Pointer
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            elif offset_value == 1:  # Dummy Node
 | 
				
			||||||
 | 
					                if not dummy_node_found:
 | 
				
			||||||
 | 
					                    dummy_node_offset = offset
 | 
				
			||||||
 | 
					                    dummy_node_found = True
 | 
				
			||||||
 | 
					            elif offset_value > 1:  # Existing Node
 | 
				
			||||||
 | 
					                if self.process.read_int(offset_value + 0x4) == key:
 | 
				
			||||||
 | 
					                    node_found = True
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            index = ((0x5 * index) + perturb + 0x1) & statemap_hashmap_size
 | 
				
			||||||
 | 
					            offset = index * 0x8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            perturb >>= perturb_shift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not node_found and dummy_node_found:  # We should reuse the dummy node
 | 
				
			||||||
 | 
					            return dummy_node_offset, False, True
 | 
				
			||||||
 | 
					        elif not node_found and not dummy_node_found:  # We should allocate a new node
 | 
				
			||||||
 | 
					            return offset, False, False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return offset, True, False  # We should update the existing node
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					from dataclasses import dataclass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from Options import Choice, DefaultOnToggle, PerGameCommonOptions, Toggle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Goal(Choice):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Determines the victory condition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Three Artifacts: Retrieve the three artifacts of magic and place them in the walking castle
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    display_name: str = "Goal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default: int = 0
 | 
				
			||||||
 | 
					    option_three_artifacts: int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QuickPortFoozle(DefaultOnToggle):
 | 
				
			||||||
 | 
					    """If true, the items needed to go down the well will be found in early locations for a smoother early game"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    display_name: str = "Quick Port Foozle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StartWithHotspotItems(DefaultOnToggle):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    If true, the player will be given all the hotspot items at the start of the game, effectively removing the need
 | 
				
			||||||
 | 
					    to enable the important hotspots in the game before interacting with them. Recommended for beginners
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Note: The spots these hotspot items would have occupied in the item pool will instead be filled with junk items.
 | 
				
			||||||
 | 
					    Expect a higher volume of filler items if you enable this option
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    display_name: str = "Start with Hotspot Items"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Deathsanity(Toggle):
 | 
				
			||||||
 | 
					    """If true, adds 16 player death locations to the world"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    display_name: str = "Deathsanity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GrantMissableLocationChecks(Toggle):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    If true, performing an irreversible action will grant the locations checks that would have become unobtainable as a
 | 
				
			||||||
 | 
					    result of that action when you meet the item requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Otherwise, the player is expected to potentially have to use the save system to reach those location checks. If you
 | 
				
			||||||
 | 
					    don't like the idea of rarely having to reload an earlier save to get a location check, make sure this option is
 | 
				
			||||||
 | 
					    enabled
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    display_name: str = "Grant Missable Checks"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dataclass
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorOptions(PerGameCommonOptions):
 | 
				
			||||||
 | 
					    goal: Goal
 | 
				
			||||||
 | 
					    quick_port_foozle: QuickPortFoozle
 | 
				
			||||||
 | 
					    start_with_hotspot_items: StartWithHotspotItems
 | 
				
			||||||
 | 
					    deathsanity: Deathsanity
 | 
				
			||||||
 | 
					    grant_missable_location_checks: GrantMissableLocationChecks
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Pymem>=1.13.0
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					from test.bases import WorldTestBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorTestBase(WorldTestBase):
 | 
				
			||||||
 | 
					    game = "Zork Grand Inquisitor"
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..data_funcs import location_access_rule_for, entrance_access_rule_for
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorLocations, ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataFuncsTest(unittest.TestCase):
 | 
				
			||||||
 | 
					    def test_location_access_rule_for(self) -> None:
 | 
				
			||||||
 | 
					        # No Requirements
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            "lambda state: True",
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.ALARM_SYSTEM_IS_DOWN, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Single Item Requirement
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Sword", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.DONT_EVEN_START_WITH_US_SPARKY, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Spell: NARWILE", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.DRAGON_ARCHIPELAGO_TIME_TUNNEL, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Single Event Requirement
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Event: Knows OBIDIL", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.A_BIG_FAT_SASSY_2_HEADED_MONSTER, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Event: Dunce Locker Openable", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.BETTER_SPELL_MANUFACTURING_IN_UNDER_10_MINUTES, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Item Requirements
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Hotspot: Purple Words", 1) and state.has("Spell: IGRAM", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.A_SMALLWAY, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Hotspot: Mossy Grate", 1) and state.has("Spell: THROCK", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.BEAUTIFUL_THATS_PLENTY, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Item Requirements OR
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Totem: Griff", 1) or state.has("Totem: Lucy", 1)) and state.has("Hotspot: Mailbox Door", 1) and state.has("Hotspot: Mailbox Flag", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.MAILED_IT_TO_HELL, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Mixed Requirements
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Event: Cigar Accessible", 1) and state.has("Hotspot: Grand Inquisitor Doll", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.ARREST_THE_VANDAL, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: state.has("Sword", 1) and state.has("Event: Rope GLORFable", 1) and state.has("Hotspot: Monastery Vent", 1)',
 | 
				
			||||||
 | 
					            location_access_rule_for(ZorkGrandInquisitorLocations.I_HOPE_YOU_CAN_CLIMB_UP_THERE, 1),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_entrance_access_rule_for(self) -> None:
 | 
				
			||||||
 | 
					        # No Requirements
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            "lambda state: True",
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.PORT_FOOZLE, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            "lambda state: True",
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.CROSSROADS, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Single Requirement
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Map", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.GUE_TECH_OUTSIDE, ZorkGrandInquisitorRegions.CROSSROADS, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Map", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.HADES_SHORE, ZorkGrandInquisitorRegions.CROSSROADS, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Requirements AND
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Spell: REZROV", 1) and state.has("Hotspot: In Magic We Trust Door", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.GUE_TECH, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Event: Door Smoked Cigar", 1) and state.has("Event: Door Drank Mead", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.DM_LAIR, ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Hotspot: Closet Door", 1) and state.has("Spell: NARWILE", 1) and state.has("Event: Knows YASTARD", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.DM_LAIR_INTERIOR, ZorkGrandInquisitorRegions.WHITE_HOUSE, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Requirements AND + OR
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Sword", 1) and state.has("Hotspot: Dungeon Master\'s Lair Entrance", 1)) or (state.has("Map", 1) and state.has("Teleporter Destination: Dungeon Master\'s Lair", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.CROSSROADS, ZorkGrandInquisitorRegions.DM_LAIR, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiple Requirements Regions
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            'lambda state: (state.has("Griff\'s Air Pump", 1) and state.has("Griff\'s Inflatable Raft", 1) and state.has("Griff\'s Inflatable Sea Captain", 1) and state.has("Hotspot: Dragon Nostrils", 1) and state.has("Griff\'s Dragon Tooth", 1) and state.can_reach("Port Foozle Past - Tavern", "Region", 1) and state.has("Lucy\'s Playing Card: 1 Pip", 1) and state.has("Lucy\'s Playing Card: 2 Pips", 1) and state.has("Lucy\'s Playing Card: 3 Pips", 1) and state.has("Lucy\'s Playing Card: 4 Pips", 1) and state.has("Hotspot: Tavern Fly", 1) and state.has("Hotspot: Alpine\'s Quandry Card Slots", 1) and state.can_reach("White House", "Region", 1) and state.has("Totem: Brog", 1) and state.has("Brog\'s Flickering Torch", 1) and state.has("Brog\'s Grue Egg", 1) and state.has("Hotspot: Cooking Pot", 1) and state.has("Brog\'s Plank", 1) and state.has("Hotspot: Skull Cage", 1))',
 | 
				
			||||||
 | 
					            entrance_access_rule_for(
 | 
				
			||||||
 | 
					                ZorkGrandInquisitorRegions.DRAGON_ARCHIPELAGO_DRAGON, ZorkGrandInquisitorRegions.ENDGAME, 1
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					from typing import Dict, Set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import ZorkGrandInquisitorTestBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..data_funcs import location_names_to_location, locations_with_tag
 | 
				
			||||||
 | 
					from ..enums import ZorkGrandInquisitorLocations, ZorkGrandInquisitorTags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LocationsTestNoDeathsanity(ZorkGrandInquisitorTestBase):
 | 
				
			||||||
 | 
					    options = {
 | 
				
			||||||
 | 
					        "deathsanity": "false",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_correct_locations_exist(self) -> None:
 | 
				
			||||||
 | 
					        expected_locations: Set[ZorkGrandInquisitorLocations] = locations_with_tag(
 | 
				
			||||||
 | 
					            ZorkGrandInquisitorTags.CORE
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._assert_expected_locations_exist(expected_locations)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _assert_expected_locations_exist(self, expected_locations: Set[ZorkGrandInquisitorLocations]) -> None:
 | 
				
			||||||
 | 
					        location_name_to_location: Dict[str, ZorkGrandInquisitorLocations] = location_names_to_location()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for location_object in self.multiworld.get_locations(1):
 | 
				
			||||||
 | 
					            location: ZorkGrandInquisitorLocations = location_name_to_location.get(
 | 
				
			||||||
 | 
					                location_object.name
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if location is None:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.assertIn(location, expected_locations)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            expected_locations.remove(location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(0, len(expected_locations))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LocationsTestDeathsanity(LocationsTestNoDeathsanity):
 | 
				
			||||||
 | 
					    options = {
 | 
				
			||||||
 | 
					        "deathsanity": "true",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_correct_locations_exist(self) -> None:
 | 
				
			||||||
 | 
					        expected_locations: Set[ZorkGrandInquisitorLocations] = (
 | 
				
			||||||
 | 
					            locations_with_tag(ZorkGrandInquisitorTags.CORE) | locations_with_tag(ZorkGrandInquisitorTags.DEATHSANITY)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._assert_expected_locations_exist(expected_locations)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,206 @@
 | 
				
			||||||
 | 
					from typing import Any, Dict, List, Set, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from BaseClasses import Item, ItemClassification, Location, Region, Tutorial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from worlds.AutoWorld import WebWorld, World
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .data.item_data import item_data, ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					from .data.location_data import location_data, ZorkGrandInquisitorLocationData
 | 
				
			||||||
 | 
					from .data.region_data import region_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .data_funcs import (
 | 
				
			||||||
 | 
					    item_names_to_id,
 | 
				
			||||||
 | 
					    item_names_to_item,
 | 
				
			||||||
 | 
					    location_names_to_id,
 | 
				
			||||||
 | 
					    item_groups,
 | 
				
			||||||
 | 
					    items_with_tag,
 | 
				
			||||||
 | 
					    location_groups,
 | 
				
			||||||
 | 
					    locations_by_region,
 | 
				
			||||||
 | 
					    location_access_rule_for,
 | 
				
			||||||
 | 
					    entrance_access_rule_for,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .enums import (
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorEvents,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorItems,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorLocations,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorRegions,
 | 
				
			||||||
 | 
					    ZorkGrandInquisitorTags,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .options import ZorkGrandInquisitorOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorItem(Item):
 | 
				
			||||||
 | 
					    game = "Zork Grand Inquisitor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorLocation(Location):
 | 
				
			||||||
 | 
					    game = "Zork Grand Inquisitor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorWebWorld(WebWorld):
 | 
				
			||||||
 | 
					    theme: str = "stone"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tutorials: List[Tutorial] = [
 | 
				
			||||||
 | 
					        Tutorial(
 | 
				
			||||||
 | 
					            "Multiworld Setup Guide",
 | 
				
			||||||
 | 
					            "A guide to setting up the Zork Grand Inquisitor randomizer connected to an Archipelago Multiworld",
 | 
				
			||||||
 | 
					            "English",
 | 
				
			||||||
 | 
					            "setup_en.md",
 | 
				
			||||||
 | 
					            "setup/en",
 | 
				
			||||||
 | 
					            ["Serpent.AI"],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZorkGrandInquisitorWorld(World):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Zork: Grand Inquisitor is a 1997 point-and-click adventure game for PC.
 | 
				
			||||||
 | 
					    Magic has been banned from the great Underground Empire of Zork. By edict of the Grand Inquisitor Mir Yannick, the
 | 
				
			||||||
 | 
					    Empire has been sealed off and the practice of mystic arts declared punishable by "Totemization" (a very bad thing).
 | 
				
			||||||
 | 
					    The only way to restore magic to the kingdom is to find three hidden artifacts: The Coconut of Quendor, The Cube of
 | 
				
			||||||
 | 
					    Foundation, and The Skull of Yoruk.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options_dataclass = ZorkGrandInquisitorOptions
 | 
				
			||||||
 | 
					    options: ZorkGrandInquisitorOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    game = "Zork Grand Inquisitor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item_name_to_id = item_names_to_id()
 | 
				
			||||||
 | 
					    location_name_to_id = location_names_to_id()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item_name_groups = item_groups()
 | 
				
			||||||
 | 
					    location_name_groups = location_groups()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    required_client_version: Tuple[int, int, int] = (0, 4, 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    web = ZorkGrandInquisitorWebWorld()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item_name_to_item: Dict[str, ZorkGrandInquisitorItems] = item_names_to_item()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_regions(self) -> None:
 | 
				
			||||||
 | 
					        deathsanity: bool = bool(self.options.deathsanity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        region_mapping: Dict[ZorkGrandInquisitorRegions, Region] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        region_enum_item: ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					        for region_enum_item in region_data.keys():
 | 
				
			||||||
 | 
					            region_mapping[region_enum_item] = Region(region_enum_item.value, self.player, self.multiworld)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        region_locations_mapping: Dict[ZorkGrandInquisitorRegions, Set[ZorkGrandInquisitorLocations]]
 | 
				
			||||||
 | 
					        region_locations_mapping = locations_by_region(include_deathsanity=deathsanity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        region_enum_item: ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					        region: Region
 | 
				
			||||||
 | 
					        for region_enum_item, region in region_mapping.items():
 | 
				
			||||||
 | 
					            regions_locations: Set[ZorkGrandInquisitorLocations] = region_locations_mapping[region_enum_item]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Locations
 | 
				
			||||||
 | 
					            location_enum_item: ZorkGrandInquisitorLocations
 | 
				
			||||||
 | 
					            for location_enum_item in regions_locations:
 | 
				
			||||||
 | 
					                data: ZorkGrandInquisitorLocationData = location_data[location_enum_item]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                location: ZorkGrandInquisitorLocation = ZorkGrandInquisitorLocation(
 | 
				
			||||||
 | 
					                    self.player,
 | 
				
			||||||
 | 
					                    location_enum_item.value,
 | 
				
			||||||
 | 
					                    data.archipelago_id,
 | 
				
			||||||
 | 
					                    region_mapping[data.region],
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                location.event = isinstance(location_enum_item, ZorkGrandInquisitorEvents)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if location.event:
 | 
				
			||||||
 | 
					                    location.place_locked_item(
 | 
				
			||||||
 | 
					                        ZorkGrandInquisitorItem(
 | 
				
			||||||
 | 
					                            data.event_item_name,
 | 
				
			||||||
 | 
					                            ItemClassification.progression,
 | 
				
			||||||
 | 
					                            None,
 | 
				
			||||||
 | 
					                            self.player,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                location_access_rule: str = location_access_rule_for(location_enum_item, self.player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if location_access_rule != "lambda state: True":
 | 
				
			||||||
 | 
					                    location.access_rule = eval(location_access_rule)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                region.locations.append(location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Connections
 | 
				
			||||||
 | 
					            region_exit: ZorkGrandInquisitorRegions
 | 
				
			||||||
 | 
					            for region_exit in region_data[region_enum_item].exits or tuple():
 | 
				
			||||||
 | 
					                entrance_access_rule: str = entrance_access_rule_for(region_enum_item, region_exit, self.player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if entrance_access_rule == "lambda state: True":
 | 
				
			||||||
 | 
					                    region.connect(region_mapping[region_exit])
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    region.connect(region_mapping[region_exit], rule=eval(entrance_access_rule))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.multiworld.regions.append(region)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_items(self) -> None:
 | 
				
			||||||
 | 
					        quick_port_foozle: bool = bool(self.options.quick_port_foozle)
 | 
				
			||||||
 | 
					        start_with_hotspot_items: bool = bool(self.options.start_with_hotspot_items)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_pool: List[ZorkGrandInquisitorItem] = list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item: ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					        data: ZorkGrandInquisitorItemData
 | 
				
			||||||
 | 
					        for item, data in item_data.items():
 | 
				
			||||||
 | 
					            tags: Tuple[ZorkGrandInquisitorTags, ...] = data.tags or tuple()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ZorkGrandInquisitorTags.FILLER in tags:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            elif ZorkGrandInquisitorTags.HOTSPOT in tags and start_with_hotspot_items:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_pool.append(self.create_item(item.value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        total_locations: int = len(self.multiworld.get_unfilled_locations(self.player))
 | 
				
			||||||
 | 
					        item_pool += [self.create_filler() for _ in range(total_locations - len(item_pool))]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.multiworld.itempool += item_pool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if quick_port_foozle:
 | 
				
			||||||
 | 
					            self.multiworld.early_items[self.player][ZorkGrandInquisitorItems.ROPE.value] = 1
 | 
				
			||||||
 | 
					            self.multiworld.early_items[self.player][ZorkGrandInquisitorItems.LANTERN.value] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if not start_with_hotspot_items:
 | 
				
			||||||
 | 
					                self.multiworld.early_items[self.player][ZorkGrandInquisitorItems.HOTSPOT_WELL.value] = 1
 | 
				
			||||||
 | 
					                self.multiworld.early_items[self.player][ZorkGrandInquisitorItems.HOTSPOT_JACKS_DOOR.value] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.multiworld.early_items[self.player][
 | 
				
			||||||
 | 
					                    ZorkGrandInquisitorItems.HOTSPOT_GRAND_INQUISITOR_DOLL.value
 | 
				
			||||||
 | 
					                ] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if start_with_hotspot_items:
 | 
				
			||||||
 | 
					            item: ZorkGrandInquisitorItems
 | 
				
			||||||
 | 
					            for item in items_with_tag(ZorkGrandInquisitorTags.HOTSPOT):
 | 
				
			||||||
 | 
					                self.multiworld.push_precollected(self.create_item(item.value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_item(self, name: str) -> ZorkGrandInquisitorItem:
 | 
				
			||||||
 | 
					        data: ZorkGrandInquisitorItemData = item_data[self.item_name_to_item[name]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ZorkGrandInquisitorItem(
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            data.classification,
 | 
				
			||||||
 | 
					            data.archipelago_id,
 | 
				
			||||||
 | 
					            self.player,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_basic(self) -> None:
 | 
				
			||||||
 | 
					        self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fill_slot_data(self) -> Dict[str, Any]:
 | 
				
			||||||
 | 
					        return self.options.as_dict(
 | 
				
			||||||
 | 
					            "goal",
 | 
				
			||||||
 | 
					            "quick_port_foozle",
 | 
				
			||||||
 | 
					            "start_with_hotspot_items",
 | 
				
			||||||
 | 
					            "deathsanity",
 | 
				
			||||||
 | 
					            "grant_missable_location_checks",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_filler_item_name(self) -> str:
 | 
				
			||||||
 | 
					        return self.random.choice(list(self.item_name_groups["Filler"]))
 | 
				
			||||||
		Loading…
	
		Reference in New Issue