data/shopgui.py (view raw)
1"""
2This class controls the textbox GUI for any shop state.
3A Gui object is created and updated by the shop state.
4"""
5
6import pygame as pg
7from . import setup
8from . components import textbox
9from . import constants as c
10
11
12class Gui(object):
13 """Class that controls the GUI of the shop state"""
14 def __init__(self, level):
15 self.level = level
16 self.game_data = self.level.game_data
17 self.level.game_data['last direction'] = 'down'
18 self.sellable_items = level.sell_items
19 self.player_inventory = level.game_data['player inventory']
20 self.name = level.name
21 self.state = 'dialogue'
22 self.no_selling = ['Inn', 'Magic Shop']
23 self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
24 self.index = 0
25 self.timer = 0.0
26 self.allow_input = False
27 self.items = level.items
28 self.item_to_be_sold = None
29 self.item_to_be_purchased = None
30 self.dialogue = level.dialogue
31 self.accept_dialogue = level.accept_dialogue
32 self.accept_sale_dialogue = level.accept_sale_dialogue
33 self.arrow = textbox.NextArrow()
34 self.selection_arrow = textbox.NextArrow()
35 self.arrow_pos1 = (50, 475)
36 self.arrow_pos2 = (50, 515)
37 self.arrow_pos3 = (50, 555)
38 self.arrow_pos4 = (50, 495)
39 self.arrow_pos5 = (50, 535)
40 self.arrow_pos_list = [self.arrow_pos1, self.arrow_pos2, self.arrow_pos3]
41 self.two_arrow_pos_list = [self.arrow_pos4, self.arrow_pos5]
42 self.arrow_index = 0
43 self.selection_arrow.rect.topleft = self.arrow_pos1
44 self.dialogue_box = self.make_dialogue_box(self.dialogue, self.index)
45 self.gold_box = self.make_gold_box()
46 if self.name in self.no_selling:
47 choices = self.items[0]['dialogue']
48 else:
49 choices = ['Buy', 'Sell', 'Leave']
50 self.selection_box = self.make_selection_box(choices)
51 self.state_dict = self.make_state_dict()
52
53
54
55 def make_dialogue_box(self, dialogue_list, index):
56 """Make the sprite that controls the dialogue"""
57 image = setup.GFX['dialoguebox']
58 rect = image.get_rect()
59 surface = pg.Surface(rect.size)
60 surface.set_colorkey(c.BLACK)
61 surface.blit(image, rect)
62 dialogue = self.font.render(dialogue_list[index],
63 True,
64 c.NEAR_BLACK)
65 dialogue_rect = dialogue.get_rect(left=50, top=50)
66 surface.blit(dialogue, dialogue_rect)
67 sprite = pg.sprite.Sprite()
68 sprite.image = surface
69 sprite.rect = rect
70 self.check_to_draw_arrow(sprite)
71
72 return sprite
73
74
75 def check_to_draw_arrow(self, sprite):
76 """Blink arrow if more text needs to be read"""
77 if self.index < len(self.dialogue) - 1:
78 sprite.image.blit(self.arrow.image, self.arrow.rect)
79
80
81 def make_gold_box(self):
82 """Make the box to display total gold"""
83 image = setup.GFX['goldbox']
84 rect = image.get_rect(bottom=608, right=800)
85
86 surface = pg.Surface(rect.size)
87 surface.set_colorkey(c.BLACK)
88 surface.blit(image, (0, 0))
89 gold = self.player_inventory['GOLD']['quantity']
90 text = 'Gold: ' + str(gold)
91 text_render = self.font.render(text, True, c.NEAR_BLACK)
92 text_rect = text_render.get_rect(x=80, y=60)
93
94 surface.blit(text_render, text_rect)
95
96 sprite = pg.sprite.Sprite()
97 sprite.image = surface
98 sprite.rect = rect
99
100 return sprite
101
102
103 def make_selection_box(self, choices):
104 """Make the box for the player to select options"""
105 image = setup.GFX['shopbox']
106 rect = image.get_rect(bottom=608)
107
108 surface = pg.Surface(rect.size)
109 surface.set_colorkey(c.BLACK)
110 surface.blit(image, (0, 0))
111
112 if len(choices) == 2:
113 choice1 = self.font.render(choices[0], True, c.NEAR_BLACK)
114 choice1_rect = choice1.get_rect(x=200, y=35)
115 choice2 = self.font.render(choices[1], True, c.NEAR_BLACK)
116 choice2_rect = choice2.get_rect(x=200, y=75)
117
118 surface.blit(choice1, choice1_rect)
119 surface.blit(choice2, choice2_rect)
120
121 elif len(choices) == 3:
122 choice1 = self.font.render(choices[0], True, c.NEAR_BLACK)
123 choice1_rect = choice1.get_rect(x=200, y=15)
124 choice2 = self.font.render(choices[1], True, c.NEAR_BLACK)
125 choice2_rect = choice2.get_rect(x=200, y=55)
126 choice3 = self.font.render(choices[2], True, c.NEAR_BLACK)
127 choice3_rect = choice3.get_rect(x=200, y=95)
128
129 surface.blit(choice1, choice1_rect)
130 surface.blit(choice2, choice2_rect)
131 surface.blit(choice3, choice3_rect)
132
133 sprite = pg.sprite.Sprite()
134 sprite.image = surface
135 sprite.rect = rect
136
137 return sprite
138
139
140 def make_state_dict(self):
141 """Make the state dictionary for the GUI behavior"""
142 state_dict = {'dialogue': self.control_dialogue,
143 'select': self.make_selection,
144 'confirmpurchase': self.confirm_purchase,
145 'confirmsell': self.confirm_sell,
146 'reject': self.reject_insufficient_gold,
147 'accept': self.accept_purchase,
148 'acceptsell': self.accept_sale,
149 'hasitem': self.has_item,
150 'buysell': self.buy_sell,
151 'sell': self.sell_items,
152 'cantsell': self.cant_sell}
153
154 return state_dict
155
156
157 def control_dialogue(self, keys, current_time):
158 """Control the dialogue boxes"""
159 self.dialogue_box = self.make_dialogue_box(self.dialogue, self.index)
160
161 if self.index < (len(self.dialogue) - 1) and self.allow_input:
162 if keys[pg.K_SPACE]:
163 self.index += 1
164 self.allow_input = False
165
166 if self.index == (len(self.dialogue) - 1):
167 self.state = self.begin_new_transaction()
168
169 if not keys[pg.K_SPACE]:
170 self.allow_input = True
171
172
173 def begin_new_transaction(self):
174 """Set state to buysell or select, depending if the shop
175 is a Inn/Magic shop or not"""
176 if self.level.name in self.no_selling:
177 state = 'select'
178 else:
179 state = 'buysell'
180
181 return state
182
183
184 def make_selection(self, keys, current_time):
185 """Control the selection"""
186 choices = []
187 for item in self.items:
188 choices.append(item['dialogue'])
189 if self.name in self.no_selling:
190 choices.append('Leave')
191 else:
192 choices.append('Cancel')
193 self.dialogue_box = self.make_dialogue_box(self.dialogue, self.index)
194 self.selection_box = self.make_selection_box(choices)
195 self.gold_box = self.make_gold_box()
196
197 if len(choices) == 2:
198 arrow_list = self.two_arrow_pos_list
199 elif len(choices) == 3:
200 arrow_list = self.arrow_pos_list
201 else:
202 arrow_list = None
203 AssertionError('Only two items supported')
204
205 self.selection_arrow.rect.topleft = arrow_list[self.arrow_index]
206
207
208 if keys[pg.K_DOWN] and self.allow_input:
209 if self.arrow_index < (len(choices) - 1):
210 self.arrow_index += 1
211 self.allow_input = False
212 elif keys[pg.K_UP] and self.allow_input:
213 if self.arrow_index > 0:
214 self.arrow_index -= 1
215 self.allow_input = False
216 elif keys[pg.K_SPACE] and self.allow_input:
217 if self.arrow_index == 0:
218 self.state = 'confirmpurchase'
219 self.item_to_be_purchased = self.items[0]
220
221 elif self.arrow_index == 1 and len(choices) == 3:
222 self.state = 'confirmpurchase'
223 self.item_to_be_purchased = self.items[1]
224
225 else:
226 if self.level.name in self.no_selling:
227 self.level.done = True
228 self.game_data['last state'] = self.level.name
229 else:
230 self.state = 'buysell'
231
232 self.arrow_index = 0
233 self.allow_input = False
234
235 if not keys[pg.K_SPACE] and not keys[pg.K_UP] and not keys[pg.K_DOWN]:
236 self.allow_input = True
237
238
239
240 def confirm_purchase(self, keys, current_time):
241 """Confirm selection state for GUI"""
242 dialogue = ['Are you sure?']
243 choices = ['Yes', 'No']
244 self.selection_box = self.make_selection_box(choices)
245 self.gold_box = self.make_gold_box()
246 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
247 self.selection_arrow.rect.topleft = self.two_arrow_pos_list[self.arrow_index]
248
249 if keys[pg.K_DOWN] and self.allow_input:
250 if self.arrow_index < (len(choices) - 1):
251 self.arrow_index += 1
252 self.allow_input = False
253 elif keys[pg.K_UP] and self.allow_input:
254 if self.arrow_index > 0:
255 self.arrow_index -= 1
256 self.allow_input = False
257 elif keys[pg.K_SPACE] and self.allow_input:
258 if self.arrow_index == 0:
259 self.buy_item()
260 elif self.arrow_index == 1:
261 self.state = self.begin_new_transaction()
262 self.arrow_index = 0
263 self.allow_input = False
264
265 if not keys[pg.K_SPACE] and not keys[pg.K_DOWN] and not keys[pg.K_UP]:
266 self.allow_input = True
267
268
269 def buy_item(self):
270 """Attempt to allow player to purchase item"""
271 item = self.item_to_be_purchased
272
273 self.player_inventory['GOLD']['quantity'] -= item['price']
274
275 if self.player_inventory['GOLD']['quantity'] < 0:
276 self.player_inventory['GOLD']['quantity'] += item['price']
277 self.state = 'reject'
278 else:
279 if (item['type'] in self.player_inventory and
280 self.name == c.MAGIC_SHOP):
281 self.state = 'hasitem'
282 self.player_inventory['GOLD']['quantity'] += item['price']
283 else:
284 self.state = 'accept'
285 self.add_player_item(item)
286
287
288 def add_player_item(self, item):
289 """Add item to player's inventory"""
290 item_type = item['type']
291 quantity = item['quantity']
292 value = item['price']
293 magic_list = ['Cure', 'Fire Blast']
294 player_items = self.level.game_data['player inventory']
295 player_health = self.level.game_data['player stats']['health']
296 player_magic = self.level.game_data['player stats']['magic points']
297
298 item_to_add = {'quantity': quantity,
299 'value': value}
300
301 if item_type in magic_list:
302 item_to_add = {'magic points': item['magic points'],
303 'power': item['power']}
304 player_items[item_type] = item_to_add
305 elif item_type in player_items:
306 player_items[item_type]['quantity'] += quantity
307 elif quantity > 0:
308 player_items[item_type] = item_to_add
309 elif item_type == 'room':
310 player_health['current'] = player_health['maximum']
311 player_magic['current'] = player_magic['maximum']
312
313
314 def confirm_sell(self, keys, current_time):
315 """Confirm player wants to sell item"""
316 dialogue = ['Are you sure?']
317 choices = ['Yes', 'No']
318 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
319 self.selection_box = self.make_selection_box(choices)
320 self.selection_arrow.rect.topleft = self.two_arrow_pos_list[self.arrow_index]
321
322 if keys[pg.K_DOWN] and self.allow_input:
323 if self.arrow_index < (len(choices) - 1):
324 self.arrow_index += 1
325 self.allow_input = False
326 elif keys[pg.K_UP] and self.allow_input:
327 if self.arrow_index > 0:
328 self.arrow_index -= 1
329 self.allow_input = False
330 elif keys[pg.K_SPACE] and self.allow_input:
331 if self.arrow_index == 0:
332 self.sell_item_from_inventory()
333 elif self.arrow_index == 1:
334 self.state = self.begin_new_transaction()
335 self.allow_input = False
336 self.arrow_index = 0
337
338 if not keys[pg.K_SPACE] and not keys[pg.K_UP] and not keys[pg.K_DOWN]:
339 self.allow_input = True
340
341
342 def sell_item_from_inventory(self):
343 """Allow player to sell item to shop"""
344 item_price = self.item_to_be_sold['price']
345 item_name = self.item_to_be_sold['type']
346 self.player_inventory['gold'] += (item_price / 2)
347 self.state = 'acceptsell'
348 if self.player_inventory[item_name]['quantity'] > 1:
349 self.player_inventory[item_name]['quantity'] -= 1
350 else:
351 del self.player_inventory[self.item_to_be_sold['type']]
352
353
354 def reject_insufficient_gold(self, keys, current_time):
355 """Reject player selection if they do not have enough gold"""
356 dialogue = ["You don't have enough gold!"]
357 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
358
359 if keys[pg.K_SPACE] and self.allow_input:
360 self.state = self.begin_new_transaction()
361 self.selection_arrow.rect.topleft = self.arrow_pos1
362 self.allow_input = False
363
364 if not keys[pg.K_SPACE]:
365 self.allow_input = True
366
367
368 def accept_purchase(self, keys, current_time):
369 """Accept purchase and confirm with message"""
370 self.dialogue_box = self.make_dialogue_box(self.accept_dialogue, 0)
371 self.gold_box = self.make_gold_box()
372
373 if keys[pg.K_SPACE] and self.allow_input:
374 self.state = self.begin_new_transaction()
375 self.selection_arrow.rect.topleft = self.arrow_pos1
376 self.allow_input = False
377
378 if not keys[pg.K_SPACE]:
379 self.allow_input = True
380
381
382 def accept_sale(self, keys, current_time):
383 """Confirm to player that item was sold"""
384 self.dialogue_box = self.make_dialogue_box(self.accept_sale_dialogue, 0)
385 self.gold_box = self.make_gold_box()
386
387 if keys[pg.K_SPACE] and self.allow_input:
388 self.state = self.begin_new_transaction()
389 self.selection_arrow.rect.topleft = self.arrow_pos1
390 self.allow_input = False
391
392 if not keys[pg.K_SPACE]:
393 self.allow_input = True
394
395
396 def has_item(self, keys, current_time):
397 """Tell player he has item already"""
398 dialogue = ["You have that item already."]
399 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
400
401 if keys[pg.K_SPACE] and self.allow_input:
402 self.state = self.begin_new_transaction()
403 self.selection_arrow.rect.topleft = self.arrow_pos1
404 self.allow_input = False
405
406 if not keys[pg.K_SPACE]:
407 self.allow_input = True
408
409
410 def buy_sell(self, keys, current_time):
411 """Ask player if they want to buy or sell something"""
412 dialogue = ["Would you like to buy or sell an item?"]
413 choices = ['Buy', 'Sell', 'Leave']
414 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
415 self.selection_box = self.make_selection_box(choices)
416 self.selection_arrow.rect.topleft = self.arrow_pos_list[self.arrow_index]
417
418 if keys[pg.K_DOWN] and self.allow_input:
419 if self.arrow_index < (len(self.arrow_pos_list) - 1):
420 self.arrow_index += 1
421 self.allow_input = False
422
423 elif keys[pg.K_UP] and self.allow_input:
424 if self.arrow_index > 0:
425 self.arrow_index -= 1
426 self.allow_input = False
427 elif keys[pg.K_SPACE] and self.allow_input:
428 if self.arrow_index == 0:
429 self.state = 'select'
430 self.allow_input = False
431 self.arrow_index = 0
432 elif self.arrow_index == 1:
433 if self.check_for_sellable_items():
434 self.state = 'sell'
435 self.allow_input = False
436 self.arrow_index = 0
437 else:
438 self.state = 'cantsell'
439 self.allow_input = False
440 self.arrow_index = 0
441
442 else:
443
444 self.level.done = True
445 self.game_data['last state'] = self.level.name
446
447 self.arrow_index = 0
448
449 if not keys[pg.K_SPACE] and not keys[pg.K_DOWN] and not keys[pg.K_UP]:
450 self.allow_input = True
451
452
453 def check_for_sellable_items(self):
454 """Check for sellable items"""
455 for item in self.player_inventory:
456 if item in self.sellable_items:
457 return True
458 else:
459 return False
460
461
462 def sell_items(self, keys, current_time):
463 """Have player select items to sell"""
464 dialogue = ["What would you like to sell?"]
465 choices = []
466 item_list = []
467 for item in self.items:
468 if item['type'] in self.player_inventory:
469 name = item['type']
470 price = " (" + str(item['price'] / 2) + " gold)"
471 choices.append(name + price)
472 item_list.append(name)
473 choices.append('Cancel')
474 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
475 self.selection_box = self.make_selection_box(choices)
476
477 if len(choices) == 2:
478 self.selection_arrow.rect.topleft = self.two_arrow_pos_list[self.arrow_index]
479 elif len(choices) == 3:
480 self.selection_arrow.rect.topleft = self.arrow_pos_list[self.arrow_index]
481
482 if keys[pg.K_DOWN] and self.allow_input:
483 if self.arrow_index < (len(self.arrow_pos_list) - 1):
484 self.arrow_index += 1
485 self.allow_input = False
486 elif keys[pg.K_UP] and self.allow_input:
487 if self.arrow_index > 0:
488 self.arrow_index -= 1
489 self.allow_input = False
490 elif keys[pg.K_SPACE] and self.allow_input:
491 if self.arrow_index == 0:
492 self.state = 'confirmsell'
493 self.allow_input = False
494 for item in self.items:
495 if item['type'] == item_list[0]:
496 self.item_to_be_sold = item
497
498 elif self.arrow_index == 1 and len(choices) == 3:
499 self.state = 'confirmsell'
500 self.allow_input = False
501 for item in self.items:
502 if item['type'] == choices[1]:
503 self.item_to_be_sold = item
504 else:
505 self.state = 'buysell'
506 self.allow_input = False
507 self.arrow_index = 0
508
509 if not keys[pg.K_SPACE] and not keys[pg.K_DOWN] and not keys[pg.K_UP]:
510 self.allow_input = True
511
512
513 def cant_sell(self, keys, current_time):
514 """Do not allow player to sell anything"""
515 dialogue = ["You don't have anything to sell!"]
516 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
517
518 if keys[pg.K_SPACE] and self.allow_input:
519 self.state = 'buysell'
520 self.allow_input = False
521
522
523 if not keys[pg.K_SPACE]:
524 self.allow_input = True
525
526
527 def update(self, keys, current_time):
528 """Updates the shop GUI"""
529 state_function = self.state_dict[self.state]
530 state_function(keys, current_time)
531
532
533 def draw(self, surface):
534 """Draw GUI to level surface"""
535 state_list1 = ['dialogue', 'reject', 'accept', 'hasitem']
536 state_list2 = ['select', 'confirmpurchase', 'buysell', 'sell', 'confirmsell']
537
538 surface.blit(self.dialogue_box.image, self.dialogue_box.rect)
539 surface.blit(self.gold_box.image, self.gold_box.rect)
540 if self.state in state_list2:
541 surface.blit(self.selection_box.image, self.selection_box.rect)
542 surface.blit(self.selection_arrow.image, self.selection_arrow.rect)
543