| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
from movable import Movable |
|---|
| 21 |
|
|---|
| 22 |
class Thing(object): |
|---|
| 23 |
def __init__(self, world, name, place): |
|---|
| 24 |
self.world = world |
|---|
| 25 |
self.name = name |
|---|
| 26 |
self.place = place |
|---|
| 27 |
self.aliases = [name,] |
|---|
| 28 |
self.commands = list() |
|---|
| 29 |
self.on_enters = list() |
|---|
| 30 |
self.on_leaves = list() |
|---|
| 31 |
|
|---|
| 32 |
def add_aliases(self, aliases_obj, alias_str): |
|---|
| 33 |
""" Safely add aliases """ |
|---|
| 34 |
if not (isinstance(alias_str, str) or isinstance(alias_str, unicode)): |
|---|
| 35 |
return False |
|---|
| 36 |
if alias_str: |
|---|
| 37 |
aliases = alias_str.split(',') |
|---|
| 38 |
for alias in aliases: |
|---|
| 39 |
if alias: |
|---|
| 40 |
aliases_obj.append(alias.strip()) |
|---|
| 41 |
|
|---|
| 42 |
def parse_commands(self, command_elements): |
|---|
| 43 |
""" Parse commands and store them in self.commands """ |
|---|
| 44 |
for command in command_elements: |
|---|
| 45 |
if command.getAttribute('objects'): |
|---|
| 46 |
objects = command.getAttribute('objects').split(',') |
|---|
| 47 |
required_objects = tuple(objects) |
|---|
| 48 |
else: |
|---|
| 49 |
required_objects = tuple() |
|---|
| 50 |
command_obj = dict() |
|---|
| 51 |
command_obj['name'] = command.getAttribute('name').replace('%self%', '<<self>>') |
|---|
| 52 |
command_obj['name'] = command_obj['name'] % required_objects |
|---|
| 53 |
command_obj['aliases'] = list() |
|---|
| 54 |
command_obj['aliases'].append(command_obj['name']) |
|---|
| 55 |
command_obj['actions'] = list() |
|---|
| 56 |
command_obj['signal'] = command.getAttribute('signal').strip() |
|---|
| 57 |
command_obj['objects'] = list(required_objects) |
|---|
| 58 |
|
|---|
| 59 |
aliases = command.getAttribute('aliases') |
|---|
| 60 |
self.add_aliases(command_obj['aliases'], aliases) |
|---|
| 61 |
|
|---|
| 62 |
action_elements = command.getElementsByTagName('*') |
|---|
| 63 |
for i in action_elements: |
|---|
| 64 |
self.parse_action(command_obj['actions'], i) |
|---|
| 65 |
self.commands.append(command_obj) |
|---|
| 66 |
|
|---|
| 67 |
def parse_action(self, action_list, action_element): |
|---|
| 68 |
""" |
|---|
| 69 |
Parse action_element (xml.dom.minidom.Element) |
|---|
| 70 |
and append each action in action_list |
|---|
| 71 |
""" |
|---|
| 72 |
action_obj = dict() |
|---|
| 73 |
action_obj['name'] = action_element.localName |
|---|
| 74 |
|
|---|
| 75 |
action_obj['target'] = action_element.getAttribute('target') |
|---|
| 76 |
if action_element.hasAttribute('count'): |
|---|
| 77 |
action_obj['count'] = int(action_element.getAttribute('count')) |
|---|
| 78 |
|
|---|
| 79 |
if action_element.firstChild and action_element.firstChild.data: |
|---|
| 80 |
action_obj['params'] = action_element.firstChild.data.strip() |
|---|
| 81 |
action_list.append(action_obj) |
|---|
| 82 |
|
|---|
| 83 |
def do_action(self, action, player=None): |
|---|
| 84 |
""" Execute a stored action """ |
|---|
| 85 |
|
|---|
| 86 |
target = False |
|---|
| 87 |
if action['target'] == 'actor': |
|---|
| 88 |
target = player |
|---|
| 89 |
elif action['target'] == 'self': |
|---|
| 90 |
target = self |
|---|
| 91 |
elif action['target']: |
|---|
| 92 |
target = None |
|---|
| 93 |
for i in (self.place.visitors + self.place.npcs): |
|---|
| 94 |
if action['target'] == i.name: |
|---|
| 95 |
target = i |
|---|
| 96 |
break |
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
params = '' |
|---|
| 100 |
if action.has_key('params'): |
|---|
| 101 |
params = action['params'] |
|---|
| 102 |
params = params.replace('%self%', self.name) |
|---|
| 103 |
if player: |
|---|
| 104 |
params = params.replace('%actor%', player.name) |
|---|
| 105 |
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 |
if action['name'] == 'say': |
|---|
| 109 |
if target: |
|---|
| 110 |
self.say(params, target) |
|---|
| 111 |
else: |
|---|
| 112 |
self.say(params) |
|---|
| 113 |
|
|---|
| 114 |
|
|---|
| 115 |
elif action['name'] == 'narration': |
|---|
| 116 |
if target: |
|---|
| 117 |
target.send_message(None, params) |
|---|
| 118 |
else: |
|---|
| 119 |
self.place.broadcast_message(None, params) |
|---|
| 120 |
|
|---|
| 121 |
|
|---|
| 122 |
elif action['name'] == 'follow': |
|---|
| 123 |
if target.place is not None and not isinstance(target, NonPlayableCharacter): |
|---|
| 124 |
forbidden_places = params.split(',') |
|---|
| 125 |
for i in xrange(len(forbidden_places)): |
|---|
| 126 |
forbidden_places[i] = forbidden_places[i].strip() |
|---|
| 127 |
if not target.place.name in forbidden_places: |
|---|
| 128 |
self.say('/me follows ' + target.name) |
|---|
| 129 |
self.move_to(target.place) |
|---|
| 130 |
|
|---|
| 131 |
|
|---|
| 132 |
elif action['name'] == 'signal': |
|---|
| 133 |
if target is False: |
|---|
| 134 |
for i in (self.place.npcs + self.place.things): |
|---|
| 135 |
i.trigger_signal(params, player) |
|---|
| 136 |
elif target: |
|---|
| 137 |
target.trigger_signal(params, player) |
|---|
| 138 |
elif ':Failed' not in params: |
|---|
| 139 |
for i in (self.place.npcs + self.place.things): |
|---|
| 140 |
i.trigger_signal(params+':Failed', player) |
|---|
| 141 |
|
|---|
| 142 |
|
|---|
| 143 |
elif action['name'] == 'move': |
|---|
| 144 |
if not target: |
|---|
| 145 |
target = self |
|---|
| 146 |
if not params or params == target.place.name: |
|---|
| 147 |
for name, place in target.place.exits.items(): |
|---|
| 148 |
target.move_to(self.world.place(place)) |
|---|
| 149 |
break |
|---|
| 150 |
else: |
|---|
| 151 |
target.move_to(target.world.place(params)) |
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
elif action['name'] == 'add-exit': |
|---|
| 155 |
(spec, place) = params.split(':') |
|---|
| 156 |
spec = spec.strip() |
|---|
| 157 |
place = place.strip() |
|---|
| 158 |
self.place.exits[spec] = place |
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
elif action['name'] == 'del-exit': |
|---|
| 162 |
if self.place.exits.has_key(params): |
|---|
| 163 |
del self.place.exits[params] |
|---|
| 164 |
|
|---|
| 165 |
elif action['name'] == 'give': |
|---|
| 166 |
if not target: |
|---|
| 167 |
target = player |
|---|
| 168 |
if target: |
|---|
| 169 |
if not 'count' in action or target.inventory.count(params) < action['count']: |
|---|
| 170 |
target.inventory.append(params) |
|---|
| 171 |
|
|---|
| 172 |
elif action['name'] == 'use': |
|---|
| 173 |
if not target: |
|---|
| 174 |
target = player |
|---|
| 175 |
if target: |
|---|
| 176 |
target.inventory.remove(params) |
|---|
| 177 |
|
|---|
| 178 |
def trigger_event(self, event, actor=None): |
|---|
| 179 |
""" Trigger events if handled by the NPC""" |
|---|
| 180 |
if event == 'on-enter': |
|---|
| 181 |
for on_enter in self.on_enters: |
|---|
| 182 |
if (not on_enter['target'] or |
|---|
| 183 |
on_enter['target'].lower() == actor.name.lower()): |
|---|
| 184 |
for action in on_enter['actions']: |
|---|
| 185 |
self.do_action(action, actor) |
|---|
| 186 |
|
|---|
| 187 |
if event == 'on-leave': |
|---|
| 188 |
for on_leave in self.on_leaves: |
|---|
| 189 |
if (not on_leave['target'] or |
|---|
| 190 |
on_leave['target'].lower() == actor.name.lower()): |
|---|
| 191 |
for action in on_leave['actions']: |
|---|
| 192 |
self.do_action(action, actor) |
|---|
| 193 |
|
|---|
| 194 |
if event == 'on-self-enter': |
|---|
| 195 |
for i in self.on_self_enter: |
|---|
| 196 |
self.do_action(i, actor) |
|---|
| 197 |
|
|---|
| 198 |
if event == 'on-self-leave': |
|---|
| 199 |
for i in self.on_self_leave: |
|---|
| 200 |
self.do_action(i, actor) |
|---|
| 201 |
|
|---|
| 202 |
def trigger_signal(self, signal, actor=None): |
|---|
| 203 |
""" Trigger a signal if handled by the NPC """ |
|---|
| 204 |
for command in self.commands: |
|---|
| 205 |
if signal.strip() == command['signal'].strip(): |
|---|
| 206 |
for action in command['actions']: |
|---|
| 207 |
self.do_action(action, actor) |
|---|
| 208 |
|
|---|
| 209 |
def handle_command(self, text, player): |
|---|
| 210 |
""" |
|---|
| 211 |
Test all combinations with all aliasies. |
|---|
| 212 |
If command is handled, execute actions and return True. |
|---|
| 213 |
Else, return False. |
|---|
| 214 |
""" |
|---|
| 215 |
for alias in self.aliases: |
|---|
| 216 |
for command_obj in self.commands: |
|---|
| 217 |
for command in command_obj['aliases']: |
|---|
| 218 |
command_txt = command |
|---|
| 219 |
command_txt = command_txt.replace('<<self>>', alias) |
|---|
| 220 |
command_txt = command_txt.lower() |
|---|
| 221 |
if command_txt and command_txt in text.lower().strip(): |
|---|
| 222 |
has_required = True |
|---|
| 223 |
for i in command_obj['objects']: |
|---|
| 224 |
if i not in player.inventory: |
|---|
| 225 |
player.send_message('Help!', |
|---|
| 226 |
'You don\'t have a %s' % i) |
|---|
| 227 |
has_required = False |
|---|
| 228 |
break |
|---|
| 229 |
if has_required: |
|---|
| 230 |
player.say('/me %s' % command_obj['name'].replace( |
|---|
| 231 |
'<<self>>', self.name)) |
|---|
| 232 |
for action in command_obj['actions']: |
|---|
| 233 |
self.do_action(action, player) |
|---|
| 234 |
return True |
|---|
| 235 |
return False |
|---|
| 236 |
|
|---|
| 237 |
|
|---|
| 238 |
class NonPlayableCharacter(Movable, Thing): |
|---|
| 239 |
def __init__(self, world, name, jid, place): |
|---|
| 240 |
Movable.__init__(self, world, name, jid) |
|---|
| 241 |
Thing.__init__(self, world, name, place) |
|---|
| 242 |
|
|---|
| 243 |
self.on_self_enter = list() |
|---|
| 244 |
self.on_self_leave = list() |
|---|
| 245 |
|
|---|
| 246 |
def fix_presence(self, role='participant', affiliation='member'): |
|---|
| 247 |
return Movable.fix_presence(self, role, affiliation) |
|---|
| 248 |
|
|---|