93dac190dba2d7a9d99fa1a10f1e392eadcd17c7
[butaba-adventures.git] / utility.py
1 # utility functions for the game
2 import pygame
3 import sys
4 import os.path
5 import xml.etree.cElementTree as ET
6 import textwrap
7
8 # function to run through an interactive dialogue and return the response ID
9 def dialogue_play (screen, bgscreen, npc, responder,
10 marginleft=0, margintop=0, marginright=0, marginbottom=0):
11
12 # first check if NPC has a dialogue at all
13 if len (npc.dialogues) == 0 or npc.currentdialog >= len (npc.dialogues):
14 return None
15
16 # get the conversation as a dictionary
17 convtree = xml_to_dict (npc.dialogues[npc.currentdialog])
18
19 scrwidth = screen.get_width ()
20 scrheight = screen.get_height ()
21 bgwidth = bgscreen.get_width ()
22 bgheight = bgscreen.get_height ()
23 leftedge = scrwidth/2 - bgwidth/2
24 topedge = scrheight/2 - bgheight/2
25
26 # now initiate the conversation
27 dlg_id = "1"
28 while 1:
29 screen.blit (bgscreen, (leftedge, topedge))
30 if npc.portrait is not None:
31 screen.blit (npc.portrait, (leftedge, topedge))
32
33 # get the lines to display wrapped using textwrap module
34 lines = []
35 textnpc = textwrap.wrap (convtree[dlg_id][0], 40)
36 for text in textnpc:
37 lines.append ((10, 0, 0, 0, text))
38
39 put_lines (screen, lines,
40 pygame.Rect(leftedge+marginleft, topedge+margintop,
41 bgwidth-marginleft-marginright, bgheight-margintop-marginbottom))
42 pygame.display.update ()
43
44 for event in pygame.event.get ():
45 if event.type == pygame.QUIT:
46 sys.exit (0)
47
48 # function to parse a conversation XML into a python dictionary
49 def xml_to_dict (file):
50 # parse the dialogue XML file
51 dlgtree = ET.parse (file)
52 # get the root element
53 conversation = dlgtree.getroot ()
54
55 # build the conversation tree as a dictionary
56 convtree = dict ()
57 for dlg in conversation.findall ("dialogue"):
58 id = dlg.get ("id")
59 convtree[id] = []
60 convtree[id].append (dlg.find ("speech").text)
61 for resp in dlg.findall ("response"):
62 convtree[id].append ((resp.text, resp.get ("id"), resp.get ("nextdialogue")))
63
64 return convtree
65
66
67 # function to draw text on surface
68 def put_text (surface, x, y, size, (r,g,b), text):
69 harisfont = os.path.join ("font", "harisgamefont.ttf")
70 textsurf = pygame.font.Font (harisfont, size).render (text, True, pygame.Color (r,g,b))
71 surface.blit (textsurf, (x, y))
72
73 # function to draw several lines of text, centered horizontally and vertically on screen
74 # or drawn centered on a rectangle
75 def put_lines (surface, text_lines, rect=None):
76 textsurfs = []
77 height = 0
78 harisfont = os.path.join ("font", "harisgamefont.ttf")
79
80 for size, r, g, b, text in text_lines:
81 s = pygame.font.Font (harisfont, size).render (text, True, pygame.Color (r,g,b))
82 # add spacing
83 height = height + s.get_height()*1.5
84 textsurfs.append (s)
85
86 i = 0
87 # if no rectangle specified, center in screen
88 if rect is None:
89 scrwidth = surface.get_width ()
90 scrheight = surface.get_height ()
91
92 for s in textsurfs:
93 surface.blit (s, (scrwidth/2 - s.get_width()/2, scrheight/2 - height/2+ i* (s.get_height()*1.5)))
94 i += 1
95 # center on specified rectangular region
96 else:
97 midx = (rect.left + rect.right)/2
98 midy = (rect.top + rect.bottom)/2
99 num = len (textsurfs) / 2
100 for s in textsurfs:
101 surface.blit (s, (midx - s.get_width()/2, midy - (num-i) * s.get_height() * 3/2))
102 i += 1
103
104 # function to ask a question and return answer
105 def ask_question (surface, question, answers, bgscreen):
106
107 sel_answer = 1
108
109 while 1:
110 textarray = [ [ 10, 128, 0, 0, question ] ]
111
112 i = 1
113 for answer in answers:
114 if sel_answer == i:
115 r, g, b = 255, 0, 0
116 else:
117 r, g, b = 0, 0, 0
118 textarray.append ( [10, r, g, b, answer] )
119
120 i += 1
121
122 surface.blit (bgscreen, (surface.get_width()/2 - bgscreen.get_width()/2,
123 surface.get_height()/2 - bgscreen.get_height()/2))
124 put_lines (surface, textarray, pygame.Rect (surface.get_width()/2 - bgscreen.get_width()/2,
125 surface.get_height()/2 - bgscreen.get_height()/2,
126 bgscreen.get_width(), bgscreen.get_height()))
127
128 pygame.display.update ()
129
130 for event in pygame.event.get ():
131 if event.type == pygame.QUIT:
132 sys.exit (0)
133 elif event.type == pygame.KEYDOWN:
134 if event.key == pygame.K_UP:
135 sel_answer -= 1
136 if sel_answer < 1:
137 sel_answer = 1
138 elif event.key == pygame.K_DOWN:
139 sel_answer += 1
140 if sel_answer > len(answers):
141 sel_answer = len(answers)
142 elif event.key == pygame.K_RETURN:
143 return sel_answer
144
145 # function displaying the contents of a container. Object must contain
146 # items list
147 # edgewidth - container edges to avoid drawing items in
148 def get_container_object (surface, obj, bgimage, edgewidth=0):
149
150 # get the number of items
151 numitems = len (obj.objects)
152 # number of rows
153 num_rows = (bgimage.get_height () - edgewidth*2) / 48
154 # number of cols
155 num_cols = (bgimage.get_width () - edgewidth*2) / 48
156
157 objposx = surface.get_width()/2 - bgimage.get_width()/2
158 objposy = surface.get_height()/2 - bgimage.get_height()/2
159
160 selitem = 0
161 selrow = 0
162 selcol = 0
163
164 while 1:
165 # display the background for the container
166 surface.blit (bgimage, (objposx, objposy))
167
168 # display each item in the container
169 i = 0
170 j = 0
171
172 # display all the items in container
173 for item in obj.objects:
174 surface.blit (item.image, (objposx + edgewidth+ j*48, objposy + edgewidth + i*48))
175 j += 1
176 if j >= num_cols:
177 j = 0
178 i += 1
179 # only draw selector if there is at least one item
180 if numitems > 0:
181 pygame.draw.rect (surface, pygame.Color (255,255,255),
182 pygame.Rect(objposx + edgewidth + selcol*48, objposy + edgewidth + selrow*48, 48, 48), 1)
183
184 pygame.display.update ()
185
186 # get events
187 for event in pygame.event.get ():
188 if event.type == pygame.QUIT:
189 sys.exit (0)
190 elif event.type == pygame.KEYDOWN:
191 if event.key == pygame.K_ESCAPE:
192 return None
193 elif event.key == pygame.K_RETURN:
194 if numitems > 0 and selitem >= 0 and selitem < numitems:
195 return obj.objects[selitem]
196 else:
197 return None
198 elif event.key == pygame.K_UP or event.key == pygame.K_LEFT:
199 # go to the prev item
200 selitem -= 1
201 if selitem < 0:
202 selitem = numitems - 1
203 selrow = selitem / num_cols
204 selcol = selitem % num_cols
205
206 elif event.key == pygame.K_DOWN or event.key == pygame.K_RIGHT:
207 # go to the next item
208 selitem += 1
209 if selitem > numitems - 1:
210 selitem = 0
211 selrow = selitem / num_cols
212 selcol = selitem % num_cols