Skip to content

Commit

Permalink
first apworld?
Browse files Browse the repository at this point in the history
  • Loading branch information
nbrochu committed Nov 21, 2023
1 parent 9bdfd82 commit e2e38e0
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 152 deletions.
21 changes: 21 additions & 0 deletions worlds/zork_grand_inquisitor/LICENSE
Original file line number Diff line number Diff line change
@@ -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.
93 changes: 57 additions & 36 deletions worlds/zork_grand_inquisitor/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def _cmd_zork(self):
result = 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.")
Expand All @@ -36,6 +37,11 @@ def __init__(self, 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):
from kvui import GameManager

Expand All @@ -62,55 +68,70 @@ def on_package(self, cmd, _args):

CommonClient.async_start(process_package(self, cmd, _args))

async def controller(self):
while not self.exit_event.is_set():
await asyncio.sleep(0.1)

async def controller(ctx):
while not ctx.exit_event.is_set():
# Update Completed Locations
completed_locations = set()
# Update Completed Locations
completed_locations = set()

for location_id in ctx.checked_locations:
location = ctx.id_to_locations[location_id]
completed_locations.add(location)
for location_id in self.checked_locations:
location = self.id_to_locations[location_id]
completed_locations.add(location)

ctx.game_controller.completed_locations = completed_locations
self.game_controller.completed_locations = completed_locations

# Enqueue Received Item Delta
for network_item in ctx.items_received:
item = ctx.id_to_items[network_item.item]
# Enqueue Received Item Delta
for network_item in self.items_received:
item = self.id_to_items[network_item.item]

if item not in ctx.game_controller.received_items:
if item not in ctx.game_controller.received_items_queue:
ctx.game_controller.received_items_queue.append(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
ctx.game_controller.update()
# Game Controller Update
if self.game_controller.is_process_running():
self.game_controller.update()
self.can_display_process_message = True
else:
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."
)

# Send Checked Locations
checked_location_ids = list()
if self.can_display_process_message:
CommonClient.logger.info(process_message)
self.can_display_process_message = False

while len(ctx.game_controller.completed_locations_queue) > 0:
location = ctx.game_controller.completed_locations_queue.popleft()
location_id = ctx.location_name_to_id[location.value]
# Send Checked Locations
checked_location_ids = list()

checked_location_ids.append(location_id)
while len(self.game_controller.completed_locations_queue) > 0:
location = self.game_controller.completed_locations_queue.popleft()
location_id = self.location_name_to_id[location.value]

await ctx.send_msgs([
{
"cmd": "LocationChecks",
"locations": checked_location_ids
}
])
checked_location_ids.append(location_id)

