Ticket #66: teleport_player.patch

File teleport_player.patch, 19.5 KB (added by saritor, 10 years ago)

This patch puts door objects into the game and implements code to use context menus to initiate a teleport of a player within the currently loaded map.

  • local_loaders/xmlmap.py

     
    299299                inst_dict["locked"] = instance.get('locked') 
    300300                inst_dict["name"] = instance.get('name') 
    301301                inst_dict["text"] = instance.get('text') 
     302                inst_dict["target_map_name"] = instance.get('target_map_name') 
     303                inst_dict["target_map"] = instance.get('target_map') 
     304                inst_dict["target_pos"] = (instance.get('target_x'), instance.get('target_y')) 
    302305                self.data.createObject( layer, inst_dict, inst ) 
    303306                 
    304307    def parseCameras(self, map_elt, map): 
  • maps/map.xml

     
    2121        <import file="../objects/ground/block/block.xml"></import> 
    2222        <import file="../objects/objects/crate/crate.xml"></import> 
    2323        <import file="../objects/ground/misc/test.xml"></import> 
    24          
     24 
    2525        <!-- Import the test buildings (and their doors) --> 
    2626        <import file="../objects/buildings/shanty/shantya.xml"></import> 
    2727        <import file="../objects/buildings/shanty/shantyb.xml"></import> 
     
    3434        <import file="../objects/buildings/shanty/shantyi.xml"></import> 
    3535        <import file="../objects/buildings/shanty/shanty-shadow.xml"></import> 
    3636        <import file="../objects/buildings/shanty/shanty-door.xml"></import> 
    37          
     37 
    3838        <import file="../objects/buildings/windmill/windmilla.xml"></import> 
    3939        <import file="../objects/buildings/windmill/windmillb.xml"></import> 
    4040        <import file="../objects/buildings/windmill/windmillc.xml"></import> 
     
    947947                        <i x="10.0" o="brick" z="0.0" y="-7.0" r="0"></i> 
    948948                        <i x="11.0" o="brick" z="0.0" y="-7.0" r="0"></i> 
    949949                        <i x="12.0" o="brick" z="0.0" y="-7.0" r="0"></i> 
    950          
     950 
    951951                        <i x="-6.0" o="snow02" z="0.0" y="-13.0" r="0"></i> 
    952952                        <i x="-5.0" o="snow02" z="0.0" y="-13.0" r="0"></i> 
    953953                        <i x="-4.0" o="snow02" z="0.0" y="-13.0" r="0"></i> 
     
    965965                        <i x="-5.0" o="gravel" z="0.0" y="-11.0" r="0"></i> 
    966966                        <i x="-4.0" o="gravel" z="0.0" y="-11.0" r="0"></i> 
    967967                        <i x="-3.0" o="gravel" z="0.0" y="-11.0" r="0"></i> 
    968                          
     968 
    969969                        <i x="-2.0" o="snow02" z="0.0" y="-11.0" r="0"></i> 
    970970                        <i x="-1.0" o="snow02" z="0.0" y="-11.0" r="0"></i> 
    971971                        <i x="-4.0" o="brick" z="0.0" y="3.0" r="0"></i> 
     
    19481948            <i x="1" o="block" z="0.0" y="3" r="0"></i> 
    19491949            <i x="1" o="block" z="0.0" y="4" r="0"></i>             
    19501950            <i x="1" o="block" z="0.0" y="5" r="0"></i> 
    1951              
     1951 
    19521952            <!-- more block tiles --> 
    19531953            <i x="7" o="block" z="0.0" y="-4" r="0"></i> 
    19541954            <i x="7" o="block" z="0.0" y="-3" r="0"></i> 
    19551955            <i x="8" o="block" z="0.0" y="-4" r="0"></i> 
    19561956            <i x="8" o="block" z="0.0" y="-3" r="0"></i> 
    1957              
     1957 
    19581958            <!-- There must be one and one only PC character --> 
    19591959                        <i x="0.0" o="PC" z="0.0" y="0.0" r="0" id="PC" object_type="PlayerCharacter"></i> 
    1960              
     1960 
    19611961            <!-- There can be any number of NPC characters --> 
    19621962            <i x="-4.0" o="npc_woman" z="0.0" y="-7.0" r="0" id="woman01" object_type="NonPlayerCharacter" 
    19631963                                text="A friendly woman"></i> 
    1964              
    1965              
     1964 
     1965 
    19661966                        <i x="-3.0" o="crate" z="0.0" y="-4.0" r="0" id="crate01" object_type="WoodenCrate" is_open="False" locked="False" name="asdf" 
    19671967                text="A crate that is covered in grime and dirt. There doesn't seem to be anything remarkable about it"></i> 
    1968   
     1968 
    19691969                        <!-- There can be any number of objects --> 
    19701970                        <!-- Object blocking is set in the objects own xml file --> 
    19711971                        <i x="-4.0" o="crate" z="0.0" y="-6.0" r="0" id="crate02" object_type="WoodenCrate" 
    19721972                is_open="False" locked="False" name="A dirty old crate" 
    19731973                        text="A crate that is covered in grime and dirt. There doesn't seem to be anything remarkable about it"></i> 
    1974              
     1974 
     1975                        <!-- A sample door --> 
     1976                        <i x="-2.0" o="shanty-door" z="0.0" y="6.0" r="0" id="shanty-door01" object_type="ShantyDoor" is_open="False" 
     1977                                name="Shanty Door" text="Looks like the entrance to the building." target_map_name="my-map" target_map="maps/map.xml" 
     1978                                target_x="10.0" target_y="10.0"></i> 
     1979 
    19751980                </instances> 
    19761981        </layer> 
    19771982 
    19781983        <camera ref_cell_width="72" zoom="1.0" tilt="-60.0" id="main" ref_layer_id="ObjectLayer" ref_cell_height="38" rotation="45.0"> 
    19791984        </camera> 
    19801985</map> 
    1981  
  • run.py

     
    100100        self.world.data = self.model 
    101101        self.listener = ApplicationListener(self.engine,self.world,self.model) 
    102102        self.world.quitFunction = self.listener.quitGame 
    103         self.model.loadMap("main_map", str(TDS.readSetting("MapFile")))    
     103        self.model.loadMap("my-map", str(TDS.readSetting("MapFile"))) 
    104104        pychan.init(self.engine, debug = True) 
    105105 
    106106    def loadSettings(self): 
  • scripts/engine.py

     
    2222from objectLoader import ObjectXMLParser 
    2323from objects.action import * 
    2424 
    25 # design note: 
    26 # there is a map file that FIFE reads. We use that file for half the map 
    27 # format because the map editor in FIFE uses it, and secondly because it 
    28 # save us writing a bunch of new code. 
    29 # However, the objects and characters on a map are liable to change 
    30 # whilst the game is being run, so when we change the map, we need to 
    31 # to grab the objects and npc data EITHER from the engine state, or grab 
    32 # from another file if in their initial state 
    33 # This other file has the name AAA_objects.xml where AAA.xml is the name 
    34 # of the original mapfile. 
    3525 
    3626class Engine: 
    3727    """Engine holds the logic for the game. 
     
    5040        self.mapchange = False 
    5141        self.gameState = GameState() 
    5242        self.pc_run = 1 
     43        self.targetmapid = None 
    5344 
    5445    def reset(self): 
    5546        """Clears the data on a map reload so we don't have objects/npcs from 
     
    10495 
    10596    def createObject (self, layer, attributes, instance): 
    10697        """Create an object and add it to the current map. 
    107             Inputs: 
    108                 layer = FIFE layer object exists in 
    109                 attributes = dictionary of all object attributes 
    110                 instance = FIFE instance corresponding to the object 
    111             Return: 
    112                 Nothing 
     98           @type layer: fife.Layer 
     99           @param layer: FIFE layer object exists in 
     100           @type attributes: Dictionary 
     101           @param attributes: Dictionary of all object attributes 
     102           @type instance: fife.Instance 
     103           @param instance: FIFE instance corresponding to the object 
     104           @return: None 
    113105        """ 
    114106        # create the extra data 
    115107        extra = {} 
     
    127119 
    128120    def addPC(self, layer, pc, instance): 
    129121        """Add the PC to the map 
    130             Inputs: 
    131                 layer = FIFE layer object exists in 
    132                 pc = PlayerCharacter object 
    133                 instance = FIFE instance of PC 
    134             Returns: 
    135                 Nothing 
     122           @type layer: fife.Layer 
     123           @param layer: FIFE layer object exists in 
     124           @type pc: PlayerCharacter 
     125           @param pc: PlayerCharacter object 
     126           @type instance: fife.Instance 
     127           @param instance: FIFE instance of PC 
     128           @return: None 
    136129        """ 
    137130        # add to view data  
    138131        self.view.activeMap.addObject(pc.ID, instance)           
     
    146139 
    147140    def addObject(self, layer, obj, instance): 
    148141        """Adds an object to the map. 
    149             Inputs: 
    150                 layer = FIFE layer object exists in 
    151                 obj = corresponding object class 
    152                 instance = FIFE instance of object 
    153             Returns: 
    154                 Nothing 
     142           @type layer: fife.Layer 
     143           @param layer: FIFE layer object exists in 
     144           @type obj: GameObject 
     145           @param obj: corresponding object class 
     146           @type instance: fife.Instance 
     147           @param instance: FIFE instance of object 
     148           @return: Nothing 
    155149        """ 
    156150         
    157151        ref = self.gameState.getObjectById(obj.ID)  
     
    167161             
    168162        # add it to the view 
    169163        self.view.activeMap.addObject(obj.ID, instance)           
    170         
     164 
    171165        if obj.trueAttr("NPC"): 
    172166            # create the agent 
    173167            obj.setup() 
     
    175169            # create the PC agent 
    176170            obj.start() 
    177171 
    178     def addDoors(self, doors): 
    179         """Add all the doors to the map as well. 
    180            As an object they will have already been added. 
    181            @type doors: list 
    182            @param doors: List of doors 
    183            @return: None""" 
    184         for i in doors: 
    185             self.doors[str(i.id)] = MapDoor(i.id, i.destmap, (i.destx, i.desty)) 
    186  
    187172    def objectActive(self, ident): 
    188173        """Given the objects ID, pass back the object if it is active, 
    189174           False if it doesn't exist or not displayed 
     
    194179        for i in self.gameState.getObjectsFromMap(self.gameState.currentMap): 
    195180            if (i.ID == ident): 
    196181                # we found a match 
    197                 return i          
     182                return i 
    198183        # no match 
    199184        return False 
    200185 
     
    212197            if obj.trueAttr("NPC"): 
    213198                # keep it simple for now, None to be replaced by callbacks 
    214199                actions.append(["Talk", "Talk", self.initTalk, obj]) 
    215                 actions.append(["Attack", "Attack", self.nullFunc, obj])  
    216             elif obj.trueAttr("Door"): 
    217                 actions.append(["Change Map", "Change Map", \ 
    218                        self.gameState.PC.approach, [obj.X, obj.Y], \ 
    219                         ChangeMapAction(self, self.doors[str(i.ID)].map, [i.destx, i.desty])]) 
    220                 pass 
     200                actions.append(["Attack", "Attack", self.nullFunc, obj]) 
    221201            else: 
    222                 actions.append(["Examine", "Examine", self.gameState.PC.approach,   
     202                actions.append(["Examine", "Examine", self.gameState.PC.approach, \ 
    223203                                [obj.X, obj.Y], ExamineBoxAction(self, obj.name, obj.text)]) 
     204                # is it a Door? 
     205                if obj.trueAttr("door"): 
     206                    actions.append(["Change Map", "Change Map", \ 
     207                       self.gameState.PC.approach, [obj.X, obj.Y], \ 
     208                            ChangeMapAction(self, obj.target_map_name, \ 
     209                                obj.target_pos)]) 
    224210                # is it a container? 
    225211                if obj.trueAttr("container"): 
    226212                    actions.append(["Open", "Open", self.gameState.PC.approach, [obj.X, obj.Y], OpenBoxAction(self, "Box")]) 
    227213                # can you pick it up? 
    228214                if obj.trueAttr("carryable"): 
    229                     actions.append(["Pick Up", "Pick Up", self.nullFunc, obj])        
    230                      
     215                    actions.append(["Pick Up", "Pick Up", self.nullFunc, obj]) 
     216 
    231217        return actions 
    232218     
    233219    def nullFunc(self, userdata): 
     
    242228        self.gameState.PC.approach([npc.getLocation().getLayerCoordinates().x, npc.getLocation().getLayerCoordinates().y], TalkAction(self, npc)) 
    243229 
    244230    def loadMap(self, map_name, map_file): 
    245         """Load a new map. TODO: needs some error checking 
     231        """THIS FUNCTION IS BROKEN. DO NOT USE IT YET 
     232           Load a new map. 
    246233           @type map_name: string 
    247234           @param map_name: Name of the map to load 
    248235           @type map_file: string 
     
    253240        self.view.loadMap(map_name, str(map_file)) 
    254241        self.view.setActiveMap(map_name) 
    255242 
    256         self.reset()         
    257          
     243        self.reset() 
     244 
    258245        # create the PC agent 
    259246        self.view.activeMap.addPC(self.gameState.PC.behaviour.agent) 
    260247        self.gameState.PC.start() 
     
    269256            self.gameState.PC.run(position) 
    270257        else: 
    271258            self.gameState.PC.walk(position) 
    272          
     259 
    273260    def changeMap(self, map, targetPosition): 
    274261        """Registers for a mapchange on the next pump(). 
    275            @type map: ??? 
    276            @param map: Name of the target map. 
    277            @type targetPosition: ??? 
     262           @type map: String 
     263           @param map: Target maps . 
     264           @type targetPosition: Tuple 
    278265           @param targetPosition: Position of PC on target map. 
    279266           @return: None""" 
    280         # save the postions 
    281         self.updateGameState() 
    282         # set the PC position 
    283         self.gameState.PC.posx = targetPosition[0] 
    284         self.gameState.PC.posy = targetPosition[1] 
    285         # set the parameters for the mapchange 
    286         self.targetMap = map 
    287         # issue the mapchange 
    288         self.mapchange = True 
     267        # set the parameters for the mapchange if moving to a new map 
     268        if map != self.gameState.currentMap: 
     269            print map 
     270            print self.gameState.currentMap 
     271            self.targetmapid = map 
     272            # issue the mapchange 
     273            self.mapchange = True 
     274        else: 
     275            #set the player position on the current map 
     276            self.view.teleport(targetPosition) 
    289277 
    290278    def handleCommands(self): 
    291279        if self.mapchange: 
    292             self.loadMap(self.targetMap) 
     280            self.loadMap(self.targetmapid, self.gameState.objects[self.targetmapid]) 
    293281            self.mapchange = False 
    294282 
    295283    def pump(self): 
    296284        """Main loop in the engine.""" 
    297285        self.handleCommands() 
    298  
  • scripts/objects/__init__.py

     
    1414 
    1515#   You should have received a copy of the GNU General Public License 
    1616#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>. 
    17 import containers 
     17import containers, doors 
    1818import actors 
    1919import sys 
    2020 
    21 object_modules = [containers, actors,] 
     21object_modules = [containers, actors, doors] 
    2222 
    2323def getAllObjects (): 
    2424    """Returns a dictionary with the names of the concrete game object classes 
     
    4949        for key, val in extra.items(): 
    5050            info[key] = val 
    5151 
    52         return getAllObjects()[obj_type](ID, **info) 
    53  No newline at end of file 
     52        # this is for testing purposes 
     53        return getAllObjects()[obj_type](ID, **info) 
  • scripts/objects/action.py

     
    2424class ChangeMapAction(Action): 
    2525    """A change map scheduled""" 
    2626    def __init__(self, engine, targetmap, targetpos): 
    27         """@type engine: Engine reference 
     27        """Initiates a change of the position of the character 
     28           possibly flagging a new map to be loaded. 
     29           @type engine: Engine reference 
    2830           @param engine: A reference to the engine. 
    2931           @type targetmap: String 
    3032           @param targetmap: Target mapname. 
     
    3436        self.engine = engine 
    3537        self.targetpos = targetpos 
    3638        self.targetmap = targetmap 
    37         
     39 
    3840    def execute(self): 
    3941        """Executes the mapchange.""" 
    4042        self.engine.changeMap(self.targetmap, self.targetpos) 
  • scripts/objects/actors.py

     
    135135           @return: None""" 
    136136        self.state = _AGENT_STATE_RUN 
    137137        self.behaviour.agent.move('walk', location, self.behaviour.speed-1) 
    138        
     138 
     139    def teleport(self, location): 
     140        """Teleports a PC instantly to the given location. 
     141           @type location: fife.Location 
     142           @param location: Target coordinates for PC. 
     143           @return: None""" 
     144        self.state = _AGENT_STATE_IDLE 
     145        self.behaviour.agent.setLocation(location) 
     146 
    139147    def approach(self, location, action = None): 
    140148        """Approaches an npc and then ???. 
    141149           @type loc: fife.Location 
  • scripts/objects/composed.py

     
    3030        Trappable    .__init__(self, **kwargs) 
    3131        Destructable .__init__(self, **kwargs) 
    3232        self.blocking = True 
     33 
     34class Door(GameObject, Lockable, Scriptable, Trappable): 
     35    """Composite class that can be used to create doors on a map.""" 
     36    def __init__ (self, target_map_name = 'my-map', target_map = 'map/map.xml', target_pos = (0.0, 0.0), \ 
     37                        **kwargs): 
     38        GameObject   .__init__(self, **kwargs) 
     39        Lockable     .__init__(self, **kwargs) 
     40        Scriptable   .__init__(self, **kwargs) 
     41        Trappable    .__init__(self, **kwargs) 
     42        self.is_door = True 
     43        self.target_map_name = target_map_name 
     44        self.target_map = target_map 
     45        self.target_pos = target_pos 
     46        self.blocking = True 
     47 No newline at end of file 
  • scripts/objects/doors.py

     
     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"""Containes classes defining concrete door game objects.""" 
     19 
     20__all__ = ["ShantyDoor",] 
     21 
     22from composed import Door 
     23 
     24class ShantyDoor(Door): 
     25    def __init__ (self, ID, name = 'Shanty Door', \ 
     26            text = 'A door', gfx = 'shanty-door', target_map_name = 'my-map', \ 
     27            target_map = 'map.xml', target_pos = (0.0, 0.0), \ 
     28            **kwargs): 
     29        Door.__init__(self, ID = ID, name = name, text = text, gfx = gfx, \ 
     30            target_map_name = 'my-map', target_map = target_map, \ 
     31            target_pos = target_pos, **kwargs) 
  • scripts/world.py

     
    210210        self.hud.hideContainer() 
    211211        self.data.gameState.PC.run(click) 
    212212 
     213    def teleport(self, position): 
     214        """Called when a door is used that moves a player to a new 
     215           location on the same map. the setting of position may want 
     216           to be created as its own method down the road. 
     217            
     218           @type position: String Tuple 
     219           @param position: X,Y coordinates passed from enigine.changeMap 
     220           @return: fife.Location 
     221        """ 
     222        coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0) 
     223        location = fife.Location(self.activeMap.agent_layer) 
     224        location.setMapCoordinates(coord) 
     225        self.data.gameState.PC.teleport(location) 
     226 
    213227    def mouseMoved(self, evt): 
    214228        """Called when the mouse is moved 
    215229           @type evt: fife.event