all repos — Legends-RPG @ a2ffdf647695282f3e789bc49cd116ff8b677ad2

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