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