all repos — Legends-RPG @ bc9dbbaff0f24475c11c5f6a992e77532b9db02c

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.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