all repos — Legends-RPG @ cc5415b4ae455bd90a3ba7e4e0e42dc9b3e9811d

A fantasy mini-RPG built with Python and Pygame.

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