# Check for Goal Completion
if ctx.game_controller.goal_completed:
await ctx.send_msgs([
await self.send_msgs([
{
"cmd": "StatusUpdate",
"status": CommonClient.ClientStatus.CLIENT_GOAL
"cmd": "LocationChecks",
"locations": checked_location_ids
}
])

await asyncio.sleep(0.2)
# Check for Goal Completion
if self.game_controller.goal_completed:
await self.send_msgs([
{
"cmd": "StatusUpdate",
"status": CommonClient.ClientStatus.CLIENT_GOAL
}
])


async def process_package(ctx: ZorkGrandInquisitorContext, cmd, _args):
Expand All @@ -125,9 +146,9 @@ def main():

async def _main():
ctx = ZorkGrandInquisitorContext(None, None)
ctx.server_task = asyncio.create_task(CommonClient.server_loop(ctx), name="server loop")

asyncio.create_task(controller(ctx), name="ZorkGrandInquisitorController")
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()
Expand Down
82 changes: 49 additions & 33 deletions worlds/zork_grand_inquisitor/game_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@
from .game_state_manager import GameStateManager


### PROBLEMS / TODO
# Need Repro: Dying in Old Scratch caused Plants are mans best friend to be completed and game crash
# Maybe only when done on the surface without dalboz? Not reproduced in DML

# 2 Ropes sometimes... after messing with sword + rope? Minor?

# Subway token conditionals are not working properly
# Still a problem with hungus lard and plug in out states. It disappears after plugging it and taking it ouj
# Possible to do messy stuff with sword / map that are supposed to disappear after glass breaks. Clicking fast on them
# Map needs duplication prevention

# Detect when the game is not running and prompt to /zork again

class GameController:
def __init__(self, logger=None):
self.logger = logger
Expand Down Expand Up @@ -59,25 +46,35 @@ def log(self, message):
if self.logger:
self.logger.info(message)

def log_debug(self, message):
if self.logger:
self.logger.debug(message)

def open_process_handle(self):
return self.game_state_manager.open_process_handle()

def close_process_handle(self):
return self.game_state_manager.close_process_handle()

def is_process_running(self):
return self.game_state_manager.is_process_running

def update(self):
if self.game_state_manager.is_process_running:
self.game_state_manager.refresh_game_location()
if self.game_state_manager.is_process_still_running():
try:
self.game_state_manager.refresh_game_location()

self._apply_permanent_game_state()
self._apply_conditional_game_state()
self._apply_permanent_game_state()
self._apply_conditional_game_state()

self._check_for_completed_locations()
self._manage_items()
self._check_for_completed_locations()
self._manage_items()

self._apply_conditional_teleports()
self._apply_conditional_teleports()

self._check_for_victory()
self._check_for_victory()
except Exception as e:
self.log_debug(e)

def _apply_permanent_game_state(self):
self._write_game_state_value_for(10934, 1) # Rope Taken
Expand Down Expand Up @@ -277,14 +274,25 @@ def _manage_items(self):

game_state_inventory_items = self._determine_game_state_inventory()

inventory_items_to_add = received_inventory_items - game_state_inventory_items
inventory_items_to_remove = game_state_inventory_items - received_inventory_items
inventory_items_to_add = received_inventory_items - game_state_inventory_items

for item in inventory_items_to_remove:
self._remove_from_inventory(item)

for item in inventory_items_to_add:
self._add_to_inventory(item)

for item in inventory_items_to_remove:
self._remove_from_inventory(item)
# Item Deduplication (Just in Case)
seen_items = set()

for i in range(151, 171):
item = self._read_game_state_value_for(i)

if item in seen_items:
self._write_game_state_value_for(i, 0)
else:
seen_items.add(item)

def _apply_conditional_teleports(self):
if self._player_is_at("uw1k") and self._read_game_state_value_for(13938) == 0:
Expand Down Expand Up @@ -355,8 +363,9 @@ def _add_to_inventory(self, item):
data = item_data[item]

if ZorkGrandInquisitorTags.INVENTORY_ITEM in data.tags:
inventory_slot = self.available_inventory_slots.pop()
self._write_game_state_value_for(inventory_slot, data.game_state_keys[0])
if len(self.available_inventory_slots): # Inventory slot overflow protection
inventory_slot = self.available_inventory_slots.pop()
self._write_game_state_value_for(inventory_slot, data.game_state_keys[0])
elif ZorkGrandInquisitorTags.SPELL in data.tags:
self._write_game_state_value_for(data.game_state_keys[0], 1)
elif ZorkGrandInquisitorTags.TOTEM in data.tags:
Expand Down Expand Up @@ -429,7 +438,7 @@ def _filter_received_inventory_items(self, received_inventory_items):
elif item == ZorkGrandInquisitorItems.HUNGUS_LARD:
if self._read_game_state_value_for(4870) == 1:
to_filter_inventory_items.add(item)
elif self._read_game_state_value_for(4309) == 1:
elif self._read_game_state_value_for(4244) == 1 and self._read_game_state_value_for(4309) == 0:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.JAR_OF_HOTBUGS:
if self._read_game_state_value_for(4750) == 1:
Expand All @@ -442,8 +451,13 @@ def _filter_received_inventory_items(self, received_inventory_items):
elif item == ZorkGrandInquisitorItems.LARGE_TELEGRAPH_HAMMER:
if self._read_game_state_value_for(9491) == 3:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.MAP:
if self._read_game_state_value_for(16618) == 1:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.MEAD_LIGHT:
if self._read_game_state_value_for(17620) > 0:
if 105 in inventory_item_values:
to_filter_inventory_items.add(item)
elif self._read_game_state_value_for(17620) > 0:
to_filter_inventory_items.add(item)
elif self._read_game_state_value_for(4034) == 1:
to_filter_inventory_items.add(item)
Expand Down Expand Up @@ -491,7 +505,7 @@ def _filter_received_inventory_items(self, received_inventory_items):
if self._read_game_state_value_for(11838) == 1:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.SUBWAY_TOKEN:
if self._read_game_state_value_for(13163) == 2:
if self._read_game_state_value_for(13167) == 1:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.SWORD:
if 22 in inventory_item_values:
Expand All @@ -501,7 +515,9 @@ def _filter_received_inventory_items(self, received_inventory_items):
elif 111 in inventory_item_values:
to_filter_inventory_items.add(item)
elif item == ZorkGrandInquisitorItems.ZIMDOR_SCROLL:
if self._read_game_state_value_for(17620) == 3:
if 105 in inventory_item_values:
to_filter_inventory_items.add(item)
elif self._read_game_state_value_for(17620) == 3:
to_filter_inventory_items.add(item)
elif self._read_game_state_value_for(4034) == 1:
to_filter_inventory_items.add(item)
Expand All @@ -521,17 +537,17 @@ def _filter_received_inventory_items(self, received_inventory_items):

def _read_game_state_value_for(self, key):
try:
return self.game_state_manager.read_game_state_value_for(key)[0]
return self.game_state_manager.read_game_state_value_for(key)
except Exception as e:
self.log(f"Exception: {e} while trying to read {key}")
self.log_debug(f"Exception: {e} while trying to read {key}")

return False

def _write_game_state_value_for(self, key, value):
try:
return self.game_state_manager.write_game_state_value_for(key, value)
except Exception as e:
self.log(f"Exception: {e} while trying to write {key} = {value}")
self.log_debug(f"Exception: {e} while trying to write {key} = {value}")

return False

Expand Down
Loading

0 comments on commit e2e38e0

Please sign in to comment.