X-Git-Url: https://harishankar.org/repos/?p=butaba-adventures.git;a=blobdiff_plain;f=utility.py;h=f115374cfa0381c6fe50947cf70859910b5c9cc1;hp=5d8c45d0e3e24bbbe6c95ffcc066c4212d7489dc;hb=63f74206e69c1147ed006ccadb359fc6e21fefbb;hpb=7dbb8e9b6766b7c0c17433bea3c88a321036b837 diff --git a/utility.py b/utility.py index 5d8c45d..f115374 100644 --- a/utility.py +++ b/utility.py @@ -1,29 +1,267 @@ # utility functions for the game 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_portrait=None, + 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" + reply_mode = False + current_resp = convtree[dlg_id][1][0][1] + + while 1: + screen.blit (bgscreen, (leftedge, topedge)) + + # a dialgoue ID of 0 always exits the conversation + # return the unique response ID + if dlg_id == "0": + return current_resp + + # not reply mode + if reply_mode is False: + 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) + elif event.type == pygame.KEYDOWN: + # now continue the dialog + if event.key == pygame.K_RETURN or event.key == pygame.K_SPACE: + reply_mode = True + current_resp = convtree[dlg_id][1][0][1] + sel = 0 + # reply mode + else: + if responder_portrait is not None: + screen.blit (responder_portrait, (leftedge, topedge)) + + lines = [] + for resptext, respid, nextdlgid in convtree[dlg_id][1]: + if respid == current_resp: + lines.append ((10, 255, 0, 0, resptext)) + else: + lines.append ((10, 0, 0, 0, resptext)) + + 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) + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_UP or event.key == pygame.K_LEFT: + sel -= 1 + if sel < 0: + sel = 0 + current_resp = convtree[dlg_id][1][sel][1] + elif event.key == pygame.K_DOWN or event.key == pygame.K_RIGHT: + sel += 1 + if sel >= len (convtree[dlg_id][1]): + sel = len(convtree[dlg_id][1]) - 1 + current_resp = convtree[dlg_id][1][sel][1] + + elif event.key == pygame.K_RETURN or event.key == pygame.K_SPACE: + dlg_id = convtree[dlg_id][1][sel][2] + reply_mode = False + +# 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") + speech = dlg.find ("speech").text + responses = [] + for resp in dlg.findall ("response"): + responses.append ((resp.text, resp.get ("id"), resp.get ("nextdialogue"))) + + convtree[id] = (speech, responses) + + + return convtree + # function to draw text on surface def put_text (surface, x, y, size, (r,g,b), text): - harisfont = os.path.join ("font", "HarisComic-2.ttf") + harisfont = os.path.join ("font", "harisgamefont.ttf") 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 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") + for size, r, g, b, text in text_lines: + s = pygame.font.Font (harisfont, size).render (text, True, pygame.Color (r,g,b)) + # add spacing + height = height + s.get_height()*1.5 + textsurfs.append (s) + + i = 0 + # 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): - pygame.draw.rect (surface, pygame.Color (255, 255, 128), pygame.Rect (40, 40, 480-40, 480-40)) +def ask_question (surface, question, answers, bgscreen): + + sel_answer = 1 + + while 1: + textarray = [ [ 10, 128, 0, 0, question ] ] + + i = 1 + for answer in answers: + if sel_answer == i: + r, g, b = 255, 0, 0 + else: + r, g, b = 0, 0, 0 + textarray.append ( [10, r, g, b, answer] ) - put_text (surface, 60, 60, 22, (0, 0, 192), question) + i += 1 - i = 1 - for answer in answers: - put_text (surface, 60, i*20+60, 22, (0, 0, 128), "%d" % i) - put_text (surface, 80, i*20+60, 22, (0, 0, 0), answer) + surface.blit (bgscreen, (surface.get_width()/2 - bgscreen.get_width()/2, + surface.get_height()/2 - bgscreen.get_height()/2)) + 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 () + + for event in pygame.event.get (): + if event.type == pygame.QUIT: + sys.exit (0) + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_UP: + sel_answer -= 1 + if sel_answer < 1: + sel_answer = 1 + elif event.key == pygame.K_DOWN: + sel_answer += 1 + if sel_answer > len(answers): + sel_answer = len(answers) + elif event.key == pygame.K_RETURN: + return sel_answer + +# function displaying the contents of a container. Object must contain +# items list +# edgewidth - container edges to avoid drawing items in +def get_container_object (surface, obj, bgimage, edgewidth=0): + + # get the number of items + numitems = len (obj.objects) + # number of rows + num_rows = (bgimage.get_height () - edgewidth*2) / 48 + # number of cols + num_cols = (bgimage.get_width () - edgewidth*2) / 48 + + objposx = surface.get_width()/2 - bgimage.get_width()/2 + objposy = surface.get_height()/2 - bgimage.get_height()/2 + + selitem = 0 + selrow = 0 + selcol = 0 while 1: + # display the background for the container + surface.blit (bgimage, (objposx, objposy)) + + # display each item in the container + i = 0 + j = 0 + + # display all the items in container + for item in obj.objects: + surface.blit (item.image, (objposx + edgewidth+ j*48, objposy + edgewidth + i*48)) + j += 1 + if j >= num_cols: + j = 0 + i += 1 + # only draw selector if there is at least one item + if numitems > 0: + pygame.draw.rect (surface, pygame.Color (255,255,255), + pygame.Rect(objposx + edgewidth + selcol*48, objposy + edgewidth + selrow*48, 48, 48), 1) + + pygame.display.update () + + # get events for event in pygame.event.get (): if event.type == pygame.QUIT: sys.exit (0) elif event.type == pygame.KEYDOWN: - print event.key + if event.key == pygame.K_ESCAPE: + return None + elif event.key == pygame.K_RETURN: + if numitems > 0 and selitem >= 0 and selitem < numitems: + return obj.objects[selitem] + else: + return None + elif event.key == pygame.K_UP or event.key == pygame.K_LEFT: + # go to the prev item + selitem -= 1 + if selitem < 0: + selitem = numitems - 1 + selrow = selitem / num_cols + selcol = selitem % num_cols + + elif event.key == pygame.K_DOWN or event.key == pygame.K_RIGHT: + # go to the next item + selitem += 1 + if selitem > numitems - 1: + selitem = 0 + selrow = selitem / num_cols + selcol = selitem % num_cols