source: trunk/game/scripts/gamescenecontroller.py @ 595

Revision 595, 13.3 KB checked in by beliar, 10 years ago (diff)

Patch by Beliar.

  • Items lying on the map can now be picked up. (Items can't be dropped on the map yet though)
  • Every Agent is now given a unique ID if the original is already used. This is needed for the items to be correctly removed from the map in savegames. Note: Savegames have NOT become incompatible in this revision.
Line 
1#!/usr/bin/env python
2
3#   This file is part of PARPG.
4
5#   PARPG is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9
10#   PARPG is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14
15#   You should have received a copy of the GNU General Public License
16#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
17
18from controllerbase import ControllerBase
19from datetime import date, time
20from fife import fife
21from scripts.gui.hud import Hud
22import random
23import glob
24import os
25from objects.action import ChangeMapAction, ExamineAction, OpenBoxAction, \
26                           UnlockBoxAction, LockBoxAction, TalkAction, \
27                           PickUpAction
28
29class GameSceneController(ControllerBase):
30    '''
31    This controller handles inputs when the game is in "scene" state.
32    "Scene" state is when the player can move around and interact
33    with objects. Like, talking to a npc or examining the contents of a box.
34    '''
35
36
37    def __init__(self, engine, view, model, application):
38        '''
39        Constructor
40        @param engine: Instance of the active fife engine
41        @type engine: fife.Engine
42        @param view: Instance of a GameSceneView
43        @param type: scripts.GameSceneView
44        @param model: The model that has the current gamestate
45        @type model: scripts.GameModel
46        @param application: The application that created this controller
47        @type application: scripts.PARPGApplication
48        @param settings: The current settings of the application
49        @type settings: fife.extensions.fife_settings.Setting
50        '''
51        super(GameSceneController, self).__init__(engine,
52                                                  view,
53                                                  model,
54                                                  application,
55                                                  reg_mouse=True, 
56                                                  reg_keys=True)
57        # Last saved mouse coords       
58        self.last_mousecoords = None
59       
60        self.mouse_callback = None
61
62        if model.settings.get("FIFE",  "PlaySounds"):
63            if not self.view.sounds.music_init:
64                music_file = random.choice(glob.glob(os.path.join(
65                                                                  "music", 
66                                                                  "*.ogg")))
67                self.view.sounds.playMusic(music_file) 
68
69
70    def initHud(self):
71        """Initialize the hud member
72        @return: None"""
73        hud_callbacks = {
74            'saveGame': self.saveGame,
75            'loadGame': self.loadGame,
76            'quitGame': self.quitGame,
77        }
78        self.view.hud = Hud(self, 
79                            self.model.settings, 
80                            hud_callbacks)
81
82    def keyPressed(self, evt):
83        """Whenever a key is pressed, fife calls this routine.
84           @type evt: fife.event
85           @param evt: The event that fife caught
86           @return: None"""
87        key = evt.getKey()
88        key_val = key.getValue()
89
90        if(key_val == key.Q):
91            # we need to quit the game
92            self.hud.quitGame()
93        if(key_val == key.T):
94            self.active_map.toggleRenderer('GridRenderer')
95        if(key_val == key.F1):
96            # display the help screen and pause the game
97            self.hud.displayHelp()
98        if(key_val == key.F5):
99            self.active_map.toggleRenderer('CoordinateRenderer')
100        if(key_val == key.F7):
101            # F7 saves a screenshot to fife/clients/parpg/screenshots
102            screenshot_file = "screenshots/screen-%s-%s.png" % \
103                    (date.today().strftime('%Y-%m-%d'),\
104                    time.strftime('%H-%M-%S'))
105            print "PARPG: Saved:", screenshot_file
106            self.engine.getRenderBackend().captureScreen(screenshot_file)
107        if(key_val == key.F10):
108            # F10 shows/hides the console
109            self.engine.getGuiManager().getConsole().toggleShowHide()
110        if(key_val == key.I):
111            # I opens and closes the inventory
112            self.hud.toggleInventory()
113        if(key_val == key.A):
114            # A adds a test action to the action box
115            # The test actions will follow this format: Action 1,
116            # Action 2, etc.
117            self.view.hud.addAction("Action " + str(self.action_number))
118            self.view.action_number += 1
119        if(key_val == key.ESCAPE):
120            # Escape brings up the main menu
121            self.view.hud.displayMenu()
122            # Hide the quit menu
123            self.view.hud.quit_window.hide()
124        if(key_val == key.M):
125            self.view.sounds.toggleMusic()
126        if(key_val == key.PAUSE):
127            # Pause pause/unpause the game
128            self.view.togglePause()
129
130    def mouseReleased(self, evt):
131        """If a mouse button is released, fife calls this routine.
132           We want to wait until the button is released, because otherwise
133           pychan captures the release if a menu is opened.
134           @type evt: fife.event
135           @param evt: The event that fife caught
136           @return: None"""
137        self.view.hud.hideContextMenu()
138        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
139        if(evt.getButton() == fife.MouseEvent.LEFT):
140            self.model.movePlayer(self.model.getCoords(scr_point))
141        elif(evt.getButton() == fife.MouseEvent.RIGHT):
142            # is there an object here?
143            tmp_active_map = self.model.active_map
144            instances = tmp_active_map.cameras[tmp_active_map.my_cam_id].\
145                            getMatchingInstances(scr_point,
146                                                 tmp_active_map.agent_layer)
147            info = None
148            for inst in instances:
149                # check to see if this is an active item
150                if(self.model.objectActive(inst.getId())):
151                    # yes, get the model
152                    info = self.getItemActions(inst.getId())
153                    break
154
155            # take the menu items returned by the engine or show a
156            # default menu if no items
157            data = info or \
158                [["Walk", "Walk here", self.view.onWalk, 
159                  self.model.getCoords(scr_point)]]
160            # show the menu
161            self.view.hud.showContextMenu(data, (scr_point.x, scr_point.y))
162
163    def mouseMoved(self, evt):
164        """Called when the mouse is moved
165           @type evt: fife.event
166           @param evt: The event that fife caught
167           @return: None"""
168        self.last_mousecoords = fife.ScreenPoint(evt.getX(), evt.getY())
169        self.view.highlightFrontObject(self.last_mousecoords)       
170
171    def handleCommands(self):
172        """Check if a command is to be executed
173        """
174        if self.model.map_change:
175            if self.model.active_map:
176                player_agent = self.model.active_map.\
177                                    agent_layer.getInstance("PlayerCharacter")
178                self.model.active_map.agent_layer.deleteInstance(player_agent)
179                player_char = self.model.game_state.player_character
180                self.model.game_state.player_character = None
181                pc_agent = self.model.agents[self.model.ALL_AGENTS_KEY]\
182                                                ["PlayerCharacter"] 
183                pc_agent["Map"] = self.model.target_map_name
184                pc_agent["Position"] = self.model.target_position
185                pc_agent["Inventory"] = player_char.inventory.serializeInventory()
186            self.model.loadMap(self.model.target_map_name)
187            self.model.setActiveMap(self.model.target_map_name)         
188            self.model.readAgentsOfMap(self.model.target_map_name)
189            self.model.placeAgents()
190            self.model.placePC()
191            self.model.map_change = False
192            # The PlayerCharacter has an inventory, and also some
193            # filling of the ready slots in the HUD.
194            # At this point we sync the contents of the ready slots
195            # with the contents of the inventory.
196            self.view.hud.inventory = None
197            self.view.hud.initializeInventory()         
198                       
199    def nullFunc(self, userdata):
200        """Sample callback for the context menus."""
201        print userdata   
202
203    def initTalk(self, npc_info):
204        """ Starts the PlayerCharacter talking to an NPC. """
205        # TODO: work more on this when we get NPCData and HeroData straightened
206        # out
207        npc = self.model.game_state.getObjectById(npc_info.ID,
208                                            self.model.game_state.\
209                                                current_map_name)
210        self.model.game_state.player_character.approach([npc.getLocation().\
211                                     getLayerCoordinates().x,
212                                     npc.getLocation().\
213                                     getLayerCoordinates().y],
214                                    TalkAction(self, npc))
215
216    def getItemActions(self, obj_id):
217        """Given the objects ID, return the text strings and callbacks.
218           @type obj_id: string
219           @param obj_id: ID of object
220           @rtype: list
221           @return: List of text and callbacks"""
222        actions = []
223        # note: ALWAYS check NPC's first!
224        obj = self.model.game_state.\
225                        getObjectById(obj_id,
226                                      self.model.game_state.current_map_name)
227       
228        if obj is not None:
229            if obj.trueAttr("NPC"):
230                # keep it simple for now, None to be replaced by callbacks
231                actions.append(["Talk", "Talk", self.initTalk, obj])
232                actions.append(["Attack", "Attack", self.nullFunc, obj])
233            else:
234                actions.append(["Examine", "Examine",
235                                self.model.game_state.player_character.approach, 
236                                [obj.X, obj.Y],
237                                ExamineAction(self, obj.name, obj.text)])
238                # is it a Door?
239                if obj.trueAttr("door"):
240                    actions.append(["Change Map", "Change Map",
241                       self.model.game_state.player_character.approach, 
242                       [obj.X, obj.Y],
243                       ChangeMapAction(self, obj.target_map_name,
244                                       obj.target_pos)])
245                # is it a container?
246                if obj.trueAttr("container"):
247                    actions.append(["Open", "Open", 
248                                    self.model.game_state.\
249                                        player_character.approach,
250                                    [obj.X, obj.Y],
251                                    OpenBoxAction(self, obj)])
252                    actions.append(["Unlock", "Unlock", 
253                                    self.model.game_state.\
254                                        player_character.approach,
255                                    [obj.X, obj.Y],
256                                    UnlockBoxAction(self, obj)])
257                    actions.append(["Lock", "Lock", 
258                                    self.model.game_state.\
259                                        player_character.approach,
260                                    [obj.X, obj.Y],
261                                    LockBoxAction(self, obj)])
262                # can you pick it up?
263                if obj.trueAttr("carryable"):
264                    actions.append(["Pick Up", "Pick Up", 
265                                    self.model.game_state.\
266                                        player_character.approach,
267                                    [obj.X, obj.Y],
268                                    PickUpAction(self, obj)])
269
270        return actions
271   
272    def saveGame(self, *args, **kwargs):
273        """Saves the game state, delegates call to engine.Engine
274           @return: None"""
275        self.model.save(*args, **kwargs)
276
277    def loadGame(self, *args, **kwargs):
278        """Loads the game state, delegates call to engine.Engine
279           @return: None"""
280        # Remove all currently loaded maps so we can start fresh
281        self.model.deleteMaps()
282        self.view.hud.inventory = None
283
284        self.model.load(*args, **kwargs)
285        self.view.hud.initializeInventory()         
286
287    def quitGame(self):
288        """Quits the game
289           @return: None"""
290        self.application.listener.quitGame()
291
292    def pump(self):
293        """Routine called during each frame. Our main loop is in ./run.py"""
294        # uncomment to instrument
295        # t0 = time.time()
296        if self.model.active_map:
297            self.view.highlightFrontObject(self.last_mousecoords)
298            self.view.refreshTopLayerTransparencies()
299        self.handleCommands()
300        # print "%05f" % (time.time()-t0,)
Note: See TracBrowser for help on using the repository browser.