From: Harishankar Date: Wed, 5 Oct 2011 05:18:13 +0000 (+0530) Subject: Started work on NPC dialogues X-Git-Url: https://harishankar.org/repos/?p=butaba-adventures.git;a=commitdiff_plain;h=8d8c32fdbd61956ccc4792524b621524d83b0467 Started work on NPC dialogues Started basic work on NPC dialogues. Created the NPC dialogue screen and successfully displayed text. --- diff --git a/background/dialog_screen.png b/background/dialog_screen.png new file mode 100644 index 0000000..2194d96 Binary files /dev/null and b/background/dialog_screen.png differ diff --git a/butaba.py b/butaba.py index 7b93980..ca44883 100644 --- a/butaba.py +++ b/butaba.py @@ -20,4 +20,3 @@ class Butaba: self.health = health self.objects = inventory self.gold = gold - diff --git a/dialogues/bulisa1.dlg b/dialogues/bulisa1.dlg index c5db25b..e684042 100644 --- a/dialogues/bulisa1.dlg +++ b/dialogues/bulisa1.dlg @@ -28,8 +28,7 @@ Bye! - Thanks so much! There is an empty bucket somewhere in the garden. - Take that, go to the well behind the house, draw water and bring it back to me. + Thanks so much! There is an empty bucket somewhere in the garden. Take that, go to the well behind the house, draw water and bring it back to me. Right. I'll go at once. \ No newline at end of file diff --git a/maingame.py b/maingame.py index 431d44d..32df4cc 100644 --- a/maingame.py +++ b/maingame.py @@ -28,6 +28,9 @@ class MainGame: self.img_chestbg = pygame.image.load (os.path.join ("background", "chestcontent.png")).convert () + self.img_dialogue = pygame.image.load (os.path.join ("background", "dialog_screen.png")).convert () + self.img_dialogue.set_colorkey (pygame.Color (0, 255, 0)) + # initialize object graphics self.img_redpotion = pygame.image.load (os.path.join ("objects", "red-potion.png")).convert () @@ -61,6 +64,9 @@ class MainGame: self.img_bulisa = pygame.image.load (os.path.join ("sprite", "bulisa.png")).convert () self.img_bulisa.set_colorkey (pygame.Color (0, 255, 0)) + # initialize NPC portraits + self.img_bulisa_portrait = pygame.image.load (os.path.join ("portraits", "bulisa.png")).convert () + # set level data self.setup_levels () # set current level and position of our character @@ -85,7 +91,8 @@ class MainGame: potion2 = gameobjects.HealthPotion (5, 2, self.img_redpotion) potion3 = gameobjects.HealthPotion (5, 2, self.img_redpotion) - npc_bulisa = npcs.Bulisa (4, 3, self.img_bulisa, None) + npc_bulisa = npcs.Bulisa (4, 3, self.img_bulisa, self.img_bulisa_portrait, + [ os.path.join ("dialogues", "bulisa1.dlg") ]) chest1.objects = [ gold50, gold25, potion2, potion3, key2, gold10 ] @@ -247,7 +254,12 @@ class MainGame: # interaction with npcs def interact_npc (self, npc): - pass + # interact with NPC and get the response ID + resp_id = utility.dialogue_play (self.screen, self.img_dialogue, npc, self.butaba, 0, 90) + + # if none + if resp_id is None: + self.status_message = "You cannot initiate a conversation with %s" % npc.charname # interaction with objects def interact_objects (self, container, objs): diff --git a/npcs.py b/npcs.py index ae781da..d368833 100644 --- a/npcs.py +++ b/npcs.py @@ -6,7 +6,7 @@ import os.path class NPC: # initalize the NPC - def __init__ (self, charname, row, col, image=None, portrait=None, dialogue_set=set(), + def __init__ (self, charname, row, col, image=None, portrait=None, dialogues=[], currentdialog=0, is_dead=False): # name of the character self.charname = charname @@ -19,7 +19,7 @@ class NPC: self.portrait = portrait # dialogue set for NPC # each dialogue in the set is a path to an XML file containing the dialogue - self.dialogue_set = dialogue_set + self.dialogues = dialogues # index of the current dialogue which will be initiated with the main # character self.currentdialog = currentdialog @@ -29,6 +29,6 @@ class NPC: # Bulisa is Butaba's friend class Bulisa (NPC): - def __init__ (self, row, col, image, portrait, dialogue_set=set(), currentdialog=0): - NPC.__init__ (self, "Bulisa", row, col, image, portrait, dialogue_set, currentdialog) + def __init__ (self, row, col, image, portrait, dialogues=[], currentdialog=0): + NPC.__init__ (self, "Bulisa", row, col, image, portrait, dialogues, currentdialog) diff --git a/portraits/bulisa.png b/portraits/bulisa.png new file mode 100644 index 0000000..f8f7a97 Binary files /dev/null and b/portraits/bulisa.png differ diff --git a/utility.py b/utility.py index 05faab5..93dac19 100644 --- a/utility.py +++ b/utility.py @@ -2,6 +2,67 @@ import pygame import sys import os.path +import xml.etree.cElementTree as ET +import textwrap + +# function to run through an interactive dialogue and return the response ID +def dialogue_play (screen, bgscreen, npc, responder, + marginleft=0, margintop=0, marginright=0, marginbottom=0): + + # first check if NPC has a dialogue at all + if len (npc.dialogues) == 0 or npc.currentdialog >= len (npc.dialogues): + return None + + # get the conversation as a dictionary + convtree = xml_to_dict (npc.dialogues[npc.currentdialog]) + + scrwidth = screen.get_width () + scrheight = screen.get_height () + bgwidth = bgscreen.get_width () + bgheight = bgscreen.get_height () + leftedge = scrwidth/2 - bgwidth/2 + topedge = scrheight/2 - bgheight/2 + + # now initiate the conversation + dlg_id = "1" + while 1: + screen.blit (bgscreen, (leftedge, topedge)) + if npc.portrait is not None: + screen.blit (npc.portrait, (leftedge, topedge)) + + # get the lines to display wrapped using textwrap module + lines = [] + textnpc = textwrap.wrap (convtree[dlg_id][0], 40) + for text in textnpc: + lines.append ((10, 0, 0, 0, text)) + + put_lines (screen, lines, + pygame.Rect(leftedge+marginleft, topedge+margintop, + bgwidth-marginleft-marginright, bgheight-margintop-marginbottom)) + pygame.display.update () + + for event in pygame.event.get (): + if event.type == pygame.QUIT: + sys.exit (0) + +# function to parse a conversation XML into a python dictionary +def xml_to_dict (file): + # parse the dialogue XML file + dlgtree = ET.parse (file) + # get the root element + conversation = dlgtree.getroot () + + # build the conversation tree as a dictionary + convtree = dict () + for dlg in conversation.findall ("dialogue"): + id = dlg.get ("id") + convtree[id] = [] + convtree[id].append (dlg.find ("speech").text) + for resp in dlg.findall ("response"): + convtree[id].append ((resp.text, resp.get ("id"), resp.get ("nextdialogue"))) + + return convtree + # function to draw text on surface def put_text (surface, x, y, size, (r,g,b), text): @@ -9,8 +70,9 @@ def put_text (surface, x, y, size, (r,g,b), text): textsurf = pygame.font.Font (harisfont, size).render (text, True, pygame.Color (r,g,b)) surface.blit (textsurf, (x, y)) -# function to draw several lines of text, centered horizontally and vertically on surface -def put_lines (surface, text_lines): +# function to draw several lines of text, centered horizontally and vertically on screen +# or drawn centered on a rectangle +def put_lines (surface, text_lines, rect=None): textsurfs = [] height = 0 harisfont = os.path.join ("font", "harisgamefont.ttf") @@ -21,12 +83,23 @@ def put_lines (surface, text_lines): height = height + s.get_height()*1.5 textsurfs.append (s) - scrwidth = surface.get_width () - scrheight = surface.get_height () i = 0 - for s in textsurfs: - surface.blit (s, (scrwidth/2 - s.get_width()/2, scrheight/2 - height/2+ i* (s.get_height()*1.5))) - i += 1 + # if no rectangle specified, center in screen + if rect is None: + scrwidth = surface.get_width () + scrheight = surface.get_height () + + for s in textsurfs: + surface.blit (s, (scrwidth/2 - s.get_width()/2, scrheight/2 - height/2+ i* (s.get_height()*1.5))) + i += 1 + # center on specified rectangular region + else: + midx = (rect.left + rect.right)/2 + midy = (rect.top + rect.bottom)/2 + num = len (textsurfs) / 2 + for s in textsurfs: + surface.blit (s, (midx - s.get_width()/2, midy - (num-i) * s.get_height() * 3/2)) + i += 1 # function to ask a question and return answer def ask_question (surface, question, answers, bgscreen): @@ -48,7 +121,9 @@ def ask_question (surface, question, answers, bgscreen): surface.blit (bgscreen, (surface.get_width()/2 - bgscreen.get_width()/2, surface.get_height()/2 - bgscreen.get_height()/2)) - put_lines (surface, textarray) + put_lines (surface, textarray, pygame.Rect (surface.get_width()/2 - bgscreen.get_width()/2, + surface.get_height()/2 - bgscreen.get_height()/2, + bgscreen.get_width(), bgscreen.get_height())) pygame.display.update ()