add function triggers to logic system
This commit is contained in:
parent
dc00a78b57
commit
4affcb893a
|
@ -1,4 +1,4 @@
|
||||||
adventure/custom_actions.py
|
adventure/custom_*.py
|
||||||
worlds/
|
worlds/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.env
|
.env
|
||||||
|
|
|
@ -9,6 +9,13 @@ from adventure.models import Actor, Item, Room, World
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
OPPOSITE_DIRECTIONS = {
|
||||||
|
"north": "south",
|
||||||
|
"south": "north",
|
||||||
|
"east": "west",
|
||||||
|
"west": "east",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_room(
|
def generate_room(
|
||||||
agent: Agent, world_theme: str, existing_rooms: List[str], callback
|
agent: Agent, world_theme: str, existing_rooms: List[str], callback
|
||||||
|
@ -147,13 +154,14 @@ def generate_world(
|
||||||
|
|
||||||
existing_actors: List[str] = []
|
existing_actors: List[str] = []
|
||||||
existing_items: List[str] = []
|
existing_items: List[str] = []
|
||||||
|
existing_rooms: List[str] = []
|
||||||
|
|
||||||
# generate the rooms
|
# generate the rooms
|
||||||
rooms = []
|
rooms = []
|
||||||
for i in range(room_count):
|
for i in range(room_count):
|
||||||
existing_rooms = [room.name for room in rooms]
|
|
||||||
room = generate_room(agent, theme, existing_rooms, callback=callback)
|
room = generate_room(agent, theme, existing_rooms, callback=callback)
|
||||||
rooms.append(room)
|
rooms.append(room)
|
||||||
|
existing_rooms.append(room.name)
|
||||||
|
|
||||||
item_count = randint(0, 3)
|
item_count = randint(0, 3)
|
||||||
callback(f"Generating {item_count} items for room: {room.name}")
|
callback(f"Generating {item_count} items for room: {room.name}")
|
||||||
|
@ -198,13 +206,6 @@ def generate_world(
|
||||||
actor.items.append(item)
|
actor.items.append(item)
|
||||||
existing_items.append(item.name)
|
existing_items.append(item.name)
|
||||||
|
|
||||||
opposite_directions = {
|
|
||||||
"north": "south",
|
|
||||||
"south": "north",
|
|
||||||
"east": "west",
|
|
||||||
"west": "east",
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate portals to link the rooms together
|
# generate portals to link the rooms together
|
||||||
for room in rooms:
|
for room in rooms:
|
||||||
directions = ["north", "south", "east", "west"]
|
directions = ["north", "south", "east", "west"]
|
||||||
|
@ -213,7 +214,7 @@ def generate_world(
|
||||||
logger.debug(f"Room {room.name} already has a {direction} portal")
|
logger.debug(f"Room {room.name} already has a {direction} portal")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
opposite_direction = opposite_directions[direction]
|
opposite_direction = OPPOSITE_DIRECTIONS[direction]
|
||||||
|
|
||||||
if randint(0, 1):
|
if randint(0, 1):
|
||||||
dest_room = choice([r for r in rooms if r.name != room.name])
|
dest_room = choice([r for r in rooms if r.name != room.name])
|
||||||
|
@ -233,7 +234,7 @@ def generate_world(
|
||||||
|
|
||||||
# create bidirectional links
|
# create bidirectional links
|
||||||
room.portals[direction] = dest_room.name
|
room.portals[direction] = dest_room.name
|
||||||
dest_room.portals[opposite_directions[direction]] = room.name
|
dest_room.portals[OPPOSITE_DIRECTIONS[direction]] = room.name
|
||||||
|
|
||||||
# ensure actors act in a stable order
|
# ensure actors act in a stable order
|
||||||
order = [actor.name for room in rooms for actor in room.actors]
|
order = [actor.name for room in rooms for actor in room.actors]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from importlib import import_module
|
|
||||||
from json import load
|
from json import load
|
||||||
from logging.config import dictConfig
|
from logging.config import dictConfig
|
||||||
from os import environ, path
|
from os import environ, path
|
||||||
|
@ -12,6 +11,7 @@ from packit.toolbox import Toolbox
|
||||||
from packit.utils import logger_with_colors
|
from packit.utils import logger_with_colors
|
||||||
|
|
||||||
from adventure.context import set_current_broadcast
|
from adventure.context import set_current_broadcast
|
||||||
|
from adventure.plugins import load_plugin
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
LOG_PATH = "logging.json"
|
LOG_PATH = "logging.json"
|
||||||
|
@ -209,6 +209,9 @@ def parse_args():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--max-rooms", type=int, help="The maximum number of rooms to generate"
|
"--max-rooms", type=int, help="The maximum number of rooms to generate"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--optional-actions", type=bool, help="Whether to include optional actions"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--server", type=str, help="The address on which to run the server"
|
"--server", type=str, help="The address on which to run the server"
|
||||||
)
|
)
|
||||||
|
@ -326,6 +329,16 @@ def main():
|
||||||
)
|
)
|
||||||
extra_actions.extend(module_actions)
|
extra_actions.extend(module_actions)
|
||||||
|
|
||||||
|
if args.optional_actions:
|
||||||
|
logger.info("Loading optional actions")
|
||||||
|
from adventure.optional_actions import init as init_optional_actions
|
||||||
|
|
||||||
|
optional_actions = init_optional_actions()
|
||||||
|
logger.info(
|
||||||
|
f"Loaded optional actions: {[action.__name__ for action in optional_actions]}"
|
||||||
|
)
|
||||||
|
extra_actions.extend(optional_actions)
|
||||||
|
|
||||||
# load extra systems
|
# load extra systems
|
||||||
def snapshot_system(world: World, step: int) -> None:
|
def snapshot_system(world: World, step: int) -> None:
|
||||||
logger.debug("Snapshotting world state")
|
logger.debug("Snapshotting world state")
|
||||||
|
@ -356,12 +369,5 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_plugin(name):
|
|
||||||
module_name, function_name = name.rsplit(":", 1)
|
|
||||||
plugin_module = import_module(module_name)
|
|
||||||
plugin_entry = getattr(plugin_module, function_name)
|
|
||||||
return plugin_entry()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
|
||||||
|
def load_plugin(name: str, override_function: str | None = None):
|
||||||
|
plugin_entry = get_plugin_function(name, override_function)
|
||||||
|
return plugin_entry()
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_function(name: str, override_function: str | None = None):
|
||||||
|
module_name, function_name = name.rsplit(":", 1)
|
||||||
|
plugin_module = import_module(module_name)
|
||||||
|
return getattr(plugin_module, override_function or function_name)
|
|
@ -5,7 +5,8 @@ from typing import Dict, List, Optional
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from yaml import Loader, load
|
from yaml import Loader, load
|
||||||
|
|
||||||
from adventure.models import World, dataclass
|
from adventure.models import Actor, Item, Room, World, dataclass
|
||||||
|
from adventure.plugins import get_plugin_function
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ class LogicRule:
|
||||||
chance: float = 1.0
|
chance: float = 1.0
|
||||||
remove: Optional[List[str]] = None
|
remove: Optional[List[str]] = None
|
||||||
set: Optional[Dict[str, str]] = None
|
set: Optional[Dict[str, str]] = None
|
||||||
|
trigger: Optional[List[str]] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -32,10 +34,17 @@ class LogicTable:
|
||||||
|
|
||||||
with open("./worlds/logic.yaml") as file:
|
with open("./worlds/logic.yaml") as file:
|
||||||
logic_rules = LogicTable(**load(file, Loader=Loader))
|
logic_rules = LogicTable(**load(file, Loader=Loader))
|
||||||
|
logic_triggers = {
|
||||||
|
rule: [get_plugin_function(trigger) for trigger in rule.trigger]
|
||||||
|
for rule in logic_rules.rules
|
||||||
|
if rule.trigger
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def update_attributes(
|
def update_attributes(
|
||||||
attributes: Dict[str, str], dataset: LogicTable
|
entity: Room | Actor | Item,
|
||||||
|
attributes: Dict[str, str],
|
||||||
|
dataset: LogicTable,
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
for rule in dataset.rules:
|
for rule in dataset.rules:
|
||||||
if rule.match.items() <= attributes.items():
|
if rule.match.items() <= attributes.items():
|
||||||
|
@ -52,18 +61,22 @@ def update_attributes(
|
||||||
for key in rule.remove or []:
|
for key in rule.remove or []:
|
||||||
attributes.pop(key, None)
|
attributes.pop(key, None)
|
||||||
|
|
||||||
|
if rule in logic_triggers:
|
||||||
|
for trigger in logic_triggers[rule]:
|
||||||
|
attributes = trigger(entity, attributes)
|
||||||
|
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
def update_logic(world: World, step: int) -> None:
|
def update_logic(world: World, step: int) -> None:
|
||||||
for room in world.rooms:
|
for room in world.rooms:
|
||||||
room.attributes = update_attributes(room.attributes, logic_rules)
|
room.attributes = update_attributes(room, room.attributes, logic_rules)
|
||||||
for actor in room.actors:
|
for actor in room.actors:
|
||||||
actor.attributes = update_attributes(actor.attributes, logic_rules)
|
actor.attributes = update_attributes(actor, actor.attributes, logic_rules)
|
||||||
for item in actor.items:
|
for item in actor.items:
|
||||||
item.attributes = update_attributes(item.attributes, logic_rules)
|
item.attributes = update_attributes(item, item.attributes, logic_rules)
|
||||||
for item in room.items:
|
for item in room.items:
|
||||||
item.attributes = update_attributes(item.attributes, logic_rules)
|
item.attributes = update_attributes(item, item.attributes, logic_rules)
|
||||||
|
|
||||||
logger.info("updated world attributes")
|
logger.info("updated world attributes")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue