source: branches/active/character_customization/game/parpg/gamescenecontroller.py @ 790

Revision 790, 18.0 KB checked in by aspidites, 9 years ago (diff)

Patch by Aspidites:

  • removed files related to windows packaging
  • simplified settings module API:

+ paths argument no longer exists. There is now exactly

3 arguments: system_path, user_path, and prefix, which

will eventually be explained in documentation

+ user config file is now properly created, leaving the

system config file untouched

+ by default, the new suffix is '.cfg'.
+ sections and options are now properties instead of callables

  • updated menus.py to cope with these minor changes
  • updated setup scripts (both) with missing path information

+ only thing remaining for the windows installer is to test on

on a windows machine (as opposed to wine), and to get
prerequisites installed correctly (fife installer giving trouble)

  • Property svn:eol-style set to native
Line 
1#   This file is part of PARPG.
2
3#   PARPG is free software: you can redistribute it and/or modify
4#   it under the terms of the GNU General Public License as published by
5#   the Free Software Foundation, either version 3 of the License, or
6#   (at your option) any later version.
7
8#   PARPG is distributed in the hope that it will be useful,
9#   but WITHOUT ANY WARRANTY; without even the implied warranty of
10#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#   GNU General Public License for more details.
12
13#   You should have received a copy of the GNU General Public License
14#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
15"""This file contains the GameSceneController that handles input when the game
16   is exploring a scene"""
17
18
19from datetime import datetime
20import random
21import glob
22import os
23
24from fife import fife
25from fife import extensions
26
27from controllerbase import ControllerBase
28from parpg.gui.hud import Hud
29from parpg.gui import drag_drop_data as data_drag
30from objects.action import ChangeMapAction, ExamineAction, OpenBoxAction, \
31                           UnlockBoxAction, LockBoxAction, TalkAction, \
32                           PickUpAction, DropItemAction
33
34#For debugging/code analysis
35if False:
36    from gamesceneview import GameSceneView
37    from gamemodel import GameModel
38    from parpg import PARPGApplication
39
40class GameSceneController(ControllerBase):
41    '''
42    This controller handles inputs when the game is in "scene" state.
43    "Scene" state is when the player can move around and interact
44    with objects. Like, talking to a npc or examining the contents of a box.
45    '''
46
47
48    def __init__(self, engine, view, model, application):
49        '''
50        Constructor
51        @param engine: Instance of the active fife engine
52        @type engine: fife.Engine
53        @param view: Instance of a GameSceneView
54        @param type: parpg.GameSceneView
55        @param model: The model that has the current gamestate
56        @type model: parpg.GameModel
57        @param application: The application that created this controller
58        @type application: parpg.PARPGApplication
59        @param settings: The current settings of the application
60        @type settings: fife.extensions.fife_settings.Setting
61        '''
62        ControllerBase.__init__(self,
63                                engine,
64                                view,
65                                model,
66                                application)
67        #this can be helpful for IDEs code analysis
68        if False:
69            assert(isinstance(self.engine, fife.Engine))
70            assert(isinstance(self.view, GameSceneView))
71            assert(isinstance(self.view, GameModel))
72            assert(isinstance(self.application, PARPGApplication))
73            assert(isinstance(self.event_manager, fife.EventManager))
74       
75        # Last saved mouse coords       
76        self.action_number = 1
77
78        self.has_mouse_focus = True
79        self.last_mousecoords = None
80        self.mouse_callback = None
81        self.original_cursor_id = self.engine.getCursor().getId()       
82        self.scroll_direction = [0, 0]
83        self.scroll_timer = extensions.fife_timer.Timer(100,
84                                          lambda: self.view.moveCamera \
85                                                   (self.scroll_direction))   
86       
87        #this is temporary until we can set the native cursor
88        self.resetMouseCursor()
89        self.paused = False
90
91        if model.settings.fife.PlaySounds:
92            if not self.view.sounds.music_init:
93                music_file = random.choice(glob.glob(os.path.join(
94                                                                  "music", 
95                                                                  "*.ogg")))
96                self.view.sounds.playMusic(music_file) 
97        self.initHud()
98               
99
100    def initHud(self):
101        """Initialize the hud member
102        @return: None"""
103        hud_callbacks = {
104            'saveGame': self.saveGame,
105            'loadGame': self.loadGame,
106            'quitGame': self.quitGame,
107        }
108        self.view.hud = Hud(self, 
109                            self.model.settings, 
110                            hud_callbacks)
111
112    def keyPressed(self, evt):
113        """Whenever a key is pressed, fife calls this routine.
114           @type evt: fife.event
115           @param evt: The event that fife caught
116           @return: None"""
117        key = evt.getKey()
118        key_val = key.getValue()
119
120        if(key_val == key.Q):
121            # we need to quit the game
122            self.view.hud.quitGame()
123        if(key_val == key.T):
124            self.model.active_map.toggleRenderer('GridRenderer')
125        if(key_val == key.F1):
126            # display the help screen and pause the game
127            self.view.hud.displayHelp()
128        if(key_val == key.F5):
129            self.model.active_map.toggleRenderer('CoordinateRenderer')
130        if(key_val == key.F7):
131            # F7 saves a screenshot to fife/clients/parpg/screenshots
132           
133            screenshotdir = model.settings.parpg.ScreenshotsDirectory
134            screenshot_file = os.path.join(screenshotdir, 
135                                           'screen-{0}.png'.format(
136                                           datetime.now().strftime(
137                                           '%Y-%m-%d-%H-%M-%S')))
138            print "PARPG: Saved:", screenshot_file
139            self.engine.getRenderBackend().captureScreen(screenshot_file)
140        if(key_val == key.F10):
141            # F10 shows/hides the console
142            self.engine.getGuiManager().getConsole().toggleShowHide()
143        if(key_val == key.C):
144            # C opens and closes the character screen.
145            self.view.hud.toggleCharacterScreen()
146        if(key_val == key.I):
147            # I opens and closes the inventory
148            self.view.hud.toggleInventory()
149        if(key_val == key.A):
150            # A adds a test action to the action box
151            # The test actions will follow this format: Action 1,
152            # Action 2, etc.
153            self.view.hud.addAction("Action " + str(self.action_number))
154            self.action_number += 1
155        if(key_val == key.ESCAPE):
156            # Escape brings up the main menu
157            self.view.hud.displayMenu()
158            # Hide the quit menu
159            self.view.hud.quit_window.hide()
160        if(key_val == key.M):
161            self.view.sounds.toggleMusic()
162        if(key_val == key.PAUSE):
163            # Pause pause/unpause the game
164            self.model.togglePause()
165            self.pause(False)
166        if(key_val == key.SPACE):
167            self.model.active_map.centerCameraOnPlayer() 
168   
169    def mouseReleased(self, evt):
170        """If a mouse button is released, fife calls this routine.
171           We want to wait until the button is released, because otherwise
172           pychan captures the release if a menu is opened.
173           @type evt: fife.event
174           @param evt: The event that fife caught
175           @return: None"""
176        self.view.hud.hideContextMenu()
177        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
178        if(evt.getButton() == fife.MouseEvent.LEFT):
179            if(data_drag.dragging):
180                coord = self.model.getCoords(scr_point)\
181                                    .getExactLayerCoordinates()
182                commands = ({"Command": "ResetMouseCursor"}, 
183                            {"Command": "StopDragging"})
184                self.model.game_state.player_character.approach([coord.x, 
185                                                                 coord.y],
186                                    DropItemAction(self, 
187                                                   data_drag.dragged_item, 
188                                                   commands))
189            else:
190                self.model.movePlayer(self.model.getCoords(scr_point))
191        elif(evt.getButton() == fife.MouseEvent.RIGHT):
192            # is there an object here?
193            tmp_active_map = self.model.active_map
194            instances = tmp_active_map.cameras[tmp_active_map.my_cam_id].\
195                            getMatchingInstances(scr_point,
196                                                 tmp_active_map.agent_layer)
197            info = None
198            for inst in instances:
199                # check to see if this is an active item
200                if(self.model.objectActive(inst.getId())):
201                    # yes, get the model
202                    info = self.getItemActions(inst.getId())
203                    break
204
205            # take the menu items returned by the engine or show a
206            # default menu if no items
207            data = info or \
208                [["Walk", "Walk here", self.view.onWalk, 
209                  self.model.getCoords(scr_point)]]
210            # show the menu
211            self.view.hud.showContextMenu(data, (scr_point.x, scr_point.y))
212   
213       
214    def updateMouse(self):
215        """Updates the mouse values"""
216        if self.paused:
217            return
218        cursor = self.engine.getCursor()
219        #this can be helpful for IDEs code analysis
220        if False:
221            assert(isinstance(cursor, fife.Cursor))
222        self.last_mousecoords = fife.ScreenPoint(cursor.getX(), 
223                                                 cursor.getY())       
224        self.view.highlightFrontObject(self.last_mousecoords)       
225       
226        #set the trigger area in pixles
227        pixle_edge = 20
228       
229        mouse_x = self.last_mousecoords.x
230        screen_width = self.model.engine.getSettings().getScreenWidth()
231        mouse_y = self.last_mousecoords.y
232        screen_height = self.model.engine.getSettings().getScreenHeight()
233       
234        image = None
235        settings = self.model.settings
236       
237       
238        #edge logic
239        self.scroll_direction = [0, 0]
240        if self.has_mouse_focus:
241            direction = self.scroll_direction
242            #up
243            if mouse_y <= pixle_edge: 
244                direction[0] += 1
245                direction[1] -= 1
246                image = settings.parpg.CursorUp
247               
248            #right
249            if mouse_x >= screen_width - pixle_edge:
250                direction[0] += 1
251                direction[1] += 1
252                image = settings.parpg.CursorRight
253               
254            #down
255            if mouse_y >= screen_height - pixle_edge:
256                direction[0] -= 1
257                direction[1] += 1
258                image = settings.parpg.CursorDown
259               
260            #left
261            if mouse_x <= pixle_edge:
262                direction[0] -= 1
263                direction[1] -= 1
264                image = settings.parpg.CursorLeft
265           
266            if image != None and not data_drag.dragging:
267                self.setMouseCursor(image, image)
268       
269
270    def handleCommands(self):
271        """Check if a command is to be executed
272        """
273        if self.model.map_change:
274            self.pause(True)
275            if self.model.active_map:
276                player_char = self.model.game_state.player_character
277                self.model.game_state.player_character = None
278                pc_agent = self.model.agents[self.model.ALL_AGENTS_KEY]\
279                                                ["PlayerCharacter"]
280                pc_agent.update(player_char.getStateForSaving())
281                pc_agent["Map"] = self.model.target_map_name
282                pc_agent["Position"] = self.model.target_position
283                pc_agent["Inventory"] = \
284                        player_char.inventory.serializeInventory()
285                player_agent = self.model.active_map.\
286                                    agent_layer.getInstance("PlayerCharacter")
287                self.model.active_map.agent_layer.deleteInstance(player_agent)
288            self.model.loadMap(self.model.target_map_name)
289            self.model.setActiveMap(self.model.target_map_name)         
290            self.model.readAgentsOfMap(self.model.target_map_name)
291            self.model.placeAgents()
292            self.model.placePC()
293            self.model.map_change = False
294            # The PlayerCharacter has an inventory, and also some
295            # filling of the ready slots in the HUD.
296            # At this point we sync the contents of the ready slots
297            # with the contents of the inventory.
298            self.view.hud.inventory = None
299            self.view.hud.initializeInventory()         
300            self.pause(False)
301
302    def nullFunc(self, userdata):
303        """Sample callback for the context menus."""
304        print userdata   
305
306    def initTalk(self, npc_info):
307        """ Starts the PlayerCharacter talking to an NPC. """
308        # TODO: work more on this when we get NPCData and HeroData straightened
309        # out
310        npc = self.model.game_state.getObjectById(npc_info.ID,
311                                            self.model.game_state.\
312                                                current_map_name)
313        self.model.game_state.player_character.approach([npc.getLocation().\
314                                     getLayerCoordinates().x,
315                                     npc.getLocation().\
316                                     getLayerCoordinates().y],
317                                    TalkAction(self, npc))
318
319    def getItemActions(self, obj_id):
320        """Given the objects ID, return the text strings and callbacks.
321           @type obj_id: string
322           @param obj_id: ID of object
323           @rtype: list
324           @return: List of text and callbacks"""
325        actions = []
326        # note: ALWAYS check NPC's first!
327        obj = self.model.game_state.\
328                        getObjectById(obj_id,
329                                      self.model.game_state.current_map_name)
330       
331        if obj is not None:
332            if obj.trueAttr("NPC"):
333                # keep it simple for now, None to be replaced by callbacks
334                actions.append(["Talk", "Talk", self.initTalk, obj])
335                actions.append(["Attack", "Attack", self.nullFunc, obj])
336            else:
337                actions.append(["Examine", "Examine",
338                                self.model.game_state.\
339                                player_character.approach, 
340                                [obj.X, obj.Y],
341                                ExamineAction(self, 
342                                              obj_id, obj.name, 
343                                              obj.text)])
344                # is it a Door?
345                if obj.trueAttr("door"):
346                    actions.append(["Change Map", "Change Map",
347                       self.model.game_state.player_character.approach, 
348                       [obj.X, obj.Y],
349                       ChangeMapAction(self, obj.target_map_name,
350                                       obj.target_pos)])
351                # is it a container?
352                if obj.trueAttr("container"):
353                    actions.append(["Open", "Open", 
354                                    self.model.game_state.\
355                                        player_character.approach,
356                                    [obj.X, obj.Y],
357                                    OpenBoxAction(self, obj)])
358                    actions.append(["Unlock", "Unlock", 
359                                    self.model.game_state.\
360                                        player_character.approach,
361                                    [obj.X, obj.Y],
362                                    UnlockBoxAction(self, obj)])
363                    actions.append(["Lock", "Lock", 
364                                    self.model.game_state.\
365                                        player_character.approach,
366                                    [obj.X, obj.Y],
367                                    LockBoxAction(self, obj)])
368                # can you pick it up?
369                if obj.trueAttr("carryable"):
370                    actions.append(["Pick Up", "Pick Up", 
371                                    self.model.game_state.\
372                                        player_character.approach,
373                                    [obj.X, obj.Y],
374                                    PickUpAction(self, obj)])
375
376        return actions
377   
378    def saveGame(self, *args, **kwargs):
379        """Saves the game state, delegates call to engine.Engine
380           @return: None"""
381        self.model.pause(False)
382        self.pause(False)
383        self.view.hud.enabled = True
384        self.model.save(*args, **kwargs)
385
386    def loadGame(self, *args, **kwargs):
387        """Loads the game state, delegates call to engine.Engine
388           @return: None"""
389        # Remove all currently loaded maps so we can start fresh
390        self.model.pause(False)
391        self.pause(False)
392        self.view.hud.enabled = True
393        self.model.deleteMaps()
394        self.view.hud.inventory = None
395
396        self.model.load(*args, **kwargs)
397        self.view.hud.initializeInventory()         
398
399    def quitGame(self):
400        """Quits the game
401           @return: None"""
402        self.application.listener.quitGame()
403   
404    def pause(self, paused):
405        """Pauses the controller"""
406        super(GameSceneController, self).pause(paused)
407        self.paused = paused
408        if paused:
409            self.scroll_timer.stop()
410            self.resetMouseCursor()
411   
412    def onCommand(self, command):
413        if(command.getCommandType() == fife.CMD_MOUSE_FOCUS_GAINED):
414            self.has_mouse_focus = True
415        elif(command.getCommandType() == fife.CMD_MOUSE_FOCUS_LOST):
416            self.has_mouse_focus = False
417     
418    def pump(self):
419        """Routine called during each frame. Our main loop is in ./run.py"""
420        # uncomment to instrument
421        # t0 = time.time()
422        if self.paused: 
423            return
424        self.updateMouse()
425        if self.model.active_map:
426            self.view.highlightFrontObject(self.last_mousecoords)
427            self.view.refreshTopLayerTransparencies()
428            if self.scroll_direction != [0, 0]:
429                self.scroll_timer.start()
430            else: 
431                self.scroll_timer.stop()
432                if not data_drag.dragging:
433                    self.resetMouseCursor()
434               
435        self.handleCommands()
436        # print "%05f" % (time.time()-t0,)
Note: See TracBrowser for help on using the repository browser.