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
293 item_to_add = {'quantity': quantity,
294 'value': value}
295
296 if item_type in player_items:
297 player_items[item_type]['quantity'] += quantity
298 elif quantity > 0:
299 player_items[item_type] = item_to_add
300
301
302 def confirm_sell(self, keys, current_time):
303 """Confirm player wants to sell item"""
304 dialogue = ['Are you sure?']
305 choices = ['Yes', 'No']
306 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
307 self.selection_box = self.make_selection_box(choices)
308 self.selection_arrow.rect.topleft = self.two_arrow_pos_list[self.arrow_index]
309
310 if keys[pg.K_DOWN] and self.allow_input:
311 if self.arrow_index < (len(choices) - 1):
312 self.arrow_index += 1
313 self.allow_input = False
314 elif keys[pg.K_UP]:
315 if self.arrow_index > 0:
316 self.arrow_index -= 1
317 self.allow_input = False
318 elif keys[pg.K_SPACE] and self.allow_input:
319 if self.arrow_index == 0:
320 self.sell_item_from_inventory()
321 elif self.arrow_index == 1:
322 self.state = self.begin_new_transaction()
323 self.allow_input = False
324 self.arrow_index = 0
325
326 if not keys[pg.K_SPACE] and not keys[pg.K_UP] and not keys[pg.K_DOWN]:
327 self.allow_input = True
328
329
330 def sell_item_from_inventory(self):
331 """Allow player to sell item to shop"""
332 item_price = self.item_to_be_sold['price']
333 item_name = self.item_to_be_sold['type']
334 self.player_inventory['gold'] += (item_price / 2)
335 self.state = 'acceptsell'
336 if self.player_inventory[item_name]['quantity'] > 1:
337 self.player_inventory[item_name]['quantity'] -= 1
338 else:
339 del self.player_inventory[self.item_to_be_sold['type']]
340
341
342 def reject_insufficient_gold(self, keys, current_time):
343 """Reject player selection if they do not have enough gold"""
344 dialogue = ["You don't have enough gold!"]
345 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
346
347 if keys[pg.K_SPACE] and self.allow_input:
348 self.state = self.begin_new_transaction()
349 self.selection_arrow.rect.topleft = self.arrow_pos1
350 self.allow_input = False
351
352 if not keys[pg.K_SPACE]:
353 self.allow_input = True
354
355
356 def accept_purchase(self, keys, current_time):
357 """Accept purchase and confirm with message"""
358 self.dialogue_box = self.make_dialogue_box(self.accept_dialogue, 0)
359 self.gold_box = self.make_gold_box()
360
361 if keys[pg.K_SPACE] and self.allow_input:
362 self.state = self.begin_new_transaction()
363 self.selection_arrow.rect.topleft = self.arrow_pos1
364 self.allow_input = False
365
366 if not keys[pg.K_SPACE]:
367 self.allow_input = True
368
369
370 def accept_sale(self, keys, current_time):
371 """Confirm to player that item was sold"""
372 self.dialogue_box = self.make_dialogue_box(self.accept_sale_dialogue, 0)
373 self.gold_box = self.make_gold_box()
374
375 if keys[pg.K_SPACE] and self.allow_input:
376 self.state = self.begin_new_transaction()
377 self.selection_arrow.rect.topleft = self.arrow_pos1
378 self.allow_input = False
379
380 if not keys[pg.K_SPACE]:
381 self.allow_input = True
382
383
384 def has_item(self, keys, current_time):
385 """Tell player he has item already"""
386 dialogue = ["You have that item already."]
387 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
388
389 if keys[pg.K_SPACE] and self.allow_input:
390 self.state = self.begin_new_transaction()
391 self.selection_arrow.rect.topleft = self.arrow_pos1
392 self.allow_input = False
393
394 if not keys[pg.K_SPACE]:
395 self.allow_input = True
396
397
398 def buy_sell(self, keys, current_time):
399 """Ask player if they want to buy or sell something"""
400 dialogue = ["Would you like to buy or sell an item?"]
401 choices = ['Buy', 'Sell', 'Leave']
402 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
403 self.selection_box = self.make_selection_box(choices)
404 self.selection_arrow.rect.topleft = self.arrow_pos_list[self.arrow_index]
405
406 if keys[pg.K_DOWN] and self.allow_input:
407 if self.arrow_index < (len(self.arrow_pos_list) - 1):
408 self.arrow_index += 1
409 self.allow_input = False
410
411 elif keys[pg.K_UP] and self.allow_input:
412 if self.arrow_index > 0:
413 self.arrow_index -= 1
414 self.allow_input = False
415 elif keys[pg.K_SPACE] and self.allow_input:
416 if self.arrow_index == 0:
417 self.state = 'select'
418 self.allow_input = False
419 self.arrow_index = 0
420 elif self.arrow_index == 1:
421 if self.check_for_sellable_items():
422 self.state = 'sell'
423 self.allow_input = False
424 self.arrow_index = 0
425 else:
426 self.state = 'cantsell'
427 self.allow_input = False
428 self.arrow_index = 0
429
430 else:
431 self.level.done = True
432
433 self.arrow_index = 0
434
435 if not keys[pg.K_SPACE] and not keys[pg.K_DOWN] and not keys[pg.K_UP]:
436 self.allow_input = True
437
438
439 def check_for_sellable_items(self):
440 """Check for sellable items"""
441 for item in self.player_inventory:
442 if item in self.sellable_items:
443 return True
444 else:
445 return False
446
447
448 def sell_items(self, keys, current_time):
449 """Have player select items to sell"""
450 dialogue = ["What would you like to sell?"]
451 choices = []
452 item_list = []
453 for item in self.items:
454 if item['type'] in self.player_inventory:
455 name = item['type']
456 price = " (" + str(item['price'] / 2) + " gold)"
457 choices.append(name + price)
458 item_list.append(name)
459 choices.append('Cancel')
460 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
461 self.selection_box = self.make_selection_box(choices)
462
463 if len(choices) == 2:
464 self.selection_arrow.rect.topleft = self.two_arrow_pos_list[self.arrow_index]
465 elif len(choices) == 3:
466 self.selection_arrow.rect.topleft = self.arrow_pos_list[self.arrow_index]
467
468 if keys[pg.K_DOWN] and self.allow_input:
469 if self.arrow_index < (len(self.arrow_pos_list) - 1):
470 self.arrow_index += 1
471 self.allow_input = False
472 elif keys[pg.K_UP] and self.allow_input:
473 if self.arrow_index > 0:
474 self.arrow_index -= 1
475 self.allow_input = False
476 elif keys[pg.K_SPACE] and self.allow_input:
477 if self.arrow_index == 0:
478 self.state = 'confirmsell'
479 self.allow_input = False
480 for item in self.items:
481 if item['type'] == item_list[0]:
482 self.item_to_be_sold = item
483
484 elif self.arrow_index == 1 and len(choices) == 3:
485 self.state = 'confirmsell'
486 self.allow_input = False
487 for item in self.items:
488 if item['type'] == choices[1]:
489 self.item_to_be_sold = item
490 else:
491 self.state = 'buysell'
492 self.allow_input = False
493 self.arrow_index = 0
494
495 if not keys[pg.K_SPACE] and not keys[pg.K_DOWN] and not keys[pg.K_UP]:
496 self.allow_input = True
497
498
499 def cant_sell(self, keys, current_time):
500 """Do not allow player to sell anything"""
501 dialogue = ["You don't have anything to sell!"]
502 self.dialogue_box = self.make_dialogue_box(dialogue, 0)
503
504 if keys[pg.K_SPACE] and self.allow_input:
505 self.state = 'buysell'
506 self.allow_input = False
507
508
509 if not keys[pg.K_SPACE]:
510 self.allow_input = True
511
512
513 def update(self, keys, current_time):
514 """Updates the shop GUI"""
515 state_function = self.state_dict[self.state]
516 state_function(keys, current_time)
517
518
519 def draw(self, surface):
520 """Draw GUI to level surface"""
521 state_list1 = ['dialogue', 'reject', 'accept', 'hasitem']
522 state_list2 = ['select', 'confirmpurchase', 'buysell', 'sell', 'confirmsell']
523
524 surface.blit(self.dialogue_box.image, self.dialogue_box.rect)
525 surface.blit(self.gold_box.image, self.gold_box.rect)
526 if self.state in state_list2:
527 surface.blit(self.selection_box.image, self.selection_box.rect)
528 surface.blit(self.selection_arrow.image, self.selection_arrow.rect)
529