all repos — Legends-RPG @ 7725c2234297c6e0c00dfdb295d2961f72393d0f

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