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