root/adventure/thing.py

Revision 156, 10.0 kB (checked in by thib, 6 months ago)

Quelques modifs ( World, Place et Thing héritent d'object )

Line 
1 # -*- coding: utf-8 -*-
2
3 #  MUDMUC
4 #  thing.py
5 #  Copyright (c) 2008 Thibaut Girka, Anaël Verrier
6
7 #  This program is free software; you can redistribute it and/or modify
8 #  it under the terms of the GNU General Public License as published by
9 #  the Free Software Foundation; version 3 only.
10
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program; if not, write to the Free Software
18 #  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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,] # Alternative names
28         self.commands = list() # List of dicts : name, actions : 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         # Resolve target: None, self, player, or a Player instance
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         # Parse parameters, replace %self% and %actor%
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         # Execute actions
107         #   <say [target="actor|self|name"]>text</say>
108         if action['name'] == 'say':
109             if target:
110                 self.say(params, target)
111             else:
112                 self.say(params)
113        
114         #   <narration>text</narration>
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         #   <follow [target="actor|self|name"] />
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         #   <signal [target="name"]>signal</signal>
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         #   <move [target="actor|self|name"]>place</move>
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         #   <add-exit>spec: place</add-exit>
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         #   <del-exit>spec</del-exit>
161         elif action['name'] == 'del-exit':
162             if self.place.exits.has_key(params):
163                 del self.place.exits[params]
164         #   <give target="target">object</give>
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         #   <use target="target">object</give>
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
Note: See TracBrowser for help on using the browser.