Ignore:
Timestamp:
06/19/10 22:35:21 (9 years ago)
Author:
beliar
Message:

This concludes the cleanup and refactoring for now. I hope the changes will make it easier to add functionality to the game.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/code-cleanup-and-refactoring/game/scripts/gamemodel.py

    r550 r552  
    2121from gamestate import GameState 
    2222from objects import createObject 
    23 from objects.action import ChangeMapAction, ExamineBoxAction, OpenBoxAction, \ 
    24                             UnlockBoxAction, LockBoxAction, TalkAction 
     23from map import Map 
     24from fife import fife 
     25 
    2526import yaml 
    2627 
     
    3132       the fife view here. This also prevents us from just having a 
    3233       function heavy controller.""" 
    33     def __init__(self, view): 
     34    def __init__(self, engine): 
    3435        """Initialize the instance. 
    35            @type view: world 
    36            @param view: A world instance 
    37            @return: None""" 
     36        @param engine: A fife.Engine object 
     37        @type emgome: fife.Engine  
     38        @return: None""" 
    3839        # a World object (the fife stuff, essentially) 
    39         self.view = view 
    4040        self.map_change = False 
    4141        self.load_saver = False 
     
    4747        self.target_map_file = None 
    4848        self.object_db = {} 
    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, 'wb') 
    58         except(IOError): 
    59             sys.stderr.write("Error: Can't find save game: " + fname + "\n") 
    60             return 
    61          
    62         # save the PC coordinates 
    63         coords = self.game_state.PC.behaviour.agent.getLocation().\ 
    64                     getMapCoordinates() 
    65         self.game_state.saved_pc_coordinates = (coords.x, coords.y) 
    66          
    67         # Pickle it  
    68         pickle.dump(self.game_state, f) 
    69         f.close()        
    70  
    71     def load(self, path, filename): 
    72         """Loads a saver from a file. 
    73            @type filename: string 
    74            @param filename: the name of the file (including path) to load from 
    75            @return: None""" 
    76         fname = '/'.join([path, filename]) 
    77  
    78         try: 
    79             f = open(fname, 'rb') 
    80         except(IOError): 
    81             sys.stderr.write("Error: Can't find save game file\n") 
    82             return 
    83          
    84         # Remove all currently loaded maps so we can start fresh 
    85         self.view.deleteMaps() 
    86          
    87         self.game_state = pickle.load(f) 
    88         f.close() 
    89  
    90         self.target_position = self.game_state.saved_pc_coordinates 
    91  
    92         # Load the current map 
    93         if self.game_state.current_map_file: 
    94             self.loadMap(self.game_state.current_map_name, \ 
    95                          self.game_state.current_map_file)          
    96  
    97         # Recreate all the behaviours. These can't be saved because FIFE 
    98         # objects cannot be pickled 
    99          
    100         for map_id in self.game_state.objects: 
    101             for obj in self.game_state.objects[map_id].itervalues(): 
    102                 if obj.trueAttr("NPC") or obj.trueAttr("AnimatedContainer"): 
    103                     obj.createBehaviour(self.view.active_map.agent_layer) 
    104                     obj.setup() 
    105        
    106         # In most maps we'll create the PC Instance internally. In these 
    107         # cases we need a target position 
    108          
     49        # self.map is a Map object, set to none here 
     50        self.active_map = None 
     51        self.maps = {} 
     52        self.engine = engine         
    10953 
    11054    def checkAttributes(self, attributes): 
     
    15195        container.placeItem(obj) 
    15296         
     97    def save(self, path, filename): 
     98        """Writes the saver to a file. 
     99           @type filename: string 
     100           @param filename: the name of the file to write to 
     101           @return: None""" 
     102        fname = '/'.join([path, filename]) 
     103        try: 
     104            save_file = open(fname, 'wb') 
     105        except(IOError): 
     106            sys.stderr.write("Error: Can't find save game: " + fname + "\n") 
     107            return 
     108         
     109        # save the PC coordinates 
     110        coords = self.game_state.PlayerCharacter.behaviour.agent.getLocation().\ 
     111                    getMapCoordinates() 
     112        self.game_state.saved_pc_coordinates = (coords.x, coords.y) 
     113         
     114        # Pickle it  
     115        pickle.dump(self.game_state, save_file) 
     116        save_file.close()        
     117 
     118    def load(self, path, filename): 
     119        """Loads a saver from a file. 
     120           @type filename: string 
     121           @param filename: the name of the file (including path) to load from 
     122           @return: None""" 
     123        fname = '/'.join([path, filename]) 
     124 
     125        try: 
     126            load_file = open(fname, 'rb') 
     127        except(IOError): 
     128            sys.stderr.write("Error: Can't find save game file\n") 
     129            return         
     130         
     131        self.game_state = pickle.load(load_file) 
     132        load_file.close() 
     133 
     134        self.target_position = self.game_state.saved_pc_coordinates 
     135 
     136        # Load the current map 
     137        if self.game_state.current_map_file: 
     138            self.loadMap(self.game_state.current_map_name, \ 
     139                         self.game_state.current_map_file)          
     140 
     141        # Recreate all the behaviours. These can't be saved because FIFE 
     142        # objects cannot be pickled 
     143         
     144        for map_id in self.game_state.objects: 
     145            for obj in self.game_state.objects[map_id].itervalues(): 
     146                if obj.trueAttr("NPC") or obj.trueAttr("AnimatedContainer"): 
     147                    obj.createBehaviour(self.active_map.agent_layer) 
     148                    obj.setup() 
     149       
     150        # In most maps we'll create the PlayerCharacter Instance internally.  
     151        # In these cases we need a target position 
     152          
     153    def teleport(self, position): 
     154        """Called when a door is used that moves a player to a new 
     155           location on the same map. the setting of position may want 
     156           to be created as its own method down the road. 
     157           @type position: String Tuple 
     158           @param position: X,Y coordinates passed from engine.changeMap 
     159           @return: fife.Location""" 
     160        print position 
     161        coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0) 
     162        location = fife.Location(self.active_map.agent_layer) 
     163        location.setMapCoordinates(coord) 
     164        self.game_state.PlayerCharacter.teleport(location) 
     165                 
     166    def getObjectAtCoords(self, coords): 
     167        """Get the object which is at the given coords 
     168            @type coords: fife.Screenpoint 
     169            @param coords: Coordinates where to check for an object 
     170            @rtype: fife.Object 
     171            @return: An object or None""" 
     172        instances = self.active_map.cameras[ 
     173                                            self.active_map.my_cam_id].\ 
     174            getMatchingInstances(coords, self.active_map.agent_layer) 
     175        # no object returns an empty tuple 
     176        if(instances != ()): 
     177            front_y = 0 
     178             
     179 
     180            for obj in instances: 
     181                # check to see if this in our list at all 
     182                if(self.objectActive(obj.getId())): 
     183                    # check if the object is on the foreground 
     184                    obj_map_coords = \ 
     185                                      obj.getLocation().getMapCoordinates() 
     186                    obj_screen_coords = self.active_map.\ 
     187                        cameras[self.active_map.my_cam_id]\ 
     188                        .toScreenCoordinates(obj_map_coords) 
     189 
     190                    if obj_screen_coords.y > front_y: 
     191                        #Object on the foreground 
     192                        front_y = obj_screen_coords.y 
     193                        return obj 
     194                    else: 
     195                        return None 
     196        else: 
     197            return None 
     198 
     199    def getCoords(self, click): 
     200        """Get the map location x, y coordinates from the screen coordinates 
     201           @type click: fife.ScreenPoint 
     202           @param click: Screen coordinates 
     203           @rtype: fife.Location 
     204           @return: The map coordinates""" 
     205        coord = self.active_map.cameras[self.active_map.my_cam_id].\ 
     206                    toMapCoordinates(click, False) 
     207        coord.z = 0 
     208        location = fife.Location(self.active_map.agent_layer) 
     209        location.setMapCoordinates(coord) 
     210        return location 
     211 
     212    def togglePause(self): 
     213        """ Pause/Unpause the game. 
     214            @return: nothing""" 
     215        self.active_map.togglePause() 
     216     
     217    def loadMap(self, map_name, map_file): 
     218        """Load a new map. 
     219           @type map_name: string 
     220           @param map_name: Name of the map to load 
     221           @type map_file: string 
     222           @param map_file: Filename of map file to load 
     223           @return: None""" 
     224        self.game_state.current_map_file = map_file 
     225        self.game_state.current_map_name = map_name 
     226 
     227        if not map_name in self.maps:            
     228            new_map = Map(self.engine, self) 
     229            self.maps[map_name] = new_map 
     230            new_map.load(map_file) 
     231        else: 
     232            self.setActiveMap(map_name) 
     233 
     234        # create the PlayerCharacter agent 
     235        self.active_map.addPC() 
     236        self.game_state.PlayerCharacter.start() 
     237 
     238    def changeMap(self, map_name, map_file, target_position): 
     239        """Registers for a map change on the next pump(). 
     240           @type map_name: String 
     241           @param map_name: Id of the map to teleport to 
     242           @type map_file: String 
     243           @param map_file: Filename of the map to teleport to 
     244           @type target_position: Tuple 
     245           @param target_position: Position of PlayerCharacter on target map. 
     246           @return None""" 
     247        # set the parameters for the map change if moving to a new map 
     248        if map_name != self.game_state.current_map_name: 
     249            self.target_map_name = map_name 
     250            self.target_map_file = map_file 
     251            self.target_position = target_position 
     252            # issue the map change 
     253            self.map_change = True 
     254        else: 
     255            #set the player position on the current map 
     256            self.teleport(target_position) 
     257 
     258    def deleteMaps(self): 
     259        """Clear all currently loaded maps from FIFE as well as clear our 
     260            local map cache 
     261            @return: nothing""" 
     262        self.engine.getModel().deleteMaps() 
     263        self.engine.getModel().deleteObjects() 
     264        self.maps = {} 
     265         
     266    def setActiveMap(self, map_name): 
     267        """Sets the active map that is to be rendered. 
     268           @type map_name: String 
     269           @param map_name: The name of the map to load 
     270           @return: None""" 
     271        # Turn off the camera on the old map before we turn on the camera 
     272        # on the new map. 
     273        self.active_map.cameras[self.active_map.my_cam_id].setEnabled(False) 
     274        # Make the new map active. 
     275        self.active_map = self.maps[map_name] 
     276        self.active_map.makeActive() 
     277 
    153278    def createMapObject (self, layer, attributes, instance): 
    154279        """Create an object and add it to the current map. 
     
    174299            self.addObject(layer, obj, instance)  
    175300 
    176     def addPC(self, layer, pc, instance): 
    177         """Add the PC to the map 
     301    def addPC(self, layer, player_char, instance): 
     302        """Add the PlayerCharacter to the map 
    178303           @type layer: fife.Layer 
    179304           @param layer: FIFE layer object exists in 
    180            @type pc: PlayerCharacter 
    181            @param pc: PlayerCharacter object 
     305           @type player_char: PlayerCharacter 
     306           @param player_char: PlayerCharacter object 
    182307           @type instance: fife.Instance 
    183            @param instance: FIFE instance of PC 
    184            @return: None""" 
    185         # For now we copy the PC, in the future we will need to copy 
    186         # PC specifics between the different PC's 
    187         self.game_state.PC = pc 
    188         self.game_state.PC.setup() 
    189          
    190         # The PC has an inventory, and also some filling of the ready slots  
    191         # in the HUD. At this point we sync the contents of the ready slots  
    192         # with the contents of the inventory. 
    193         self.view.hud.initializeInventory() 
     308           @param instance: FIFE instance of PlayerCharacter 
     309           @return: None""" 
     310        # For now we copy the PlayerCharacter,  
     311        # in the future we will need to copy 
     312        # PlayerCharacter specifics between the different PlayerCharacter's 
     313        self.game_state.PlayerCharacter = player_char 
     314        self.game_state.PlayerCharacter.setup()         
    194315 
    195316    def addObject(self, layer, obj, instance): 
     
    217338            # create the agent 
    218339            obj.setup() 
    219             # create the PC agent 
     340            # create the PlayerCharacter agent 
    220341            obj.start() 
    221342        if obj.trueAttr("AnimatedContainer"): 
     
    236357                return i 
    237358        # no match 
    238         return False 
    239  
    240     def getItemActions(self, obj_id): 
    241         """Given the objects ID, return the text strings and callbacks. 
    242            @type obj_id: string 
    243            @param obj_id: ID of object 
    244            @rtype: list 
    245            @return: List of text and callbacks""" 
    246         actions = [] 
    247         # note: ALWAYS check NPC's first! 
    248         obj = self.game_state.getObjectById(obj_id, \ 
    249                                             self.game_state.current_map_name) 
    250          
    251         if obj is not None: 
    252             if obj.trueAttr("NPC"): 
    253                 # keep it simple for now, None to be replaced by callbacks 
    254                 actions.append(["Talk", "Talk", self.initTalk, obj]) 
    255                 actions.append(["Attack", "Attack", self.nullFunc, obj]) 
    256             else: 
    257                 actions.append(["Examine", "Examine", \ 
    258                                 self.game_state.PC.approach, [obj.X, obj.Y], \ 
    259                                 ExamineBoxAction(self, obj.name, obj.text)]) 
    260                 # is it a Door? 
    261                 if obj.trueAttr("door"): 
    262                     actions.append(["Change Map", "Change Map", \ 
    263                        self.game_state.PC.approach, [obj.X, obj.Y], \ 
    264                             ChangeMapAction(self, obj.target_map_name, \ 
    265                                 obj.target_map, obj.target_pos)]) 
    266                 # is it a container? 
    267                 if obj.trueAttr("container"): 
    268                     actions.append(["Open", "Open",  
    269                                     self.game_state.PC.approach, \ 
    270                                     [obj.X, obj.Y], \ 
    271                                     OpenBoxAction(self, obj)]) 
    272                     actions.append(["Unlock", "Unlock",  
    273                                     self.game_state.PC.approach, \ 
    274                                     [obj.X, obj.Y], \ 
    275                                     UnlockBoxAction(obj)]) 
    276                     actions.append(["Lock", "Lock",  
    277                                     self.game_state.PC.approach, \ 
    278                                     [obj.X, obj.Y], \ 
    279                                     LockBoxAction(obj)]) 
    280                 # can you pick it up? 
    281                 if obj.trueAttr("carryable"): 
    282                     actions.append(["Pick Up", "Pick Up", self.nullFunc, obj]) 
    283  
    284         return actions 
    285      
    286     def nullFunc(self, userdata): 
    287         """Sample callback for the context menus.""" 
    288         print userdata 
    289      
    290     def initTalk(self, npcInfo): 
    291         """ Starts the PC talking to an NPC. """ 
    292         # TODO: work more on this when we get NPCData and HeroData straightened 
    293         # out 
    294         npc = self.game_state.getObjectById(npcInfo.ID, \ 
    295                                             self.game_state.current_map_name) 
    296         self.game_state.PC.approach([npc.getLocation().\ 
    297                                      getLayerCoordinates().x, \ 
    298                                      npc.getLocation().\ 
    299                                      getLayerCoordinates().y], \ 
    300                                     TalkAction(self, npc)) 
    301  
    302     def loadMap(self, map_name, map_file): 
    303         """Load a new map. 
    304            @type map_name: string 
    305            @param map_name: Name of the map to load 
    306            @type map_file: string 
    307            @param map_file: Filename of map file to load 
    308            @return: None""" 
    309         self.game_state.current_map_file = map_file 
    310         self.game_state.current_map_name = map_name 
    311         self.view.loadMap(map_name, str(map_file)) 
    312  
    313         # create the PC agent 
    314         self.view.active_map.addPC() 
    315         self.game_state.PC.start() 
    316  
    317     def handleMouseClick(self, position): 
    318         """Code called when user left clicks the screen. 
     359        return False     
     360 
     361    def movePlayer(self, position): 
     362        """Code called when the player should move to another location 
    319363           @type position: fife.ScreenPoint 
    320            @param position: Screen position of click 
     364           @param position: Screen position to move to 
    321365           @return: None""" 
    322366        if(self.pc_run == 1): 
    323             self.game_state.PC.run(position) 
    324         else: 
    325             self.game_state.PC.walk(position) 
    326  
    327     def changeMap(self, map_name, map_file, target_position): 
    328         """Registers for a map change on the next pump(). 
    329            @type map_name: String 
    330            @param map_name: Id of the map to teleport to 
    331            @type map_file: String 
    332            @param map_file: Filename of the map to teleport to 
    333            @type target_position: Tuple 
    334            @param target_position: Position of PC on target map. 
    335            @return None""" 
    336         # set the parameters for the map change if moving to a new map 
    337         if map_name != self.game_state.current_map_name: 
    338             self.target_map_name = map_name 
    339             self.target_map_file = map_file 
    340             self.target_position = target_position 
    341             # issue the map change 
    342             self.map_change = True 
    343         else: 
    344             #set the player position on the current map 
    345             self.view.teleport(target_position) 
    346  
    347     def handleCommands(self): 
    348         if self.map_change: 
    349             self.loadMap(self.target_map_name, self.target_map_file) 
    350             self.view.teleport(self.target_position) 
    351             self.map_change = False 
    352          
    353         if self.load_saver: 
    354             self.load(self.savegame) 
    355             self.load_saver = False 
    356  
    357     def pump(self): 
    358         """Main loop in the engine.""" 
    359         self.handleCommands() 
    360          
     367            self.game_state.PlayerCharacter.run(position) 
     368        else: 
     369            self.game_state.PlayerCharacter.walk(position) 
     370         
     371    def teleportPlayer(self, position): 
     372        """Code called when the player should teleport to another location 
     373           @type position: fife.ScreenPoint 
     374           @param position: Screen position to teleport to 
     375           @return: None""" 
     376        self.game_state.PlayerCharacter.teleport(position) 
     377 
    361378    def readObjectDB(self, db_file): 
    362379        """Reads the Object Information Database from a file. 
Note: See TracChangeset for help on using the changeset viewer.