Changeset 361 for trunk


Ignore:
Timestamp:
11/01/09 21:29:41 (10 years ago)
Author:
orlandov
Message:

Ticket #104 - Patch by Vaporice and or1andov. Integrate quests into game dialogue and make it possible to persist quest state. fixes[s:trac, t:134]

  • Integrate Vaporice's quest engine implementation
  • Discontinue or1andov's sample dialogue and use Zenbitz's Drunkard
  • Reuse Zenbitz's dialogue functions and callbacks in the game PlayerCharacter? class
  • Whitespace and style tweaks
Location:
trunk/game
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/game/dialogue/drunkard.yaml

    r353 r361  
    1616--- 
    1717NPC: Bart The Drunkard 
    18 AVATAR: gui/icons/drunkard.png 
     18AVATAR: gui/icons/npc.png 
    1919START: main_dialog 
    2020 
     
    189189        - say: "I would think that getting your own booze ration would be reward enough!" 
    190190        - responses:  
    191            - 
    192              - "I am fond of a bender now and again, it's true." 
    193              - old_pals 
    194            - 
    195              - "Personally, I stay away from alcohol.  Dulls the senses.  But I suppose I'll help you out of the goodness of my heart." 
    196              - old_pals 
     191            - 
     192              - "I am fond of a bender now and again, it's true." 
     193              - old_pals 
     194            - 
     195              - "Personally, I stay away from alcohol.  Dulls the senses.  But I suppose I'll help you out of the goodness of my heart." 
     196              - old_pals 
    197197              
    198198    dead_pekko: 
     
    324324       - say: "You are a genius, sir, a genius. [Bart holds bottle up to the light]  Looks great. How did it come out?" 
    325325       - responses: 
     326          # hardcoding the value here until the inventory code can be used in 
     327          # game 
    326328          - 
    327329            - "I think it's just about perfect" 
    328330            - best_beer 
    329             - beer.quality >= 5 
    330           - 
    331             - "It took some doing, but I think I got it down." 
    332             - good_beer 
    333             - beer.quality == 4 
    334           - 
    335             - "I am pretty happy about it, given the circumstances." 
    336             - decent_beer 
    337             - beer.quality == 3 
    338           - 
    339             - "It's not my best work, but it will get you hammered." 
    340             - ok_beer 
    341             - beer.quality == 2 
    342           - 
    343             - "I hope it turned out OK." 
    344             - bad_beer 
    345             - beer.quality == 1 
    346           - 
    347             - "No promises on the the taste..." 
    348             - poisonous_beer 
    349             - beer.quality < 1 
     331#             - beer.quality >= 5 
     332#           - 
     333#             - "It took some doing, but I think I got it down." 
     334#             - good_beer 
     335#             - beer.quality == 4 
     336#           - 
     337#             - "I am pretty happy about it, given the circumstances." 
     338#             - decent_beer 
     339#             - beer.quality == 3 
     340#           - 
     341#             - "It's not my best work, but it will get you hammered." 
     342#             - ok_beer 
     343#             - beer.quality == 2 
     344#           - 
     345#             - "I hope it turned out OK." 
     346#             - bad_beer 
     347#             - beer.quality == 1 
     348#           - 
     349#             - "No promises on the the taste..." 
     350#             - poisonous_beer 
     351#             - beer.quality < 1 
    350352             
    351353    best_beer:  
    352354        - say: "[ Bart drinks the beer] Let the church bells ring!  This stuff is awesome!" 
     355        - complete_quest: beer 
    353356        - responses: 
    354357           -  
  • trunk/game/maps/map.xml

    r356 r361  
    18161816                        <i o="block" r="0" x="8.0" y="-3.0" z="0.0" /> 
    18171817                        <i gfx="long_coat_female" id="long_coat_female0" name="Aeon" o="long_coat_female" object_type="NonPlayerCharacter" r="0" text="A woman wearing a large coat" x="-5.0" xpos="-5.0" y="-3.0" ypos="-3.0" z="0.0" /> 
    1818                         <i gfx="long_coat_male" id="long_coat_male0" name="The Judge" o="long_coat_male" object_type="NonPlayerCharacter" r="0" text="A man wearing a large coat" x="-5.0" xpos="-5.0" y="-4.0" ypos="-4.0" z="0.0" /> 
     1818                        <i gfx="long_coat_male" id="long_coat_male0" name="Drunkard" dialogue="dialogue/drunkard.yaml" o="long_coat_male" object_type="NonPlayerCharacter" r="0" text="A very drunk looking man" x="-5.0" xpos="-5.0" y="-4.0" ypos="-4.0" z="0.0" /> 
    18191819                        <i dialogue="dialogue/farmer.yaml" gfx="male_farmer_1" id="male_farmer0" name="Manslow" o="male_farmer_1" object_type="NonPlayerCharacter" r="0" text="A grimy looking farmer" x="-5.0" xpos="-5.0" y="-5.0" ypos="-5.0" z="0.0" /> 
    18201820                        <i gfx="male_traveler_1" id="male_traveler0" name="Gregor" o="male_traveler_1" object_type="NonPlayerCharacter" r="0" text="A wandering traveler" x="-5.0" xpos="-5.0" y="-6.0" ypos="-6.0" z="0.0" /> 
    1821                         <i dialogue="dialogue/sample.yaml" gfx="npc_woman" id="woman01" name="Loranda" o="npc_woman" object_type="NonPlayerCharacter" r="0" text="A friendly woman" x="-5.0" xpos="-5.0" y="-7.0" ypos="-7.0" z="0.0" /> 
     1821                        <i gfx="npc_woman" id="woman01" name="Tina" o="npc_woman" object_type="NonPlayerCharacter" r="0" text="A friendly woman" x="-5.0" xpos="-5.0" y="-7.0" ypos="-7.0" z="0.0" /> 
    18221822                        <i gfx="crate" id="crate01" is_open="False" locked="False" name="asdf" o="crate" object_type="WoodenCrate" r="0" text="A crate that is covered in grime and dirt. There doesn&apos;t seem to be anything remarkable about it" x="-3.0" xpos="-3.0" y="-4.0" ypos="-4.0" z="0.0" /> 
    18231823                        <i gfx="crate" id="crate02" is_open="False" locked="False" name="A dirty old crate" o="crate" object_type="WoodenCrate" r="0" text="A crate that is covered in grime and dirt. There doesn&apos;t seem to be anything remarkable about it" x="-4.0" xpos="-4.0" y="-6.0" ypos="-6.0" z="0.0" /> 
  • trunk/game/run.py

    r339 r361  
    9999        self.model = engine.Engine(self.world) 
    100100        self.world.data = self.model 
     101        self.world.initHud() 
    101102        self.listener = ApplicationListener(self.engine,self.world,self.model) 
    102103        self.world.quitFunction = self.listener.quitGame 
  • trunk/game/scripts/dialogue.py

    r350 r361  
    152152            for r in command.get('responses'): 
    153153                cond = r[2:] 
    154                 if not cond or eval(cond[0], state, {}): 
    155                     responses.append(r) 
     154                try: 
     155                    if not cond or eval(cond[0], state, {}): 
     156                        responses.append(r) 
     157                except Exception, e: 
     158                    print "Error in response conditional: %s" % (cond[0],) 
     159                    #raise e 
    156160 
    157161            section = responses[response][1] 
  • trunk/game/scripts/dialoguegui.py

    r320 r361  
    2121from scripts.dialogue import DialogueEngine 
    2222 
    23 class Player(object): 
    24     """A mock player object until we have a proper Player/Quest model""" 
    25     def __init__(self): 
    26         self.current_quests = set() 
    27         self.finished_quests = set() 
     23class DialogueGUI(object): 
     24    def __init__(self, npc, quest_engine, pc): 
     25        self.pc = pc 
    2826 
    29     def canAcceptQuest(self, quest): 
    30         return     quest not in self.finished_quests \ 
    31                and quest not in self.current_quests 
     27        # define dialogue engine callbacks 
     28        def start_quest(state, quest): 
     29            print "You've picked up the '%s' quest!" % quest 
     30            state['quest'].addQuest(quest) 
    3231 
    33     def hasSatisfiedQuest(self, quest): 
    34         return quest in self.current_quests 
     32        def complete_quest(state, quest_id): 
     33            print "You've finished the quest %s" % quest_id 
     34            state['quest'].finishQuest(quest_id) 
    3535 
    36     def startQuest(self, quest): 
    37         if quest in self.current_quests: 
    38             raise RuntimeError("Already have quest, %s" % quest) 
    39         self.current_quests.add(quest) 
     36        def delete_quest(state, quest_id): 
     37            print "You've deleted quest %s" % quest_id 
     38            state['quest'].deleteQuest(quest_id) 
    4039 
    41     def completeQuest(self, quest): 
    42         self.finished_quests.add(quest) 
    43         self.current_quests.remove(quest) 
     40        def increase_value(state, quest_id, variable, value): 
     41            print "Increased %s by %i"%(variable,value) 
     42            state['quest'][quest_id].increaseValue(variable,value) 
    4443 
    45 class DialogueGUI(object): 
    46     def __init__(self, npc): 
     44        def decrease_value(state, quest_id, variable, value): 
     45            print "Decreased %s by %i"%(variable,value) 
     46            state['quest'][quest_id].decreaseValue(variable,value) 
     47 
     48        def set_value(state,quest_id, variable, value): 
     49            print "Set %s to %i"%(variable,value) 
     50            state['quest'][quest_id].setValue(variable,value) 
     51 
     52        def meet(state, npc): 
     53            print "You've met %s!" % npc 
     54            state['pc'].meet(npc) 
     55 
     56        def get_stuff(state, thing): 
     57            if thing not in state['pc'].inventory: 
     58                state['pc'].inventory.add(thing) 
     59                print "You've now have the %s" % thing 
     60 
     61        def take_stuff(state,thing): 
     62            if thing in state['pc'].inventory: 
     63                state['pc'].inventory.remove(thing) 
     64                print "You no longer have the %s" % thing 
     65 
    4766        dialogue_callbacks = { 
     67            "complete_quest": complete_quest, 
     68            "decrease_value": decrease_value, 
     69            "delete_quest": delete_quest, 
     70            'end': self.handleEnd, 
     71            "get_stuff" : get_stuff, 
     72            "increase_value": increase_value, 
     73            "meet": meet, 
     74            'npc_avatar': self.handleAvatarImage, 
     75            'responses': self.handleResponses, 
    4876            'say': self.handleSay, 
    49             'responses': self.handleResponses, 
    50             'start_quest': self.startQuest, 
    51             'complete_quest': self.completeQuest, 
    52             'npc_avatar': self.handleAvatarImage, 
    53             'end': self.handleEnd 
     77            "set_value": set_value, 
     78            "start_quest": start_quest, 
     79            "take_stuff" : take_stuff 
    5480        } 
    5581 
    56         # For testing purposes we're just using a a dummy player object  here 
    57         # until we decide on a player/quest model. 
    58         # TODO 
    59         # link this up to the actual PC and NPC instances, so that state can 
    60         # be persistent. 
    61         pc = Player() 
    6282        self.npc = npc 
    6383        state = { 
    64             'pc': pc 
     84            'pc': self.pc, 
     85            'quest': quest_engine 
    6586        } 
    6687        self.dialogue_engine = DialogueEngine(npc.dialogue, 
    6788                                              dialogue_callbacks, state) 
    6889        self.dialogue_gui = pychan.loadXML("gui/dialogue.xml") 
    69  
    70     def startQuest(self, state, quest): 
    71         """Callback for starting a quest""" 
    72         print "You've picked up the '%s' quest!" % quest, 
    73         state['pc'].startQuest(quest) 
    74  
    75     def completeQuest(self, state, quest): 
    76         """Callback for starting a quest""" 
    77         print "You've finished the '%s' quest" % quest 
    78         state['pc'].completeQuest(quest) 
    7990 
    8091    def initiateDialogue(self): 
  • trunk/game/scripts/gamestate.py

    r356 r361  
    1717 
    1818from objects import base 
     19from scripts import quest_engine 
    1920 
    2021class GameState(object): 
     
    2324        """initialize attributes""" 
    2425        self.PC = None 
     26        self.quest_engine = quest_engine.QuestEngine() 
    2527        self.objects = {} 
    2628        self.current_map_file = None 
  • trunk/game/scripts/hud.py

    r360 r361  
    2929class Hud(object): 
    3030    """Main Hud class""" 
    31     def __init__(self, engine, settings, inv_model, callbacks): 
     31    def __init__(self, engine, settings, inv_model, data, callbacks): 
    3232        """Initialise the instance. 
    3333           @type engine: fife.Engine 
     
    4848        self.engine = engine 
    4949        self.settings = settings 
     50        self.data = data 
    5051 
    5152        inv_callbacks = { 
     
    617618           @param npc: the npc that we are having a dialogue with 
    618619           @return: None""" 
    619         dialogue = DialogueGUI(npc) 
     620        dialogue = DialogueGUI( 
     621                    npc, 
     622                    self.data.game_state.quest_engine, 
     623                    self.data.game_state.PC) 
    620624        dialogue.initiateDialogue() 
  • trunk/game/scripts/objects/actors.py

    r360 r361  
    118118         
    119119        # PC _has_ an inventory, he _is not_ one 
    120         self.inventory = None 
     120        self.inventory = set(('beer',)) 
     121        self.peopleIknow = set() 
    121122         
    122123        self.state = _AGENT_STATE_NONE 
     
    124125        self.createBehaviour(agent_layer) 
    125126     
     127    def meet(self, npc): 
     128        """Record that the PC has met a certain NPC 
     129        @type npc: str 
     130        @param npc: The NPC's name or id""" 
     131        if npc in self.peopleIknow: 
     132            raise RuntimeError("I already know %s" % npc) 
     133        self.peopleIknow.add(npc) 
     134 
     135    def met(self, npc): 
     136        """Indicate whether the PC has met this npc before 
     137        @type npc: str 
     138        @param npc: The NPC's name or id 
     139        @return: None""" 
     140        return npc in self.peopleIknow 
     141 
    126142    def createBehaviour(self, layer): 
    127         """ Creates the behaviour for this actor. 
     143        """Creates the behaviour for this actor. 
    128144            @return None """ 
    129145        self.behaviour = PCBehaviour(self, layer) 
     
    173189        l = fife.Location(self.behaviour.agent.getLocation()) 
    174190        l.setLayerCoordinates(fife.ModelCoordinate(*boxLocation)) 
    175         self.behaviour.agent.move('run', l, self.behaviour.speed) 
    176          
     191        self.behaviour.agent.move('run', l, self.behaviour.speed+1) 
     192 
    177193 
    178194class NPCBehaviour(ActorBehaviour): 
     
    205221            # rl = randint(-1, 1);ud = randint(-1, 1);x += rl;y += ud 
    206222        l = fife.Location(self.agent.getLocation()) 
    207         l.setLayerCoordinates(fife.ModelCoordinate(*tuple([x, y]))) 
     223        l.setLayerCoordinates(fife.ModelCoordinate(x, y)) 
    208224        return l 
    209225 
  • trunk/game/scripts/world.py

    r358 r361  
    5353        self.event_manager = engine.getEventManager() 
    5454        self.quitFunction = None 
    55          
     55 
    5656        # self.data is an engine.Engine object, but is set in run.py 
    5757        self.data = None 
     
    6262        self.maps = {} 
    6363 
     64        self.action_number = 1 
     65 
     66        # init the sound 
     67        self.sounds = SoundEngine(engine) 
     68 
     69        # don't force restart if skipping to new section 
     70        if TDS.readSetting("PlaySounds") == "1": 
     71            if not self.sounds.music_init: 
     72                self.sounds.playMusic("/music/preciouswasteland.ogg") 
     73 
     74        # The current highlighted object 
     75        self.highlight_obj = None 
     76         
     77        # Last saved mouse coords 
     78        self.last_mousecoords = None 
     79 
     80    def initHud(self): 
     81        """Initialize the hud member 
     82        @return: None""" 
    6483        # setup the inventory model 
    6584        # make slot 'A1' and 'A3' container daggers 
     
    7190            'quitGame': self.quitGame, 
    7291        } 
    73         self.hud = hud.Hud(self.engine, TDS, inv_model, hud_callbacks) 
    74         self.action_number = 1 
    75  
    76         # init the sound 
    77         self.sounds = SoundEngine(engine) 
    78          
    79         # don't force restart if skipping to new section 
    80         if (TDS.readSetting("PlaySounds") == "1"): 
    81             if(self.sounds.music_init == False): 
    82                 self.sounds.playMusic("/music/preciouswasteland.ogg") 
    83          
    84         #The current highlighted object 
    85         self.highlight_obj = None 
    86          
    87         #Last saved mouse coords 
    88         self.last_mousecoords = None 
     92        self.hud = hud.Hud(self.engine, TDS, inv_model, self.data, hud_callbacks) 
    8993     
    9094    def quitGame(self): 
     
    102106           @return: None""" 
    103107        self.data.load(*args, **kwargs) 
    104          
     108 
    105109    def loadMap(self, map_name, filename): 
    106110        """Loads a map and stores it under the given name in the maps list. 
    107111           @type map_name: String 
    108            @param map_name: The name of the map to load  
     112           @param map_name: The name of the map to load 
    109113           @type filename: String 
    110114           @param filename: File which contains the map to be loaded 
     
    112116        if not map_name in self.maps: 
    113117            map = Map(self.engine, self.data) 
    114             self.maps[map_name] = map         
     118            self.maps[map_name] = map 
    115119            map.load(filename) 
    116120        else: 
    117121            self.setActiveMap(map_name) 
    118      
     122 
    119123    def setActiveMap(self, map_name): 
    120124        """Sets the active map that is to be rendered. 
    121125           @type map_name: String 
    122            @param map_name: The name of the map to load  
     126           @param map_name: The name of the map to load 
    123127           @return: None""" 
    124128        # Turn off the camera on the old map before we turn on the camera 
     
    180184            # Escape brings up the main menu 
    181185            self.hud.displayMenu() 
    182             # Hide the quit menu  
     186            # Hide the quit menu 
    183187            self.hud.quit_window.hide() 
    184188        if(key_val == key.M): 
     
    195199        scr_point = fife.ScreenPoint(evt.getX(), evt.getY()) 
    196200        if(evt.getButton() == fife.MouseEvent.LEFT): 
    197             self.data.handleMouseClick(self.getCoords(scr_point))       
     201            self.data.handleMouseClick(self.getCoords(scr_point)) 
    198202        elif(evt.getButton() == fife.MouseEvent.RIGHT): 
    199203            # is there an object here? 
     
    204208            for inst in instances: 
    205209                # check to see if this is an active item 
    206                 if(self.data.objectActive(inst.getId())):             
     210                if(self.data.objectActive(inst.getId())): 
    207211                    # yes, get the data 
    208212                    info = self.data.getItemActions(inst.getId()) 
    209213                    break 
    210                  
     214 
    211215            # take the menu items returned by the engine or show a 
    212             # default menu if no items     
     216            # default menu if no items 
    213217            data = info or \ 
    214218                [["Walk", "Walk here", self.onWalk, self.getCoords(scr_point)]] 
     
    281285                # check to see if this in our list at all 
    282286                if(self.data.objectActive(obj.getId())): 
    283                     # check if the object is on the foreground  
     287                    # check if the object is on the foreground 
    284288                    obj_map_coords = \ 
    285289                                      obj.getLocation().getMapCoordinates() 
     
    287291                        cameras[self.active_map.my_cam_id]\ 
    288292                        .toScreenCoordinates(obj_map_coords) 
    289                      
     293 
    290294                    if obj_screen_coords.y > front_y: 
    291295                        #Object on the foreground 
     
    309313        location.setMapCoordinates(coord) 
    310314        return location 
    311      
     315 
    312316    def deleteMaps(self): 
    313317        """Clear all currently loaded maps from FIFE as well as clear our 
Note: See TracChangeset for help on using the changeset viewer.