source: trunk/game/scripts/world.py @ 21

Revision 21, 11.2 KB checked in by icelus_parpg, 10 years ago (diff)

Apply ActionStack? patch from tie (ticket #1).

  • queue actions for hero to perform (e.g. move to target, act)
  • unit tests for ActionStack?
  • new run_tests script
  • kick added as an always present to allow queueing to be seen.
  • Property svn:eol-style set to native
Line 
1import fife, math, random
2import pychan
3import pychan.widgets as widgets
4
5from scripts.common.eventlistenerbase import EventListenerBase
6from loaders import loadMapFile
7from savers import saveMapFile
8from agents.hero import Hero
9from agents.girl import Girl
10from agents.cloud import Cloud
11from agents.beekeeper import Beekeeper
12from agents.agent import create_anonymous_agents
13from settings import Setting
14
15TDS = Setting()
16
17class MapListener(fife.MapChangeListener):
18        def __init__(self, map):
19                fife.MapChangeListener.__init__(self)
20                map.addChangeListener(self)
21
22        def onMapChanged(self, map, changedLayers):
23                return
24                print "Changes on map ", map.getId()
25                for layer in map.getLayers():
26                        print layer.getId()
27                        print "    ", ["%s, %x" % (i.getObject().getId(), i.getChangeInfo()) for i in layer.getChangedInstances()]
28
29        def onLayerCreate(self, map, layer):
30                pass
31
32        def onLayerDelete(self, map, layer):
33                pass
34
35
36class World(EventListenerBase):
37        def __init__(self, engine):
38                super(World, self).__init__(engine, regMouse=True, regKeys=True)
39                self.engine = engine
40                self.eventmanager = engine.getEventManager()
41                self.model = engine.getModel()
42                self.view = self.engine.getView()
43                self.filename = ''
44                self.pump_ctr = 0 # for testing purposis
45                self.ctrldown = False
46                self.instancemenu = pychan.loadXML('gui/instancemenu.xml')
47                # we keep a copy of all possible buttons to avoid reloading of XML
48                self.all_btns = [btn for btn in self.instancemenu.children]
49                self.instance_to_agent = {}
50                # dynamic_widgets should no longer be necessary; commenting them out to be safe
51                #self.dynamic_widgets = {}   
52               
53        def show_instancemenu(self, clickpoint, instance):
54                """Handles the display of the right-click context menu."""
55                # IMPORTANT: We assume that the ALWAYS_PRESENT_BUTTONS are
56                # _NEVER_ removed from the instancemenu
57                # IMPORTANT: World and Agent functions that handle different
58                # actions must be named "buttonNameHandler", e.g.
59                # "talkButtonHandler"
60               
61                # no right-click menu for clicking on Hero
62                if instance.getFifeId() == self.hero.agent.getFifeId():
63                        return
64                # Buttons that will always be available, regardless of the
65                # instance type.
66                # IMPORTANT: kickButton is listed here only to allow easier
67                # testing of the range check/queueing code
68                ALWAYS_PRESENT_BTNS = ('moveButton', 
69                                       'inspectButton', 
70                                       'kickButton'
71                                       )
72                # Pattern matching the name of the handler functions
73                NAME_PATTERN = "%sHandler"
74               
75                if self.instance_to_agent.has_key(instance.getFifeId()):
76                        # we got an agent here; remove any unhandled actions
77                        for btn in self.all_btns:
78                                #do we have this button in the current menu?
79                                btn_present = bool(self.instancemenu.findChild(name=btn.name))
80                                # do we need this button in the current menu?
81                                btn_needed = hasattr(self.instance_to_agent[instance.getFifeId()],NAME_PATTERN % btn.name) \
82                                           or btn.name in ALWAYS_PRESENT_BTNS
83                                if btn_needed and not btn_present:
84                                        self.instancemenu.addChild(btn)
85                                elif not btn_needed and btn_present:
86                                        self.instancemenu.removeChild(btn)
87                else:
88                        # inst is not Agent; only leave always_present actions
89                        for btn in self.instancemenu.children[:]:
90                                if not btn.name in ALWAYS_PRESENT_BTNS:
91                                        self.instancemenu.removeChild(btn)
92
93                # map a dictionary of button names to the their World fuctions
94                mapdict = dict([ (btn.name,getattr(self, NAME_PATTERN % btn.name))
95                                 for btn in self.instancemenu.children])
96                self.instancemenu.mapEvents (mapdict)
97               
98                # add some global data
99                self.instancemenu.clickpoint = clickpoint
100                self.instancemenu.instance = instance           
101                self.instancemenu.position = (clickpoint.x, clickpoint.y)
102                # show the menu
103                self.instancemenu.show()
104                return 
105
106        def hide_instancemenu(self):
107                if self.instancemenu:
108                        self.instancemenu.hide()
109
110        def reset(self):
111                self.map, self.agentlayer = None, None
112                self.cameras = {}
113                self.hero, self.girl, self.clouds, self.beekeepers = None, None, [], []
114                self.cur_cam2_x, self.initial_cam2_x, self.cam2_scrolling_right = 0, 0, True
115                self.target_rotation = 0
116                self.instance_to_agent = {}
117
118        def load(self, filename):
119                self.filename = filename
120                self.reset()
121                self.map = loadMapFile(filename, self.engine)
122                self.maplistener = MapListener(self.map)
123
124                self.agentlayer = self.map.getLayer('TechdemoMapGroundObjectLayer')
125                self.hero = Hero(self.model, 'PC', self.agentlayer)
126                self.instance_to_agent[self.hero.agent.getFifeId()] = self.hero
127                self.hero.start()
128
129                self.girl = Girl(self.model, 'NPC:girl', self.agentlayer)
130                self.instance_to_agent[self.girl.agent.getFifeId()] = self.girl
131                self.girl.start()
132
133                self.beekeepers = create_anonymous_agents(self.model, 'beekeeper', self.agentlayer, Beekeeper)
134                for beekeeper in self.beekeepers:
135                        self.instance_to_agent[beekeeper.agent.getFifeId()] = beekeeper
136                        beekeeper.start()
137
138                cloudlayer = self.map.getLayer('TechdemoMapTileLayer')
139                self.clouds = create_anonymous_agents(self.model, 'Cloud', cloudlayer, Cloud)
140                for cloud in self.clouds:
141                        cloud.start(0.1, 0.05)
142
143                for cam in self.view.getCameras():
144                        self.cameras[cam.getId()] = cam
145                self.cameras['main'].attach(self.hero.agent)
146
147                self.view.resetRenderers()
148                renderer = fife.FloatingTextRenderer.getInstance(self.cameras['main'])
149                textfont = self.engine.getGuiManager().createFont('fonts/rpgfont.png', 0, str(TDS.readSetting("FontGlyphs", strip=False)));
150                renderer.changeDefaultFont(textfont)
151
152                renderer = fife.FloatingTextRenderer.getInstance(self.cameras['small'])
153                renderer.changeDefaultFont(None)
154
155                renderer = self.cameras['main'].getRenderer('CoordinateRenderer')
156                renderer.clearActiveLayers()
157                renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("CoordinateLayerName"))))
158
159                renderer = self.cameras['main'].getRenderer('QuadTreeRenderer')
160                renderer.setEnabled(True)
161                renderer.clearActiveLayers()
162                if str(TDS.readSetting("QuadTreeLayerName")):
163                        renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("QuadTreeLayerName"))))
164
165                self.cameras['small'].getLocationRef().setExactLayerCoordinates( fife.ExactModelCoordinate( 40.0, 40.0, 0.0 ))
166                self.initial_cam2_x = self.cameras['small'].getLocation().getExactLayerCoordinates().x
167                self.cur_cam2_x = self.initial_cam2_x
168                self.cam2_scrolling_right = True
169                self.cameras['small'].setEnabled(False)
170
171                self.target_rotation = self.cameras['main'].getRotation()
172
173        def save(self, filename):
174                saveMapFile(filename, self.engine, self.map)
175
176        def keyPressed(self, evt):
177                keyval = evt.getKey().getValue()
178                keystr = evt.getKey().getAsString().lower()
179                if keystr == 't':
180                        r = self.cameras['main'].getRenderer('GridRenderer')
181                        r.setEnabled(not r.isEnabled())
182                elif keystr == 'c':
183                        r = self.cameras['main'].getRenderer('CoordinateRenderer')
184                        r.setEnabled(not r.isEnabled())
185                elif keystr == 's':
186                        c = self.cameras['small']
187                        c.setEnabled(not c.isEnabled())
188                elif keystr == 'r':
189                        pass
190#                       self.model.deleteMaps()
191#                       self.metamodel.deleteDatasets()
192#                       self.view.clearCameras()
193#                       self.load(self.filename)
194                elif keystr == 'o':
195                        self.target_rotation = (self.target_rotation + 90) % 360
196                elif keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL):
197                        self.ctrldown = True
198
199        def keyReleased(self, evt):
200                keyval = evt.getKey().getValue()
201                if keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL):
202                        self.ctrldown = False
203
204        def mouseWheelMovedUp(self, evt):
205                if self.ctrldown:
206                        self.cameras['main'].setZoom(self.cameras['main'].getZoom() * 1.05)
207
208        def mouseWheelMovedDown(self, evt):
209                if self.ctrldown:
210                        self.cameras['main'].setZoom(self.cameras['main'].getZoom() / 1.05)
211
212        def changeRotation(self):
213                currot = self.cameras['main'].getRotation()
214                if self.target_rotation != currot:
215                        self.cameras['main'].setRotation((currot + 5) % 360)
216
217        def mousePressed(self, evt):
218                # quick and dirty way to clear queued actions
219                self.hero.action_stack.clear()
220                if evt.isConsumedByWidgets():
221                        return
222
223                clickpoint = fife.ScreenPoint(evt.getX(), evt.getY())
224                if (evt.getButton() == fife.MouseEvent.LEFT):
225                        self.hide_instancemenu()
226                        target_mapcoord = self.cameras['main'].toMapCoordinates(clickpoint, False)
227                        target_mapcoord.z = 0
228                        l = fife.Location(self.agentlayer)
229                        l.setMapCoordinates(target_mapcoord)
230                        self.hero.run(l)
231
232                if (evt.getButton() == fife.MouseEvent.RIGHT):
233                        self.hide_instancemenu()
234                        instances = self.cameras['main'].getMatchingInstances(clickpoint, self.agentlayer)
235                        print "selected instances on agent layer: ", [i.getObject().getId() for i in instances]
236                        if instances:
237                                self.show_instancemenu(clickpoint, instances[0])
238
239        def mouseMoved(self, evt):
240                renderer = fife.InstanceRenderer.getInstance(self.cameras['main'])
241                renderer.removeAllOutlines()
242
243                pt = fife.ScreenPoint(evt.getX(), evt.getY())
244                instances = self.cameras['main'].getMatchingInstances(pt, self.agentlayer);
245                for i in instances:
246                        if i.getObject().getId() in ('girl', 'beekeeper'):
247                                renderer.addOutlined(i, 173, 255, 47, 2)
248
249        def onConsoleCommand(self, command):
250                result = ''
251                try:
252                        result = str(eval(command))
253                except:
254                        pass
255                return result
256
257        def moveButtonHandler(self):
258                self.hide_instancemenu()
259                self.hero.run(self.instancemenu.instance.getLocationRef())
260
261        def talkButtonHandler(self):
262                self.hide_instancemenu()
263                instance = self.instancemenu.instance
264                self.hero.talk(instance.getLocationRef())
265                if instance.getObject().getId() == 'beekeeper':
266                        beekeeperTexts = TDS.readSetting("beekeeperTexts", type='list', text=True)
267                        txtindex = random.randint(0, len(beekeeperTexts) - 1)
268                        instance.say(beekeeperTexts[txtindex], 5000)
269                if instance.getObject().getId() == 'girl':
270                        girlTexts = TDS.readSetting("girlTexts", type='list', text=True)
271                        txtindex = random.randint(0, len(girlTexts) - 1)
272                        instance.say(girlTexts[txtindex], 5000)
273
274        def kickButtonHandler(self):
275                self.hide_instancemenu()
276                inst = self.instancemenu.instance
277                #proof-of-concept range checking + action queueing
278                if self.hero.distance_to (inst) > 3:
279                        self.hero.action_stack.add_action (self.hero.agent.follow, 
280                                                          ('run',inst,4 * float(TDS.readSetting("TestAgentSpeed"))), 
281                                                         lambda x: self.hero.distance_to(x) <= 3,
282                                                         (inst,)
283                                                         )
284                        self.hero.action_stack.add_action (self.kickButtonHandler)
285                        self.hero.action_stack.run()
286                        return
287               
288                self.hero.kick(self.instancemenu.instance.getLocationRef())
289                self.instancemenu.instance.say('Hey!', 1000)
290               
291        def kissButtonHandler(self):
292                self.hide_instancemenu()
293                self.instance_to_agent[self.instancemenu.instance.getFifeId()].kissButtonHandler (self.instancemenu.instance,self.hero)
294
295        def inspectButtonHandler(self):
296                self.hide_instancemenu()
297                inst = self.instancemenu.instance
298                saytext = ['Engine told me that this instance has']
299                if inst.getId():
300                        saytext.append(' name %s,' % inst.getId())
301                saytext.append(' ID %s and' % inst.getFifeId())
302                saytext.append(' object name %s' % inst.getObject().getId())
303                self.hero.agent.say('\n'.join(saytext), 3500)
304
305        def pump(self):
306                if self.cameras['small'].isEnabled():
307                        loc = self.cameras['small'].getLocation()
308                        c = loc.getExactLayerCoordinatesRef()
309                        if self.cam2_scrolling_right:
310                                self.cur_cam2_x = c.x = c.x+0.1
311                                if self.cur_cam2_x > self.initial_cam2_x+10:
312                                        self.cam2_scrolling_right = False
313                        else:
314                                self.cur_cam2_x = c.x = c.x-0.1
315                                if self.cur_cam2_x < self.initial_cam2_x-10:
316                                        self.cam2_scrolling_right = True
317                        self.cameras['small'].setLocation(loc)
318                self.changeRotation()
319                self.pump_ctr += 1
Note: See TracBrowser for help on using the repository browser.