# HG changeset patch # User prock@33b003aa-7bff-0310-803a-e67f0ece8222 # Date 1276624400 0 # Node ID d0282579668c4e76cc951be1a95dc5555136c69c # Parent c9113e23b0041a2530a05b95d95d665850c6ff21 Added QuestManager. The player can now move from map to map and the state of the quests remains persistent. Both quests the NPC gives you are now completable. Still have to clean up the quest loading code. Started adding more comments. diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/actors/player.py --- a/demos/rpg/scripts/actors/player.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/actors/player.py Tue Jun 15 17:53:20 2010 +0000 @@ -44,7 +44,47 @@ super(Player, self).__init__(gamecontroller, layer, "Player", "player", playermodelname, "player", True) self._type = GameObjectTypes["PLAYER"] - self._playermodelname = playermodelname - self._actionlistener = PlayerActionListener(self._gamecontroller, self) self._actionlistener.attachActionListener() + + self._quests = [] + + def serialize(self): + lvars = super(Player, self).serialize() + + activequests = "" + + for quest in self._gamecontroller.questmanager.activequests: + if activequests == "": + activequests = quest.id + else: + activequests = activequests + "," + quest.id + + lvars['activequests'] = activequests + + completedquests = "" + + for quest in self._gamecontroller.questmanager.completedquests: + if completedquests == "": + completedquests = quest.id + else: + completedquests = completedquests + "," + quest.id + + lvars['completedquests'] = completedquests + + return lvars + + def deserialize(self, valuedict): + super(Player, self).deserialize(valuedict) + + activequests = valuedict['activequests'].split(",") + + for questid in activequests: + self._gamecontroller.questmanager.activateQuestById(questid) + print "loaded active quest: " + questid + + completedquests = valuedict['completedquests'].split(",") + + for questid in completedquests: + self._gamecontroller.questmanager.completeQuestById(questid) + print "loaded completed quest: " + questid diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/actors/questgiver.py --- a/demos/rpg/scripts/actors/questgiver.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/actors/questgiver.py Tue Jun 15 17:53:20 2010 +0000 @@ -36,50 +36,44 @@ super(QuestGiver, self).__init__(gamecontroller, layer, typename, baseobjectname, instancename, instanceid, createInstance) self._type = GameObjectTypes["QUESTGIVER"] - self._quests = [] - - self._activequest = None - def addQuest(self, quest): - self._quests.append(quest) + pass def offerNextQuest(self): - if self._activequest: - return - - if len(self._quests) > 0: + if self._gamecontroller.questmanager.getNextQuest(self.id): self._gamecontroller.guicontroller.showQuestDialog(self) def getNextQuest(self): - if len(self._quests) > 0: - return self._quests[0] - - return None + return self._gamecontroller.questmanager.getNextQuest(self.id) def activateQuest(self, quest): - self._activequest = quest + self._gamecontroller.questmanager.activateQuest(quest) def completeQuest(self): - if self._activequest in self._quests: - if self._activequest.checkQuestCompleted(self._gamecontroller.scene.player): - self.say("That everything I need. Thank you!") - self._gamecontroller.scene.player.gold = self._gamecontroller.scene.player.gold - self._activequest.requiredgold + for activequest in self._gamecontroller.questmanager.activequests: + if activequest.ownerid == self.id: + if activequest.checkQuestCompleted(self._gamecontroller.scene.player): + self.say("That everything I need. Thank you!") + + self._gamecontroller.scene.player.gold = self._gamecontroller.scene.player.gold - activequest.requiredgold - for itemid in self._activequest.requireditems: - self._gamecontroller.scene.player.removeItemFromInventory(itemid) - - self._quests.remove(self._activequest) - self._activequest = None - else: - self.say("Come back when you have all the items I requested!") - else: - #something went wrong - self._activequest = None + for itemid in activequest.requireditems: + self._gamecontroller.scene.player.removeItemFromInventory(itemid) + + self._gamecontroller.questmanager.completeQuest(activequest) + else: + self.say("Come back when you have all the items I requested!") def haveQuest(self): - return len(self._quests) > 0 + return bool(self._gamecontroller.questmanager.getNextQuest(self.id)) or bool(self._getActiveQuest()) def _getActiveQuest(self): - return self._activequest + """ + Returns the first active quest in the list. There should only be one + active quest per questgiver anyway. + """ + for quest in self._gamecontroller.questmanager.activequests: + if quest.ownerid == self.id: + return quest activequest = property(_getActiveQuest) diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/gamecontroller.py --- a/demos/rpg/scripts/gamecontroller.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/gamecontroller.py Tue Jun 15 17:53:20 2010 +0000 @@ -36,9 +36,14 @@ from scripts.actors.baseactor import TalkAction, PickUpItemAction, EnterPortalAction from scripts.objects.baseobject import GameObjectTypes from scripts.misc.exceptions import ObjectNotFoundError, ObjectAlreadyInSceneError +from scripts.quests.questmanager import QuestManager class KeyState(object): + """ + Holds the current state of the keys on the keyboard (down or up). + False = down, True = up. + """ def __init__(self): self._keystate = { } @@ -52,9 +57,19 @@ return False def reset(self): + """ + Empties the keystate dictionary (assumes all keys are False) + """ self._keystate.clear() class GameListener(fife.IKeyListener, fife.IMouseListener): + """ + Main game listener. Listens for Mouse and Keyboard events. + + This class also has the ability to attach and detach itself from + the event manager in cases where you do not want input processed (i.e. when + the main menu is visible). It is NOT attached by default. + """ def __init__(self, gamecontroller): self._engine = gamecontroller.engine self._gamecontroller = gamecontroller @@ -69,6 +84,9 @@ self._lastmousepos = (0.0,0.0) def attach(self): + """ + Attaches to the event manager. + """ if not self._attached: self._gamecontroller.keystate.reset() self._eventmanager.addMouseListenerFront(self) @@ -76,6 +94,9 @@ self._attached = True def detach(self): + """ + Detaches from the event manager. + """ if self._attached: self._eventmanager.removeMouseListener(self) self._eventmanager.removeKeyListener(self) @@ -180,6 +201,12 @@ self._gamecontroller.keystate.updateKey(keyval, False) class GameController(object): + """ + The main game class. + + This handles all game related code including setting up the scene, displaying user + interfaces, managing sound, etc etc. + """ def __init__(self, application, engine, settings): self._application = application self._engine = engine @@ -195,6 +222,8 @@ self._guicontroller.showMainMenu() + self._questmanager = QuestManager(self) + self._scene = None self._instancerenderer = None self._floatingtextrenderer = None @@ -204,8 +233,7 @@ def onConsoleCommand(self, command): """ - Might be useful if you want to have the game parse a command. - Not sure if I am going to keep this or not. + Parses game related console commands. """ result = "" @@ -257,6 +285,10 @@ return result def newGame(self): + """ + Removes any save games and starts a new game. + """ + self._guicontroller.hideMainMenu() for filename in glob.glob(os.path.join("saves" , "*.xml")): @@ -267,6 +299,10 @@ def loadMap(self, mapname): + """ + Creates the scene for the map and attaches the listener. + """ + if self._listener: self._listener.detach() @@ -288,6 +324,10 @@ self._listener.attach() def switchMap(self, newmapname): + """ + Queues a map switch for next frame. This must be done next frame to ensure + all events pertaining to the current frame have finished being processed. + """ self._switchmaprequested = True self._newmap = newmapname @@ -295,6 +335,9 @@ self._scene.serialize() def endGame(self): + """ + Saves the game state and destroys the scene. + """ if self._scene: self._scene.serialize() @@ -321,6 +364,9 @@ def _getGUIController(self): return self._guicontroller + def _getQuestManager(self): + return self._questmanager + def _getEngine(self): return self._engine @@ -340,6 +386,7 @@ return self._application.logger guicontroller = property(_getGUIController) + questmanager = property(_getQuestManager) engine = property(_getEngine) settings = property(_getSettings) scene = property(_getScene) diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/quests/basequest.py --- a/demos/rpg/scripts/quests/basequest.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/quests/basequest.py Tue Jun 15 17:53:20 2010 +0000 @@ -33,22 +33,26 @@ 'RETURN_ITEM':1} class Quest(object): - def __init__(self, owner, questname, questtext): - self._owner = owner - self._name = questname + def __init__(self, ownerid, questid, questtitle, questtext): + self._ownerid = ownerid + self._questid = questid + self._name = questtitle self._text = questtext + def __eq__(self, other): + return self._questid == other.id + def checkQuestCompleted(self, actor): pass - def _getOwner(self): - return self._owner + def _getOwnerID(self): + return self._ownerid def _getName(self): return self._name - def _setName(self, questname): - self._name = questname + def _setName(self, questtitle): + self._name = questtitle def _getText(self): return self._text @@ -56,13 +60,17 @@ def _setText(self, questtext): self._text = questtext - owner = property(_getOwner) + def _getID(self): + return self._questid + + ownerid = property(_getOwnerID) name = property(_getName, _setName) text = property(_getText, _setText) + id = property(_getID) class ReturnItemQuest(Quest): - def __init__(self, owner, questname, questtext): - super(ReturnItemQuest, self).__init__(owner, questname, questtext) + def __init__(self, ownerid, questid, questtitle, questtext): + super(ReturnItemQuest, self).__init__(ownerid, questid, questtitle, questtext) self._requireditems = [] self._requiredgold = 0 diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/quests/questmanager.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demos/rpg/scripts/quests/questmanager.py Tue Jun 15 17:53:20 2010 +0000 @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +# -*- coding: utf-8 -*- + +# #################################################################### +# Copyright (C) 2005-2010 by the FIFE team +# http://www.fifengine.net +# This file is part of FIFE. +# +# FIFE is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# #################################################################### +# This is the rio de hola client for FIFE. + +from fife import fife + +class QuestManager(object): + def __init__(self, gamecontroller): + self._gamecontroller = gamecontroller + + self._quests = {} + self._activequests = [] + self._completedquests = [] + + def addQuest(self, quest): + if self._quests.has_key(quest.ownerid): + if not quest in self._quests[quest.ownerid]: + self._quests[quest.ownerid].append(quest) + else: + self._quests[quest.ownerid] = [quest] + + def getQuest(self, questid): + for owner in self._quests: + for quest in self._quests[owner]: + if quest.id == questid: + return quest + + return None + + def getNextQuest(self, ownerid): + for quest in self._quests[ownerid]: + if not quest in self._activequests and not quest in self._completedquests: + return quest + + return None + + def activateQuest(self, quest): + if not quest in self._activequests: + self._activequests.append(quest) + + def completeQuest(self, quest): + if not quest in self._completedquests: + self._completedquests.append(quest) + + if quest in self._activequests: + self._activequests.remove(quest) + + def activateQuestById(self, questid): + quest = self.getQuest(questid) + if quest: + self.activateQuest(quest) + + def completeQuestById(self, questid): + quest = self.getQuest(questid) + if quest: + self.completeQuest(quest) + + def _getActiveQuests(self): + return self._activequests + + def _getCompletedQuests(self): + return self._completedquests + + def _getAllQuests(self): + return self._quests + + activequests = property(_getActiveQuests) + completedquests = property(_getCompletedQuests) + quests = property(_getAllQuests) diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/rpg.py --- a/demos/rpg/scripts/rpg.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/rpg.py Tue Jun 15 17:53:20 2010 +0000 @@ -36,6 +36,11 @@ from fife.extensions.fife_utils import getUserDataDirectory class KeyFilter(fife.IKeyFilter): + """ + This is the implementation of the fife.IKeyFilter class. + + Prevents any filtered keys from being consumed by guichan. + """ def __init__(self, keys): fife.IKeyFilter.__init__(self) self._keys = keys @@ -44,7 +49,15 @@ return event.getKey().getValue() in self._keys class ApplicationListener(fife.IKeyListener, fife.ICommandListener, fife.ConsoleExecuter): + """ + Listens for window commands, console commands and keyboard input. + + Does not process game related input. + """ def __init__(self, engine, gamecontroller): + """ + Initializes all listeners and registers itself with the eventmanager. + """ self._engine = engine self._gamecontroller = gamecontroller self._eventmanager = self._engine.getEventManager() @@ -66,12 +79,15 @@ self.quit = False def keyPressed(self, event): + """ + Processes any non game related keyboar input. + """ + if event.isConsumed(): + return + keyval = event.getKey().getValue() keystr = event.getKey().getAsString().lower() - if event.isConsumed(): - return - if keyval == fife.Key.ESCAPE: self.quit = True event.consume() @@ -89,7 +105,6 @@ self.quit = (command.getCommandType() == fife.CMD_QUIT_GAME) if self.quit: command.consume() - self._gamecontroller.endGame() def onConsoleCommand(self, command): result = "" @@ -125,6 +140,11 @@ print "No tools set up yet" class RPGApplication(ApplicationBase): + """ + The main application. It inherits fife.extensions.ApplicationBase. + + Implements ApplicationBase._pump(). + """ def __init__(self, TDS): super(RPGApplication,self).__init__(TDS) self._settings = TDS @@ -142,6 +162,11 @@ return self._listener def requestQuit(self): + """ + Sends the quit command to the application's listener. We could set + self.quitRequested to true also but this is a good example on how + to build and dispatch a fife.Command. + """ cmd = fife.Command() cmd.setSource(None) cmd.setCommandType(fife.CMD_QUIT_GAME) @@ -149,7 +174,8 @@ def _pump(self): if self._listener.quit: - self.breakRequested = True + self._gamecontroller.endGame() + self.quitRequested = True else: self._gamecontroller.pump() diff -r c9113e23b004 -r d0282579668c demos/rpg/scripts/scene.py --- a/demos/rpg/scripts/scene.py Fri Jun 11 21:29:58 2010 +0000 +++ b/demos/rpg/scripts/scene.py Tue Jun 15 17:53:20 2010 +0000 @@ -80,7 +80,7 @@ questdict = self._questsettings.get(identifier, quest, {}) if questdict['type'] == "RETURN_ITEM": - questobj = ReturnItemQuest(newobject, questdict['name'], questdict['desc']) + questobj = ReturnItemQuest(newobject.id, quest, questdict['name'], questdict['desc']) for ritem in self._questsettings.get(quest+"_items", "itemlist", []): itemdict = self._questsettings.get(quest+"_items", ritem, {}) if itemdict["name"] == "GOLD_COINS": @@ -88,9 +88,12 @@ else: questobj.addRequiredItem(ritem) else: - questobj = Quest(actor, questdict['name'], questdict['desc']) + questobj = Quest(newobject.id, quest, questdict['name'], questdict['desc']) newobject.addQuest(questobj) + + #add quest to quest manager as well + self._gamecontroller.questmanager.addQuest(questobj) elif objdict["type"] == "NPC": newobject = Actor(self._gamecontroller, self.actorlayer, objdict["type"], objectname, modeldict["model"], identifier, True)