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