class NPC(Agent): def __init__(self, settings, model, agentName, layer, world, uniqInMap=True, name=""): super(NPC, self).__init__(settings, model, agentName, layer, uniqInMap) self._state = _STATE_NONE self._name = name self._agentName = agentName self._layer = layer self._availableActions = { 'walk': False, 'run': False, 'talk': False, 'die': False, 'explode': False, 'holdgun': False, 'firegun': False, 'beshot': False, 'walkgun': False, 'rungun': False, 'diegun': False, 'beshotgun': False, 'holdpistol': False, 'aimpistolleft': False, 'aimpistolright': False, 'firepistolleft': False, 'firepistolright': False, 'walkpistol': False, 'runpistol': False, 'diepistol': False, 'beshotpistol': False, 'teleportstart': False, 'teleportend': False, 'glitch': False, 'describe' : True} self._action = { 'walk': self.walk, 'run': self.run, 'talk': self.talk, 'die': self.die, 'explode': self.explode, 'holdgun': self._idle, 'firegun': self.fire, 'beshot': self.beshot, 'walkgun': self.walk, 'rungun': self.run, 'diegun': self.die, 'beshotgun': self.beshot, 'holdpistol': self._idle, 'aimpistolleft': self.aimleft, 'aimpistolright': self.aimright, 'firepistolleft': self.fireleft, 'firepistolright': self.fireright, 'walkpistol': self.walk, 'runpistol': self.run, 'diepistol': self.die, 'beshotpistol': self.beshot, 'teleportstart': self.teleportstart, 'teleportend': self.teleportend, 'glitch': self.glitch, 'decribe' : self.describe } self._world = world self._loadNPC(self._name) def _loadNPC(self, name): self._npcFile = SimpleXMLSerializer(filename="npcs/" + name + ".xml") actionstr = self._npcFile.get("npc", "actions", None) actions = self._npcFile._deserializeDict(actionstr) for action, bool in actions.iteritems(): if bool == "True": self._availableActions[action] = True else: self._availableActions[action] = False self._actionchance = self._npcFile.get("npc", "actionchance", 0) self._description = self._npcFile.get("npc", "description", "I can see a mysterious figure,\n but I can't quite make them out.") self._autowalk = self._npcFile.get("npc", "autowalk", True) self._hasdialogue = self._npcFile.get("npc", "hasdialogue", False) self._autowalk = self._npcFile.get("npc", "autowalk", True) self._loadDialogue() self._idle() def _loadDialogue(self): if not self._hasdialogue: return self._dialogue = {} self._idledialogue = [] index = [] index = self._npcFile._deserializeList(self._npcFile.get("dialogue", "index", "")) for line in index: self._dialogue[line] = self._npcFile._deserializeDict(self._npcFile.get("dialogue", line, "")) idleindex = self._npcFile._deserializeList(self._npcFile.get("dialogue", "idleindex", "")) for line in idleindex: self._idledialogue.append(self._dialogue[line]) def _listAvailableTopics(self): returninglist = [] if not self._hasdialogue: return returninglist for index, dialogue in self._dialogue.iteritems(): if dialogue["requires"] in self._world._player._plots or dialogue["requires"] == '0' and dialogue not in self._idledialogue: returninglist.append((index, dialogue["topic"])) return returninglist def _talk(self, index): if self._world._gamestate == 'LEVEL' and index not in self._world._player._plots: self._world._player._plots.append(index) self._agent.say(self._dialogue[index]["text"], 5000) def onInstanceActionFinished(self, instance, action): self._idle() def _idle(self): self._state = _STATE_IDLE if self._autowalk: chance = random.randint(0,100) if chance < self._actionchance: self._waypointmove() else: self._agent.act('walk', self._agent.getFacingLocation()) chance = random.randint(0,100) if chance < self._actionchance / 2 and self._hasdialogue: self.talk() def _waypointmove(self): no = random.randint(0, len(self._world._waypoints) - 1) point = self._world._waypoints[no] x, point, y = point.partition(',') location = fife.Location() location.setLayer(self._layer) location.setExactLayerCoordinates(fife.ExactModelCoordinate(int(x) + random.randint(-1,1), int(y) + random.randint(-1,1))) self.run(location) def run(self, location): self._state = _STATE_RUN self._agent.move('walk', location, 0.75) def walk(self): pass def talk(self): chance = random.randint(0, len(self._idledialogue) - 1) self._talk(self._idledialogue[chance]["index"]) def die(self): pass def explode(self): pass def beshot(self): pass def aimleft(self): pass def aimright(self): pass def fire(self): pass def fireleft(self): pass def fireright(self): pass def teleportstart(self): pass def teleportend(self): pass def glitch(self): pass def describe(self): self._world._player._agent.say(self._description, 5000)
class InteractiveObject(fife.InstanceActionListener): def __init__(self, objectmanager, model, file): fife.InstanceActionListener.__init__(self) self._manager = objectmanager self._model = model self._objectFile = SimpleXMLSerializer(file) self._agentName = self._objectFile.get("object", "agentname", "dummy") self._layer = self._manager._world._map.getLayer(self._objectFile.get("object", "layer", "player")) self._agent = self._layer.getInstance(self._agentName) self._agent.addActionListener(self) self._status = self._objectFile.get("object", "status", 'INACTIVE') self._actions = { 'use' : self.use, 'destroy' : self.destroy, 'turnon' : self.activate, 'turnoff' : self.deactivate, 'explode' : self.explode, 'describe': self.describe, 'glitch' : self.glitch } self._availableactions = { 'use' : False, 'destroy' : False, 'turnon' : False, 'turnoff' : False, 'explode' : False, 'describe' : True, 'glitch' : False } actionstr = self._objectFile.get("object", "actions", None) actions = self._objectFile._deserializeDict(actionstr) for action, bool in actions.iteritems(): if bool in ("True"): self._availableactions[action] = True else: self._availableactions[action] = False self._description = self._objectFile.get("object", "description", "I can see something, but\n I can't tell what it is") self._talk = self._objectFile.get("object", "talk", False) self._message = self._objectFile._deserializeList(self._objectFile.get("object", "messages", "")) self._usesound = self._objectFile.get("object", "sound", False) if self._usesound: self._manager._world._sounds._loadclip(self._agentName, self._objectFile.get("object", "soundfile", ""), False, False) self._sound = self._manager._world._sounds._emitters[self._agentName] self._loadObject() self.onInstanceActionFinished(self._agent, "") def onInstanceActionFinished(self, instance, action): if self._status == 'ACTIVE': self._agent.act('on', self._agent.getFacingLocation()) elif self._status == 'INACTIVE': self._agent.act('off', self._agent.getFacingLocation()) elif self._status == 'DESTROYED': self._agent.act('dead', self._agent.getFacingLocation()) elif self._status == 'GLITCHED': self._agent.act('glitch', self._agent.getFacingLocation()) def use(self): if self._status == 'ACTIVE': self._agent.act('use', self._agent.getFacingLocation()) self._manager._world._player._agent.setFacingLocation(self._agent.getLocation()) if self._noactioncallbacks == 0: self._action() elif self._noactioncallbacks == 1: self._action(self._actioncallbacks[0]) elif self._noactioncallbacks == 2: self._action(self._actioncallbacks[0], self._actioncallbacks[1]) elif self._noactioncallbacks == 3: self._action(self._actioncallbacks[0], self._actioncallbacks[1], self._actioncallbacks[2]) elif self._noactioncallbacks == 4: self._action(self._actioncallbacks[0], self._actioncallbacks[1], self._actioncallbacks[2], self._actioncallbacks[3]) elif self._noactioncallbacks == 5: self._action(self._actioncallbacks[0], self._actioncallbacks[1], self._actioncallbacks[2], self._actioncallbacks[3], self._actioncallbacks[4]) if self._talk: rand = random.randint(0, len(self._message) - 1) self._manager._world._player._agent.say(self._message[rand], 3500) if self._usesound: self._sound.play() def destroy(self): self._agent.act('die', self._agent.getFacingLoaction) self._status = 'DESTROYED' def activate(self): self._agent.act('turnon', self._agent.getFacingLoaction) self._status = 'ACTIVE' def deactivate(self): self._agent.act('turnoff', self._agent.getFacingLoaction) self._status = 'INACTIVE' def explode(self): self._agent.act('explode', self._agent.getFacingLoaction) self._status = 'DESTROYED' def describe(self): self._manager._world._player._agent.say(self._description, 5000) def glitch(self): self._agent.act('glitch', self._agent.getFacingLoaction) self._status = 'GLITCHED' def noAction(self): pass # This function exists purely to act as a void function # for objects that make a pretty light def _loadObject(self): action = self._objectFile.get("object", "action", "none") if action == "none": self._action = self.noAction self._noactioncallbacks = 0 self._actioncallbacks = {} elif action == "door": loc1 = fife.Location() loc1.setLayer(self._manager._world._map.getLayer('player')) loc1.setExactLayerCoordinates(fife.ExactModelCoordinate(self._file.get("event", "newx", 0), self._file.get("event", "newy", 0))) loc2 = fife.Location() loc2.setLayer(self._manager._world._map.getLayer('player')) loc2.setExactLayerCoordinates(fife.ExactModelCoordinate(self._file.get("event", "refx", 0), self._file.get("event", "refy", 0))) self._action = self._manager._world._loadMap self._noactioncallbacks = 5 self._actioncallbakcs = { 0 : self._objectFile.get("object", "mapfile", "") , 1 : 'LEVEL' , 2 : True , 3 : loc1 , 4 : loc2 } elif action == "plot": self._action = self._manager._world._eventtracker._evaluateItem self._noactioncallbacks = 1 self._actioncallbacks = { 0 : self._agentName } elif action == "book": pass # Needs GUI manager elif action == "computer": pass # Needs GUI manager elif action == "teleport": pass # Needs hooks in the player and NPC classes
class World(EventListenerBase): """ World Class Sets up the map, gui, soundmanager and calls the Actor class to deal with actors Keyword Arguments EventListenerBase - World inherits from EventListenerBase """ def __init__(self, app, engine, setting): """ __init__ Function Starts an instance of the World class Keyword Arguments app - A pointer to the main application engine - A pointer to fife.engine setting - A pointer to a fife settings XML file """ super(World, self).__init__(engine, regKeys=True, regCmd=False, regMouse=True) # Throw values into their variables self._applictaion = app self._engine = engine self._setting = setting self._timemanager = engine.getTimeManager() self._eventmanager = engine.getEventManager() self._model = engine.getModel() self._filename = '' self._keystate = { 'UP': False, 'DOWN': False, 'LEFT': False, 'RIGHT': False, 'CTRL': False, 'SPACE': False, 'Q': False, 'E': False,} self._cameras = {} self._npcs = {} self._npclist = None self._pump_ctr = 0 self._map = None self._scene = None self._paused = True self._pausedtime = 0 self._starttime = 0 self._gamestate = 'NONE' self._quit = False self._player = None self._eventtracker = None self._objects = {} self._contextmenu = contextmenu.ContextMenu('rightclickmenu', self) self._mouseMoved = False # Start pychan pychan.init(self._engine) # Set all GUI types to empty self._hud = None self._mainmenu = None self._pausemenu = None self._loadingmenu = None self._settingsmenu = None self._aboutmenu = None # Start the sound manager self._soundmanager = SoundManager(self._engine) self._sounds = musicmanager.MusicManager(self._engine, self._soundmanager, self._timemanager) def _loadGui(self, type, guifile, imports): """ _loadGui Function Loads a pychan GUI file to one of the four GUI slots, then loads a python package to run to initilise the gui Keyword Arguments type - String, the type of GUI being loaded guifile - String, name of the pychan file being loaded imports - Boolean """ if type == 'MAIN': self._mainmenu = menuhandler.MenuHandler(guifile, self) elif type == 'HUD': self._hud = hudhandler.HUDHandler(guifile, self) elif type == 'SETTINGS': self._settingsmenu = settingshandler.SettingsHandler(guifile, self) elif type == 'ABOUT': self._aboutmenu = abouthandler.AboutHandler(guifile, self) elif type == 'PAUSE': self._pause = pychan.loadXML('gui/' + guifile + '.xml') if imports: guiinit = __import__('scripts.gui.' + guifile) guiinit.run() elif type == 'LOAD': self._loadingmenu = pychan.loadXML('gui/' + guifile + '.xml') if imports: guiinit = __import__('scripts.gui.' + guifile) guiinit.run() else: pass def _hideAllGuis(self): """ _hideAllGuis Function Hides any active GUI elements """ if self._hud != None: self._hud.hide() if self._mainmenu != None: self._mainmenu.hide() if self._pausemenu != None: self._pausemenu.hide() if self._loadingmenu != None: self._loadingmenu.hide() if self._settingsmenu != None: self._settingsmenu.hide() if self._aboutmenu != None: self._aboutmenu.hide() def _loadLevelMapCallback(self, action, percentdone): """ _loadLevelMapCallback Function Acts as a callback for level loading. Keyword Arguments action - String, what has just been loaded percentdone - Float, percentage loaded """ # You have to pump the engine, else it doesn't render anything # until the map has loaded self._engine.pump() # If it's loaded, hide the loading screen and load the HUD if percentdone == 1: self._hideAllGuis() # Otherwise set the loading screens percentage label else: loaded = self._loadingmenu.findChild(name="loading") loaded.text = str(math.floor(percentdone * 100)) + u'% Loaded' def _loadMenuMapCallback(self, action, percentdone): """ _loadMenuMapCallback Function Acts as a callback for level loading. Keyword Arguments action - String, what has just been loaded percentdone - Float, percentage loaded """ # You have to pump the engine, else it doesn't render anything # until the map has loaded self._engine.pump() # If it's loaded, hide the loading screen and load the menu if percentdone == 1: self._hideAllGuis() if self._mainmenu != None: self._mainmenu.show() # Otherwise set the loading screens percentage label else: loaded = self._loadingmenu.findChild(name="loading") loaded.text = str(math.floor(percentdone * 100)) + u'% Loaded' def _loadMap(self, filename, purpose, port=False, location=None, direction=None): """ _loadMap Function Deletes the old map and loads a new one. Also initilises cameras. Keyword Arguments filename - String, path to the map file purpose - String, LEVEL or MENU """ self._model.deleteMap(self._map) self._map = None self._npcs = {} self._npclist = False self._mapsettings = SimpleXMLSerializer(filename=filename +".config") self._eventtracker = None if purpose == 'LEVEL': # Hide any active GUIs self._hideAllGuis() # Pump the engine to force it to move to a new frame self._engine.pump() # If the loading menu is loaded, show it if self._loadingmenu != None: self._loadingmenu.show() loadwindow = self._loadingmenu.findChild(name="loadwindow") autoposition.placeWidget(loadwindow, 'automatic') # Load the map self._map = loadMapFile(filename, self._engine, self._loadLevelMapCallback) elif purpose == 'MENU': # Hide any active GUIs self._hideAllGuis() # Pump the engine to force it to move to a new frame self._engine.pump() # If the loading menu is loaded, show it if self._loadingmenu != None: self._loadingmenu.show() loadwindow = self._loadingmenu.findChild(name="loadwindow") autoposition.placeWidget(loadwindow, 'automatic') # Load the map self._map = loadMapFile(filename, self._engine, self._loadMenuMapCallback) # Start (or clear) the camera array self._cameras = {} # For each camera in the map for cam in self._map.getCameras(): # Get the camera ID camera_id = cam.getId() # Add the camera with that ID to the array self._cameras[camera_id] = cam # Reset the camera cam.resetRenderers() if purpose == 'LEVEL': # Start the player character self._startPlayerActor() if location != None: self._player._agent.setLocation(location) if direction != None: self._player._agent.setFacingLocation(direction) if self._hud != None: self._hud.show() self._loadLevelMapCallback("", 0.775) # Start the floating text renderer renderer = fife.FloatingTextRenderer.getInstance(self._cameras['main']) textfont = self._engine.getGuiManager().createFont('fonts/rpgfont.png', 0, str(self._setting.get("FIFE", "FontGlyphs"))) renderer.changeDefaultFont(textfont) renderer.setDefaultBackground(0,0,0,0) renderer.setDefaultBorder(0,0,0,0) renderer.activateAllLayers(self._map) renderer.setEnabled(True) if purpose == 'LEVEL': self._loadLevelMapCallback("", 0.8) else: self._loadMenuMapCallback("", 0.8) if self._mapsettings.get("map", "usewaypoints", False): self._waypoints = self._mapsettings._deserializeList(self._mapsettings.get("map", "waypoints", "")) else: self._waypoints = None if purpose == 'LEVEL': self._loadLevelMapCallback("", 0.825) else: self._loadMenuMapCallback("", 0.825) if self._mapsettings.get("map", "useobjects", False): self._objects = objectmanager.ObjectManager(self) objlist = self._mapsettings._deserializeList(self._mapsettings.get("map", "objectlist", False)) for file in objlist: self._objects._loadObjects(file) if purpose == 'LEVEL': self._loadLevelMapCallback("", 0.85) else: self._loadMenuMapCallback("", 0.85) if self._mapsettings.get("map", "dynamicnpcs", False): self._npclist = self._mapsettings._deserializeDict(self._mapsettings.get("map", "npclist", False)) if self._npclist != False: for id, name in self._npclist.iteritems(): self._npcs[name] = npc.NPC(self._setting, self._model, id, self._map.getLayer('player'), self, True, name) if purpose == 'LEVEL': self._loadLevelMapCallback("", 0.9) else: self._loadMenuMapCallback("", 0.9) self._eventtracker = eventtracker.EventTracker(self._engine, self._model, self._sounds, self) if self._mapsettings.get("map", "useevents", False): eventlist = self._mapsettings._deserializeList(self._mapsettings.get("map", "eventslist", "")) for file in eventlist: self._eventtracker._addEvent(file) if purpose == 'LEVEL': self._loadLevelMapCallback("", 0.95) else: self._loadMenuMapCallback("", 0.95) self._drift = {} self._drift = self._mapsettings._deserializeDict(self._mapsettings.get("map", "drift", "use : False")) if self._drift["use"] == "True": self._drift["use"] = True self._drift["x"] = float(self._drift["x"]) self._drift["y"] = float(self._drift["y"]) start = self._drift["start"].partition(",") loc = fife.Location(self._map.getLayer('player')) loc.setExactLayerCoordinates(fife.ExactModelCoordinate(float(start[0]), float(start[2]))) self._cameras['main'].setLocation(loc) else: self._drift["use"] = False self._gamestate = purpose def _getLocationAt(self, clickpoint, layer): """ Query the main camera for the Map location (on the agent layer) that a screen point refers to. """ target_mapcoord = self._cameras['main'].toMapCoordinates(clickpoint, False) target_mapcoord.z = 0 location = fife.Location(layer) location.setMapCoordinates(target_mapcoord) return location def _getInstancesAt(self, clickpoint, layer): """ Query the main camera for instances on a given layer. """ return self._cameras['main'].getMatchingInstances(clickpoint, layer) def mousePressed(self, evt): if evt.isConsumedByWidgets() or self._gamestate != 'LEVEL': return clickpoint = fife.ScreenPoint(evt.getX(), evt.getY()) playerinstance = self._getInstancesAt(clickpoint, self._map.getLayer('player')) playerinstance = playerinstance + self._getInstancesAt(clickpoint, self._map.getLayer('waypoints')) if (evt.getButton() == fife.MouseEvent.LEFT): self._player.run(self._getLocationAt(clickpoint, self._map.getLayer('player'))) self._contextmenu._hide() elif (evt.getButton() == fife.MouseEvent.RIGHT): self._contextmenu._show(playerinstance, clickpoint, self) evt.consume() def mouseMoved(self, evt, ext=False, cursor=None): self._mouseMoved = True if self._map == None or self._gamestate != 'LEVEL': return renderer = fife.InstanceRenderer.getInstance(self._cameras['main']) renderer.removeAllOutlines() if ext: pt = fife.ScreenPoint(cursor.getX(), cursor.getY()) else: pt = fife.ScreenPoint(evt.getX(), evt.getY()) instances = self._getInstancesAt(pt, self._map.getLayer('player')) instances = instances + self._getInstancesAt(pt, self._map.getLayer('waypoints')) for i in instances: for name, object in self._objects._objects.iteritems(): if i.getId() == name: renderer.addOutlined(i, random.randint(20,255), random.randint(20,255), random.randint(20,255), 1) for name, object in self._npcs.iteritems(): if i.getId() == object._agentName: renderer.addOutlined(i, random.randint(20,255), random.randint(20,255), random.randint(20,255), 1) def _keyPressed(self, evt): keyval = evt.getKey().getValue() keystr = evt.getKey().getAsString().lower() def _startPlayerActor(self): self._player = Player(self._setting, self._model, "actor-pc", self._map.getLayer('player')) self._cameras['main'].setLocation(self._player._agent.getLocation()) self._cameras['main'].attach(self._map.getLayer('player').getInstance("actor-pc")) if self._cameras['main'].getAttached() == None: def cameraDrift(self): if self._drift["use"]: oldloc = self._cameras['main'].getLocation().getExactLayerCoordinates() border = self._drift["end"].partition(",") if oldloc.x < float(border[0]): self._drift["x"] = (self._drift["x"] + random.randint(-1, 1) * 0.025) * -1 if oldloc.y < float(border[2]): self._drift["y"] = (self._drift["y"] + random.randint(-1, 1) * 0.025) * -1 border2 = self._drift["start"].partition(",") if oldloc.x > float(border2[0]): self._drift["x"] = (self._drift["x"] + random.randint(-1, 1) * 0.025) * -1 if oldloc.y > float(border2[2]): self._drift["y"] = (self._drift["y"] + random.randint(-1, 1) * 0.025) * -1 delta = self._timemanager.getTimeDelta() / 100.0 loc = fife.Location(self._map.getLayer('player')) deltax = round(oldloc.x + self._drift["x"] * delta, 2) deltay = round(oldloc.y + self._drift["y"] * delta, 2) loc.setExactLayerCoordinates(fife.ExactModelCoordinate(deltax, deltay)) self._cameras['main'].setLocation(loc)