source: trunk/game/scripts/objects/actors.py @ 356

Revision 356, 10.2 KB checked in by Kaydeth_parpg, 10 years ago (diff)

Ticket #73. Patch by Kaydeth. Most of the changes were made to the map loading logic in the Engine, World, and Map classes to make sure it could handle loading maps after the game state has been restored by a load game. Also added a floating door back to both maps so map changing can still be tested in game. fixes[s:trac, t:73]

  • 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/>.
17import fife
18from scripts import world
19from base import *
20
21"""All actors go here. Concrete classes only."""
22
23__all__ = ["PlayerCharacter", "NonPlayerCharacter",]
24
25TDS = Setting()
26_AGENT_STATE_NONE, _AGENT_STATE_IDLE, _AGENT_STATE_APPROACH, _AGENT_STATE_RUN, _AGENT_STATE_WANDER, _AGENT_STATE_TALK = xrange(6)
27
28class ActorBehaviour (fife.InstanceActionListener):
29    """Fife agent listener
30    """
31    def __init__(self, layer):
32        fife.InstanceActionListener.__init__(self)
33        self.layer = layer
34   
35    def attachToLayer(self, agent_ID):
36        """ Attaches to a certain layer
37            @type agent_ID: String
38            @param agent_ID: ID of the layer to attach to.
39            @return: None
40        """
41        self.agent = self.layer.getInstance(agent_ID)
42        self.agent.addActionListener(self)
43        self.state = _AGENT_STATE_NONE
44        self.speed = float(TDS.readSetting("PCSpeed"))-1 # TODO: rework/improve
45       
46    def getX(self):
47        """Get the NPC's x position on the map.
48           @rtype: integer"
49           @return: the x coordinate of the NPC's location"""
50        return self.agent.getLocation().getLayerCoordinates().x
51
52    def getY(self):
53        """Get the NPC's y position on the map.
54           @rtype: integer
55           @return: the y coordinate of the NPC's location"""
56        return self.agent.getLocation().getLayerCoordinates().y
57       
58    def onInstanceActionFinished(self, instance, action):
59        pass
60
61   
62class PCBehaviour (ActorBehaviour):
63    def __init__(self, parent = None, layer = None):
64        super(PCBehaviour, self).__init__(layer)
65       
66        self.parent = parent
67        self.idle_counter = 1
68        self.speed = float(TDS.readSetting("PCSpeed")) # TODO: rework/improve
69        self.nextAction = None
70        self.agent = None
71       
72    def onInstanceActionFinished(self, instance, action):
73        """@type instance: ???
74           @param instance: ???
75           @type action: ???
76           @param action: ???
77           @return: None"""
78        if self.nextAction:
79            self.nextAction.execute()
80            self.nextAction = None
81            self.idle()
82        else:
83            self.idle()
84           
85        if(action.getId() != 'stand'):
86            self.idle_counter = 1
87        else:
88            self.idle_counter += 1
89           
90    def onNewMap(self, layer):
91        """Sets the agent onto the new layer.
92        """
93        if self.agent is not None:
94            self.agent.removeActionListener(self)
95           
96        self.agent = layer.getInstance(self.parent.ID)
97        self.agent.addActionListener(self)
98        self.state = _AGENT_STATE_NONE
99        self.idle_counter = 1
100   
101    def idle(self):
102        """@return: None"""
103        self.state = _AGENT_STATE_IDLE
104        self.agent.act('stand', self.agent.getFacingLocation())
105
106class PlayerCharacter (GameObject, Living, CharStats):
107    """
108    PC class
109    """
110    def __init__ (self, ID, agent_layer = None, **kwargs):
111        GameObject.__init__( self, ID, **kwargs )
112        Living.__init__( self, **kwargs )
113        CharStats.__init__( self, **kwargs )
114
115        self.is_PC = True
116       
117        # PC _has_ an inventory, he _is not_ one
118        self.inventory = None
119       
120        self.state = _AGENT_STATE_NONE
121        self.layer_id = agent_layer.getId()
122        self.createBehaviour(agent_layer)
123   
124    def createBehaviour(self, layer):
125        """ Creates the behaviour for this actor.
126            @return None """
127        self.behaviour = PCBehaviour(self, layer)
128   
129    def setup(self):
130        """@return: None"""
131        self.behaviour.attachToLayer(self.ID)
132
133    def start(self):
134        """@return: None"""
135        self.behaviour.idle()
136   
137    def run(self, location):
138        """Makes the PC run to a certain location
139           @type location: fife.ScreenPoint
140           @param location: Screen position to run to.
141           @return: None"""
142        self.state = _AGENT_STATE_RUN
143        self.behaviour.agent.move('run', location, self.behaviour.speed+1)
144
145    def walk(self, location):
146        """Makes the PC walk to a certain location.
147           @type location: fife.ScreenPoint
148           @param location: Screen position to walk to.
149           @return: None"""
150        self.state = _AGENT_STATE_RUN
151        self.behaviour.agent.move('walk', location, self.behaviour.speed-1)
152
153    def teleport(self, location):
154        """Teleports a PC instantly to the given location.
155           @type location: fife.Location
156           @param location: Target coordinates for PC.
157           @return: None"""
158        self.state = _AGENT_STATE_IDLE
159        self.behaviour.agent.setLocation(location)
160
161    def approach(self, location, action = None):
162        """Approaches an npc and then ???.
163           @type loc: fife.Location
164           @param loc: the location to approach
165           @type action: Action
166           @param action: The action to schedule for execution after the approach.
167           @return: None"""
168        self.state = _AGENT_STATE_APPROACH
169        self.behaviour.nextAction = action
170        boxLocation = tuple([int(float(i)) for i in location])
171        l = fife.Location(self.behaviour.agent.getLocation())
172        l.setLayerCoordinates(fife.ModelCoordinate(*boxLocation))
173        self.behaviour.agent.move('run', l, self.behaviour.speed)
174
175class NPCBehaviour(ActorBehaviour):
176    def __init__(self, Parent = None, Layer = None):
177        super(NPCBehaviour, self).__init__(Layer)
178       
179        self.parent = Parent
180        self.state = _AGENT_STATE_NONE
181       
182        # hard code this for now
183        self.distRange = (2, 4)
184       
185    def getTargetLocation(self):
186        """@rtype: fife.Location
187           @return: NPC's position"""
188        x = self.getX()
189        y = self.getY()
190        if self.state == _AGENT_STATE_WANDER:
191            """ Random Target Location """
192            l = [0, 0]
193            for i in range(len(l)):
194                sign = randrange(0, 2)
195                dist = randrange(self.distRange[0], self.distRange[1])
196                if sign == 0:
197                    dist *= -1
198                l[i] = dist
199            x += l[0]
200            y += l[1]
201            # Random walk is
202            # rl = randint(-1, 1);ud = randint(-1, 1);x += rl;y += ud
203        l = fife.Location(self.agent.getLocation())
204        l.setLayerCoordinates(fife.ModelCoordinate(*tuple([x, y])))
205        return l
206
207    def onInstanceActionFinished(self, instance, action):
208        """What the NPC does when it has finished an action.
209           Called by the engine and required for InstanceActionListeners.
210           @type instance: fife.Instance
211           @param instance: self.agent (the NPC listener is listening for this
212            instance)
213           @type action: ???
214           @param action: ???
215           @return: None"""
216        if self.state == _AGENT_STATE_WANDER:
217            self.target_loc = self.getTargetLocation()
218        self.idle()
219       
220   
221    def idle(self):
222        """Controls the NPC when it is idling. Different actions
223           based on the NPC's state.
224           @return: None"""
225        if self.state == _AGENT_STATE_NONE:
226            self.state = _AGENT_STATE_IDLE
227            self.agent.act('stand', self.agent.getFacingLocation())
228        elif self.state == _AGENT_STATE_IDLE:
229            self.target_loc = self.getTargetLocation()
230            self.state = _AGENT_STATE_WANDER
231            self.agent.act('stand', self.agent.getFacingLocation())
232        elif self.state == _AGENT_STATE_WANDER:
233            self.parent.wander(self.target_loc)
234            self.state = _AGENT_STATE_NONE
235        elif self.state == _AGENT_STATE_TALK:
236            self.agent.act('stand', self.pc.getLocation())
237
238class NonPlayerCharacter(GameObject, Living, Scriptable, CharStats):
239    """
240    NPC class
241    """
242    def __init__(self, ID, agent_layer=None, name='NPC', \
243                 text = 'A nonplayer character', **kwargs):
244        # init game object
245        GameObject.__init__(self, ID, name=name, **kwargs)
246        Living.__init__(self, **kwargs)
247        Scriptable.__init__(self, **kwargs)
248        CharStats.__init__(self, **kwargs)
249
250        self.is_NPC = True
251        self.inventory = None
252        self.layer_id = agent_layer.getId()
253        self.createBehaviour(agent_layer)       
254        self.dialogue = kwargs.get('dialogue')
255
256    def createBehaviour(self, layer):
257        """ Creates the behaviour for this actor.
258            @return None """
259        self.behaviour = NPCBehaviour(self, layer)
260
261    def getLocation(self):
262        """ Get the NPC's position as a fife.Location object. Basically a
263            wrapper.
264            @rtype: fife.Location
265            @return: the location of the NPC"""
266        return self.behaviour.agent.getLocation()
267   
268    def wander(self, location):
269        """Nice slow movement for random walking.
270           @type location: fife.Location
271           @param location: Where the NPC will walk to.
272           @return: None"""
273        self.behaviour.agent.move('walk', location, self.behaviour.speed-1)
274
275    def run(self, location):
276        """Faster movement than walk.
277           @type location: fife.Location
278           @param location: Where the NPC will run to."""
279        self.behaviour.agent.move('run', location, self.behaviour.speed+1)
280
281    def talk(self, pc):
282        """ Makes the NPC ready to talk to the PC
283            @return: None"""
284        self.behaviour.state = _AGENT_STATE_TALK
285        self.behaviour.pc = pc.behaviour.agent
286        self.behaviour.idle()
287   
288    def setup(self):
289        """@return: None"""
290        self.behaviour.attachToLayer(self.ID)
291
292    def start(self):
293        """@return: None"""
294        self.behaviour.idle()
Note: See TracBrowser for help on using the repository browser.