annotate skaapsteker/dialogue.py @ 216:023eea4ad4a5

Add support for trigger world changes when entering and exiting dialog states.
author Simon Cross <hodgestar@gmail.com>
date Thu, 07 Apr 2011 00:47:02 +0200
parents a4c4e2f34162
children fcc5eca8eaca
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
1 import json
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
2
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
3 from . import data
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
4
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
5
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
6 class DSM(object):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
7 """Dialogue State Machine!
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
8
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
9 Parameters
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
10 ----------
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
11 json_filename : str
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
12 Path to file under data/ that contains JSON description
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
13 of state machine.
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
14 world : object
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
15 Something to allow states to introspect the game state with.
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
16 """
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
17
193
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
18 def __init__(self, name, world, json_filename):
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
19 me = getattr(world.npcs, name)
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
20 self.state = getattr(me, 'state', 'start')
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
21 me.state = self.state
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
22 self.world = world
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
23 self.states = AttrDict()
190
e4b466368b89 Fix dialogue.
Simon Cross <hodgestar@gmail.com>
parents: 185
diff changeset
24 src = json.loads(data.load(json_filename).read())
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
25 for state, state_src in src.iteritems():
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
26 pseudo_path = [json_filename, state]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
27 self.states[state] = DsmState(state, state_src, pseudo_path)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
28 assert self.state in self.states, "DSM must have start state"
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
29
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
30 def get_state(self):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
31 return self.states[self.state]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
32
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
33 def event(self, ev):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
34 my_locals = {
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
35 "state": self.states,
193
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
36 "world": self.world,
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 190
diff changeset
37 "npcs": self.world.npcs,
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
38 }
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
39 my_locals.update(ev.items)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
40 state = self.states[self.state]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
41 next_state = state.event(my_locals)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
42 if next_state.name in self.states:
216
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
43 self.states[self.state].leave(my_locals)
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
44 self.state = next_state.name
216
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
45 self.states[self.state].enter(my_locals)
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
46
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
47 def choice(self, i):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
48 self.event(DsmEvent(choice=i))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
49
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
50
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
51 class AttrDict(dict):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
52
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
53 def __getattr__(self, name):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
54 if name not in self:
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
55 raise AttributeError("No attribute %r" % (name,))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
56 return self[name]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
57
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
58
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
59 class DsmEvent(object):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
60
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
61 def __init__(self, choice=None):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
62 self.items = {
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
63 "choice": choice,
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
64 }
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
65
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
66
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
67 class DsmState(object):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
68 """State within a DSM.
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
69 """
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
70
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
71 def __init__(self, name, state_src, base_path):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
72 self.name = name
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
73 self.text = state_src.get("text", None)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
74 self.choices = []
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
75 self.triggers = []
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
76
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
77 choices = state_src.get("choices", [])
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
78 for i, choice in enumerate(choices):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
79 pseudo_path = base_path + ["choice-%d" % i]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
80 self.choices.append((i, choice["text"]))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
81 next_state_code = choice.get("next", None)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
82 if next_state_code is not None:
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
83 self.triggers.append(
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
84 Trigger("choice == %d" % i, next_state_code, pseudo_path))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
85
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
86 events = state_src.get("events", [])
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
87 for i, event in enumerate(events):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
88 pseudo_path = base_path + ["event-%d" % i]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
89 self.triggers.append(Trigger(event["matches"], event["next"],
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
90 pseudo_path))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
91
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
92 auto_next = state_src.get("auto_next", None)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
93 if auto_next is not None:
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
94 pseudo_path = base_path + ["auto_next"]
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
95 self.triggers.append(Trigger("""True""", auto_next, pseudo_path))
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
96
216
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
97 on_entry = state_src.get("on_entry", None)
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
98 if on_entry is not None:
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
99 self.on_entry = compile(on_entry,
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
100 "<%s>" % ":".join(base_path + ["on_entry"]),
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
101 "exec")
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
102
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
103 on_exit = state_src.get("on_exit", None)
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
104 if on_exit is not None:
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
105 self.on_exit = compile(on_exit,
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
106 "<%s>" % ":".join(base_path + ["on_exit"]),
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
107 "exec")
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
108
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
109 def __repr__(self):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
110 return "<%r name=%r>" % (self.__class__.__name__, self.name)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
111
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
112 def event(self, my_locals):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
113 for trigger in self.triggers:
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
114 next_state = trigger.fire(my_locals)
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
115 if next_state is not None:
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
116 return next_state
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
117
216
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
118 def enter(self, my_locals):
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
119 self.on_entry(my_locals, {}, my_locals.copy())
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
120
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
121 def leave(self, my_locals):
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
122 self.on_exit(my_locals, {}, my_locals.copy())
023eea4ad4a5 Add support for trigger world changes when entering and exiting dialog states.
Simon Cross <hodgestar@gmail.com>
parents: 196
diff changeset
123
153
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
124
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
125 class Trigger(object):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
126 """Matches DSM events and triggers state transitions.
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
127 """
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
128
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
129 def __init__(self, matches_code, next_state_code, pseudo_path):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
130 self._matches = compile(matches_code,
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
131 "<%s>" % ":".join(pseudo_path + ["match"]),
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
132 "eval")
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
133 self._next_state = compile(next_state_code,
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
134 "<%s>" % ":".join(pseudo_path + ["next"]),
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
135 "eval")
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
136
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
137 def fire(self, my_locals):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
138 if eval(self._matches, {}, my_locals.copy()):
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
139 return eval(self._next_state, {}, my_locals.copy())
704d23022f09 Start of dialogue tree / NPC state machine support.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
140 return None