source: trunk/game/scripts/engine.py @ 312

Revision 312, 11.0 KB checked in by Kaydeth_parpg, 10 years ago (diff)

Ticket #2: Patch by Kaydeth. Updated the classes in console.py through engine.py (went through files alphabetically) to correct some obvious discrepancies with our coding standard. comment[s:trac, t:2]

  • Property svn:eol-style set to native
Line 
1#!/usr/bin/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
18# there should be NO references to FIFE here!
19import pickle
20import sys
21from gamestate import GameState
22from objects import *
23from objectLoader import ObjectXMLParser
24from objects.action import *
25
26
27class Engine:
28    """Engine holds the logic for the game.
29       Since some data (object position and so forth) is held in the
30       fife, and would be pointless to replicate, we hold a instance of
31       the fife view here. This also prevents us from just having a
32       function heavy controller."""
33   
34    def __init__(self, view):
35        """Initialise the instance.
36           @type view: world
37           @param view: A world instance
38           @return: None"""
39        # a World object (the fife stuff, essentially)
40        self.view = view
41        self.map_change = False
42        self.game_state = GameState()
43        self.pc_run = 1
44        self.target_position = None
45    def reset(self):
46        """Clears the data on a map reload so we don't have objects/npcs from
47           other maps hanging around.
48           @return: None"""
49
50    def save(self, path, filename):
51        """Writes the saver to a file.
52           @type filename: string
53           @param filename: the name of the file to write to
54           @return: None"""
55        fname = '/'.join([path,filename])
56        try:
57            f = open(fname, 'w')
58        except(IOError):
59            sys.stderr.write("Error: Can't find save game: " + fname + "\n")
60            return
61       
62        # can't pickle SwigPyObjects
63        behaviours = {}
64        behaviours[self.game_state.PC.ID] = self.game_state.PC.behaviour;
65        self.game_state.PC.behaviour = None;
66       
67        npcs = [npc for npc in self.game_state.objects.values() \
68                if npc.trueAttr("NPC")]
69        for npc in npcs:
70            behaviours[npc.ID] = npc.behaviour;
71            npc.behaviour = None;
72       
73        pickle.dump(self.game_state, f)
74        f.close()
75       
76        # restore behaviours
77        for npc in npcs:
78            npc.behaviour = behaviours[npc.ID];
79        self.game_state.PC.behaviour = behaviours[self.game_state.PC.ID]
80
81    def load(self, path, filename):
82        """Loads a saver from a file.
83           @type path: string
84           @param path: the path where the savefile is located
85           @type filename: string
86           @param filename: the name of the file to load from
87           @return: None"""
88        fname = '/'.join([path, filename])
89        try:
90            f = open(fname, 'r')
91        except(IOError):
92            sys.stderr.write("Error: Can't find save game file\n")
93            return
94        self.game_state = pickle.load(f)
95        f.close()
96        if self.game_state.currentMap:
97            self.loadMap(self.game_state.currentMapName, \
98                         self.game_state.currentMap) 
99
100    def createObject (self, layer, attributes, instance):
101        """Create an object and add it to the current map.
102           @type layer: fife.Layer
103           @param layer: FIFE layer object exists in
104           @type attributes: Dictionary
105           @param attributes: Dictionary of all object attributes
106           @type instance: fife.Instance
107           @param instance: FIFE instance corresponding to the object
108           @return: None
109        """
110        # create the extra data
111        extra = {}
112        extra['agent_layer'] = layer
113        extra['engine'] = self
114       
115        obj = createObject(attributes, extra)
116       
117        if obj.trueAttr("PC"):
118            self.addPC(layer, obj, instance)
119        else:
120            self.addObject(layer, obj, instance)
121
122       
123
124    def addPC(self, layer, pc, instance):
125        """Add the PC to the map
126           @type layer: fife.Layer
127           @param layer: FIFE layer object exists in
128           @type pc: PlayerCharacter
129           @param pc: PlayerCharacter object
130           @type instance: fife.Instance
131           @param instance: FIFE instance of PC
132           @return: None
133        """
134        # add to view data
135        self.view.activeMap.addObject(pc.ID, instance)         
136       
137        # sync with game data
138        if self.game_state.PC is None:
139            self.game_state.PC = pc
140           
141        self.game_state.PC.setup()
142
143
144    def addObject(self, layer, obj, instance):
145        """Adds an object to the map.
146           @type layer: fife.Layer
147           @param layer: FIFE layer object exists in
148           @type obj: GameObject
149           @param obj: corresponding object class
150           @type instance: fife.Instance
151           @param instance: FIFE instance of object
152           @return: Nothing
153        """
154       
155        ref = self.game_state.getObjectById(obj.ID) 
156        if ref is None:
157            # no, add it to the game state
158            obj.map_id = self.game_state.currentMap
159            self.game_state.objects[obj.ID] = obj
160        else:
161            # yes, use the current game state data
162            obj.X = ref.X
163            obj.Y = ref.Y
164            obj.gfx = ref.gfx 
165           
166        # add it to the view
167        self.view.activeMap.addObject(obj.ID, instance)         
168
169        if obj.trueAttr("NPC"):
170            # create the agent
171            obj.setup()
172           
173            # create the PC agent
174            obj.start()
175
176    def objectActive(self, ident):
177        """Given the objects ID, pass back the object if it is active,
178           False if it doesn't exist or not displayed
179           @type ident: string
180           @param ident: ID of object
181           @rtype: boolean
182           @return: Status of result (True/False)"""
183        for i in self.game_state.getObjectsFromMap(self.game_state.currentMap):
184            if (i.ID == ident):
185                # we found a match
186                return i
187        # no match
188        return False
189
190    def getItemActions(self, obj_id):
191        """Given the objects ID, return the text strings and callbacks.
192           @type obj_id: string
193           @param obj_id: ID of object
194           @rtype: list
195           @return: List of text and callbacks"""
196        actions=[]
197        # note: ALWAYS check NPC's first!
198        obj = self.game_state.getObjectById(obj_id)
199       
200        if obj is not None:
201            if obj.trueAttr("NPC"):
202                # keep it simple for now, None to be replaced by callbacks
203                actions.append(["Talk", "Talk", self.initTalk, obj])
204                actions.append(["Attack", "Attack", self.nullFunc, obj])
205            else:
206                actions.append(["Examine", "Examine", \
207                                self.game_state.PC.approach, [obj.X, obj.Y], \
208                                ExamineBoxAction(self, obj.name, obj.text)])
209                # is it a Door?
210                if obj.trueAttr("door"):
211                    actions.append(["Change Map", "Change Map", \
212                       self.game_state.PC.approach, [obj.X, obj.Y], \
213                            ChangeMapAction(self, obj.target_map_name, \
214                                obj.target_map, obj.target_pos)])
215                # is it a container?
216                if obj.trueAttr("container"):
217                    actions.append(["Open", "Open", 
218                                    self.game_state.PC.approach, \
219                                    [obj.X, obj.Y], \
220                                    OpenBoxAction(self, "Box")])
221                # can you pick it up?
222                if obj.trueAttr("carryable"):
223                    actions.append(["Pick Up", "Pick Up", self.nullFunc, obj])
224
225        return actions
226   
227    def nullFunc(self, userdata):
228        """Sample callback for the context menus."""
229        print userdata
230   
231    def initTalk(self, npcInfo):
232        """ Starts the PC talking to an NPC. """
233        # TODO: work more on this when we get NPCData and HeroData straightened
234        # out
235        npc = self.game_state.getObjectById(npcInfo.ID)
236        self.game_state.PC.approach([npc.getLocation().\
237                                     getLayerCoordinates().x, \
238                                     npc.getLocation().\
239                                     getLayerCoordinates().y], \
240                                     TalkAction(self, npc))
241
242    def loadMap(self, map_name, map_file):
243        """THIS FUNCTION IS BROKEN. DO NOT USE IT YET
244           Load a new map.
245           @type map_name: string
246           @param map_name: Name of the map to load
247           @type map_file: string
248           @param map_file: Filename of map file to load
249           @return: None"""
250        self.game_state.currentMap = map_file
251        self.game_state.currentMapName= map_name
252        self.view.loadMap(map_name, str(map_file))
253        self.view.setActiveMap(map_name)
254
255        self.reset()
256
257        # create the PC agent
258        self.view.activeMap.addPC(self.game_state.PC.behaviour.agent)
259        self.game_state.PC.start()
260
261
262    def handleMouseClick(self,position):
263        """Code called when user left clicks the screen.
264           @type position: fife.ScreenPoint
265           @param position: Screen position of click
266           @return: None"""
267        if(self.pc_run == 1):
268            self.game_state.PC.run(position)
269        else:
270            self.game_state.PC.walk(position)
271
272    def changeMap(self, mapName, mapFile, target_position):
273        """Registers for a map change on the next pump().
274           @type nameName: String
275           @param mapName: Id of the map to teleport to
276           @type mapFile: String
277           @param mapFile: Filename of the map to teleport to
278           @type target_position: Tuple
279           @param target_position: Position of PC on target map.
280           @return None"""
281        # set the parameters for the map change if moving to a new map
282        print self.game_state.currentMapName
283        if mapName != self.game_state.currentMapName:
284            self.game_state.currentMapName = mapName
285            self.game_state.currentMap = mapFile
286            self.target_position = target_position
287            # issue the map change
288            self.map_change = True
289        else:
290            #set the player position on the current map
291            self.view.teleport(target_position)
292
293    def handleCommands(self):
294        if self.map_change:
295            self.loadMap(self.game_state.currentMapName, \
296                         self.game_state.currentMap)
297            self.view.teleport(self.target_position)
298            self.map_change = False
299
300    def pump(self):
301        """Main loop in the engine."""
302        self.handleCommands()
Note: See TracBrowser for help on using the repository browser.