From dd999a89ebe98f2e93a360a327125cee197a48be Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Mon, 27 May 2024 08:47:58 -0500 Subject: [PATCH] add weather and time-of-day system --- README.md | 2 +- taleweave/systems/quest.py | 92 ++++++++++--------- taleweave/systems/rpg/__init__.py | 8 +- taleweave/systems/sim/__init__.py | 10 +- taleweave/systems/weather/__init__.py | 49 ++++++++++ .../{rpg => weather}/weather_logic.yaml | 35 ++++--- 6 files changed, 128 insertions(+), 68 deletions(-) create mode 100644 taleweave/systems/weather/__init__.py rename taleweave/systems/{rpg => weather}/weather_logic.yaml (50%) diff --git a/README.md b/README.md index e2a07ec..88cf7e7 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ python3 -m adventure.main \ --discord=true \ --server=true \ --rooms 3 \ - --steps 30 \ + --turns 30 \ --optional-actions=true \ --actions adventure.sim_systems:init_actions \ --systems adventure.sim_systems:init_logic diff --git a/taleweave/systems/quest.py b/taleweave/systems/quest.py index 0f1e126..58475b7 100644 --- a/taleweave/systems/quest.py +++ b/taleweave/systems/quest.py @@ -29,6 +29,7 @@ logger = getLogger(__name__) QUEST_SYSTEM = "quest" +# region models @dataclass class QuestGoalContains: """ @@ -82,7 +83,47 @@ class QuestData: completed: Dict[str, List[Quest]] -# region quest completion +# endregion + + +# region state helpers +def complete_quest(quests: QuestData, character: Character, quest: Quest) -> None: + """ + Complete the given quest for the given character. + """ + if quest in quests.available.get(character.name, []): + quests.available[character.name].remove(quest) + + if quest == quests.active.get(character.name, None): + del quests.active[character.name] + + if character.name not in quests.completed: + quests.completed[character.name] = [] + + quests.completed[character.name].append(quest) + + +def get_quests_for_character(quests: QuestData, character: Character) -> List[Quest]: + """ + Get all quests for the given character. + """ + return quests.available.get(character.name, []) + + +def set_active_quest(quests: QuestData, character: Character, quest: Quest) -> None: + """ + Set the active quest for the given character. + """ + quests.active[character.name] = quest + + +def get_active_quest(quests: QuestData, character: Character) -> Quest | None: + """ + Get the active quest for the given character. + """ + return quests.active.get(character.name) + + def is_quest_complete(world: World, quest: Quest) -> bool: """ Check if the given quest is complete. @@ -121,47 +162,7 @@ def is_quest_complete(world: World, quest: Quest) -> bool: # endregion -# region state management -def get_quests_for_character(quests: QuestData, character: Character) -> List[Quest]: - """ - Get all quests for the given character. - """ - return quests.available.get(character.name, []) - - -def set_active_quest(quests: QuestData, character: Character, quest: Quest) -> None: - """ - Set the active quest for the given character. - """ - quests.active[character.name] = quest - - -def get_active_quest(quests: QuestData, character: Character) -> Quest | None: - """ - Get the active quest for the given character. - """ - return quests.active.get(character.name) - - -def complete_quest(quests: QuestData, character: Character, quest: Quest) -> None: - """ - Complete the given quest for the given character. - """ - if quest in quests.available.get(character.name, []): - quests.available[character.name].remove(quest) - - if quest == quests.active.get(character.name, None): - del quests.active[character.name] - - if character.name not in quests.completed: - quests.completed[character.name] = [] - - quests.completed[character.name].append(quest) - - -# endregion - - +# region game system callbacks def initialize_quests(world: World) -> QuestData: """ Initialize quests for the world. @@ -214,6 +215,10 @@ def simulate_quests(world: World, turn: int, data: QuestData | None = None) -> N complete_quest(quests, character, active_quest) +# endregion + + +# region I/O def load_quest_data(file: str) -> QuestData: logger.info(f"loading quest data from {file}") return load_system_data(QuestData, file) @@ -224,6 +229,9 @@ def save_quest_data(file: str, data: QuestData) -> None: return save_system_data(QuestData, file, data) +# endregion + + def init() -> List[GameSystem]: return [ GameSystem( diff --git a/taleweave/systems/rpg/__init__.py b/taleweave/systems/rpg/__init__.py index a742737..8d89e4a 100644 --- a/taleweave/systems/rpg/__init__.py +++ b/taleweave/systems/rpg/__init__.py @@ -3,12 +3,6 @@ from .language_actions import action_read from .magic_actions import action_cast from .movement_actions import action_climb -from taleweave.systems.logic import load_logic - -LOGIC_FILES = [ - "./adventure/systems/rpg/weather_logic.yaml", -] - def init_actions(): return [ @@ -24,4 +18,4 @@ def init_actions(): def init_logic(): - return [load_logic(filename) for filename in LOGIC_FILES] + return [] diff --git a/taleweave/systems/sim/__init__.py b/taleweave/systems/sim/__init__.py index fbb2a5d..fc144df 100644 --- a/taleweave/systems/sim/__init__.py +++ b/taleweave/systems/sim/__init__.py @@ -5,11 +5,11 @@ from .sleeping_actions import action_sleep from taleweave.systems.logic import load_logic LOGIC_FILES = [ - "./adventure/systems/sim/environment_logic.yaml", - "./adventure/systems/sim/hunger_logic.yaml", - "./adventure/systems/sim/hygiene_logic.yaml", - "./adventure/systems/sim/mood_logic.yaml", - "./adventure/systems/sim/sleeping_logic.yaml", + "./taleweave/systems/sim/environment_logic.yaml", + "./taleweave/systems/sim/hunger_logic.yaml", + "./taleweave/systems/sim/hygiene_logic.yaml", + "./taleweave/systems/sim/mood_logic.yaml", + "./taleweave/systems/sim/sleeping_logic.yaml", ] diff --git a/taleweave/systems/weather/__init__.py b/taleweave/systems/weather/__init__.py new file mode 100644 index 0000000..4b8f9ae --- /dev/null +++ b/taleweave/systems/weather/__init__.py @@ -0,0 +1,49 @@ +from typing import List +from taleweave.models.base import dataclass +from taleweave.models.entity import World +from taleweave.systems.logic import load_logic +from taleweave.game_system import GameSystem + +LOGIC_FILES = [ + "./taleweave/systems/weather/weather_logic.yaml", +] + + +@dataclass +class TimeOfDay: + name: str + start: int + end: int + + +TURNS_PER_DAY = 24 + +TIMES_OF_DAY: List[TimeOfDay] = [ + TimeOfDay("night", 0, 4), + TimeOfDay("morning", 5, 7), + TimeOfDay("day", 8, 18), + TimeOfDay("evening", 20, 22), + TimeOfDay("night", 23, 24), +] + + +def get_time_of_day(turn: int) -> TimeOfDay: + hour = turn % TURNS_PER_DAY + for time in TIMES_OF_DAY: + if time.start <= hour <= time.end: + return time + return TIMES_OF_DAY[0] + + +def simulate_weather(world: World, turn: int, data: None = None): + time_of_day = get_time_of_day(turn) + for room in world.rooms: + room.attributes["time"] = time_of_day.name + + +def init_systems(): + return [GameSystem("weather", simulate=simulate_weather)] + + +def init_logic(): + return [load_logic(filename) for filename in LOGIC_FILES] diff --git a/taleweave/systems/rpg/weather_logic.yaml b/taleweave/systems/weather/weather_logic.yaml similarity index 50% rename from taleweave/systems/rpg/weather_logic.yaml rename to taleweave/systems/weather/weather_logic.yaml index 21767c8..c5f972c 100644 --- a/taleweave/systems/rpg/weather_logic.yaml +++ b/taleweave/systems/weather/weather_logic.yaml @@ -4,51 +4,60 @@ rules: match: type: room outdoor: true - weather: sunny + weather: clear chance: 0.1 set: - weather: cloudy + weather: clouds - group: weather match: type: room outdoor: true - weather: cloudy + weather: clouds chance: 0.1 set: - weather: rainy + weather: rain - group: weather match: type: room outdoor: true - weather: rainy + weather: rain chance: 0.1 set: - weather: sunny + weather: clear - group: weather match: type: room outdoor: true - weather: cloudy + weather: clouds chance: 0.1 set: - weather: sunny + weather: clear labels: - match: type: room - weather: sunny + weather: clear + rule: | + "time" not in attributes or attributes&.time in ["morning", "day"] backstory: The sun is shining brightly. description: The sun is shining brightly. - match: type: room - weather: cloudy + weather: clear + rule: | + "time" in attributes and attributes&.time in ["evening", "night"] + backstory: The moon is shining brightly. + description: The moon is shining brightly. + - match: + type: room + weather: clouds backstory: The sky is overcast. description: The sky is overcast. - match: type: room - weather: rainy - backstory: Rain is falling from the sky. - description: Rain is falling from the sky. + weather: rain + backstory: Rain is falling from the cloudy sky. + description: Rain is falling from the cloudy sky.