source: trunk/PARPG/scripts/engine.py @ 68

Revision 68, 6.8 KB checked in by maximinus_parpg, 11 years ago (diff)

Cleaned up NPC class (a lot)
Right-clicking an object now shows info, albeit on the terminal.
Added information to /maps/map_objects.xml

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!
19from xml.sax import make_parser
20from xml.sax.handler import ContentHandler
21from agents.hero import Hero
22from agents.npc import NPC
23from objects import GameObject
24
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.
35
36class LocalXMLParser(ContentHandler):
37    """Class inherits from ContantHandler, and is used to parse the
38       local objects data"""
39    def __init__(self):
40        self.search = "objects"
41        self.pc = None
42        self.objects = []
43        self.npcs = []
44   
45    def startElement(self, name, attrs):
46        """Called every time we meet a new element in the XML file"""
47        # we are only looking for the 'layer' elements, the rest we ignore
48        if(name == "PC"):
49            # already have a PC?
50            if(self.pc != None):
51                sys.stderr.write("Error: 2 PC characters defined")
52                sys.exit(False)
53            # grab the data and store that as well
54            try:
55                xpos = attrs.getValue("xpos")
56                ypos = attrs.getValue("ypos")
57            except(KeyError):
58                sys.stderr.write("Error: Data missing in PC definition")
59                sys.exit(False)
60            # store for later
61            self.pc=[xpos,ypos]
62        elif(name == "NPC"):
63            # let's parse and add the data
64            try:
65                xpos=attrs.getValue("xpos")
66                ypos = attrs.getValue("ypos")
67                gfx = attrs.getValue("gfx")
68                ident = attrs.getValue("id")
69                text = attrs.getValue("text")
70            except(KeyError):
71                sys.stderr.write("Error: Data missing in NPC definition\n")
72                sys.exit(False)
73            # now we have the data, save it for later
74            self.npcs.append([xpos, ypos, gfx, ident, text])
75        elif(name == "object"):
76            # same old same old
77            try:
78                xpos = attrs.getValue("xpos")
79                ypos = attrs.getValue("ypos")
80                gfx = attrs.getValue("gfx")
81                ident = attrs.getValue("id")
82                text = attrs.getValue("text")
83            except(KeyError):
84                sys.stderr.write("Error: Data missing in object definition\n")
85                sys.exit(False)
86            # now we have the data, save it for later
87            self.objects.append([xpos, ypos, gfx, ident, text])
88
89class Engine:
90    """Engine holds the logic for the game
91       Since some data (object position and so forth) is held in the
92       fife, and would be pointless to replicate, we hold a instance of
93       the fife view here. This also prevents us from just having a
94       function heavy controller"""
95    def __init__(self, view):
96        self.view = view
97        self.PC = None
98        self.npcs = []
99        self.objects = []
100
101    def loadObjects(self, filename):
102        """Load objects from the XML file
103           Returns True if it worked, False otherwise"""
104        try:
105            objects_file = open(filename, 'rt')
106        except(IOError):
107            sys.stderr.write("Error: Can't find objects file\n")
108            return False
109        # now open and read the XML file
110        parser = make_parser()
111        cur_handler = LocalXMLParser()
112        parser.setContentHandler(cur_handler)
113        parser.parse(objects_file)
114        objects_file.close()
115        # must have at least 1 PC
116        if(cur_handler.pc == None):
117            sys.stderr.write("Error: No PC defined\n")
118            sys.exit(False)
119        # now add to the map and the engine
120        self.addPC(cur_handler.pc)
121        self.addNPCs(cur_handler.npcs)
122        self.addObjects(cur_handler.objects)
123        return True
124
125    def addPC(self,pc):
126        """Add the PC to the world"""
127        self.view.addObject(float(pc[0]), float(pc[1]),"PC")
128        self.PC = Hero("PC", self.view.agent_layer)
129        # ensure the PC starts on a default action
130        self.PC.start()
131        self.view.addPC(self.PC.agent)
132
133    def addObjects(self,objects):
134        """Add all of the objects we found into the fife map
135           and into our class
136           An NPC is just an object to FIFE"""
137        for i in objects:
138            self.view.addObject(float(i[0]), float(i[1]), i[2])
139            # now add it as an engine object
140            self.objects.append(GameObject(int(float(i[0])),
141                                           int(float(i[1])), i[3], i[4]))
142
143    def addNPCs(self,npcs):
144        """Add all of the NPCs we found into the fife map
145           and into this class"""
146        for i in npcs:
147            self.view.addObject(float(i[0]), float(i[1]), i[2])
148            # now add as engine data
149            self.npcs.append(NPC(int(float(i[0])), int(float(i[1])),
150                                 i[3], i[4]))
151
152    def getObjectString(self, xpos, ypos):
153        """Get the objects description of itself"""
154        # cycle through all of the objects; do we have something there?
155        for i in self.objects:
156            if((xpos == i.xpos)and(ypos == i.ypos)):
157                # yes, we have a match, so return the text
158                return i.text
159        for i in self.npcs:
160            if((xpos == i.xpos)and(ypos == i.ypos)):
161                # yes, we have a match, so return the text
162                return i.text
163        # nothing, but return the empty string in case we print it
164        return ""
165
166    def loadMap(self,map_file):
167        """Load a new map
168           TODO: needs some error checking"""
169        # first we let FIFE load the rest of the map
170        self.view.load(map_file)
171        # then we update FIFE with the PC, NPC and object details
172        self.loadObjects(map_file[:-4]+"_objects.xml")
173
174    def handleMouseClick(self,position):
175        self.PC.run(position)
176
Note: See TracBrowser for help on using the repository browser.