all repos — Legends-RPG @ d4842499160b2b7f27df95928231834d218d5ff4

A fantasy mini-RPG built with Python and Pygame.

data/menugui.py (view raw)

  1# -*- coding: utf-8 -*-
  2"""
  3This class controls all the GUI for the player
  4menu screen.
  5"""
  6import pygame as pg
  7from . import setup
  8from . import constants as c
  9from . import tools
 10
 11
 12class SmallArrow(pg.sprite.Sprite):
 13    """Small arrow for menu"""
 14    def __init__(self, info_box):
 15        super(SmallArrow, self).__init__()
 16        self.image = setup.GFX['smallarrow']
 17        self.rect = self.image.get_rect()
 18        self.state = 'selectmenu'
 19        self.state_dict = self.make_state_dict()
 20        self.slots = info_box.slots
 21        self.pos_list = []
 22
 23
 24    def make_state_dict(self):
 25        """Make state dictionary"""
 26        state_dict = {'selectmenu': self.navigate_select_menu,
 27                      'itemsubmenu': self.navigate_item_submenu,
 28                      'magicsubmenu': self.navigate_magic_submenu}
 29
 30        return state_dict
 31
 32
 33    def navigate_select_menu(self, pos_index):
 34        """Nav the select menu"""
 35        self.pos_list = self.make_select_menu_pos_list()
 36        self.rect.topleft = self.pos_list[pos_index]
 37
 38
 39    def navigate_item_submenu(self, pos_index):
 40        """Nav the item submenu"""
 41        self.pos_list = self.make_item_menu_pos_list()
 42        self.rect.topleft = self.pos_list[pos_index]
 43
 44    def navigate_magic_submenu(self, pos_index):
 45        """Nav the magic submenu"""
 46        self.pos_list = self.make_magic_menu_pos_list()
 47        self.rect.topleft = self.pos_list[pos_index]
 48
 49    def make_magic_menu_pos_list(self):
 50        """
 51        Make the list of possible arrow positions for magic submenu.
 52        """
 53        pos_list = [(310, 119),
 54                    (310, 169)]
 55
 56        return pos_list
 57
 58    def make_select_menu_pos_list(self):
 59        """Make the list of possible arrow positions"""
 60        pos_list = []
 61
 62        for i in range(4):
 63            pos = (35, 356 + (i * 50))
 64            pos_list.append(pos)
 65
 66        return pos_list
 67
 68    def make_item_menu_pos_list(self):
 69        """Make the list of arrow positions in the item submenu"""
 70        pos_list = [(300, 173),
 71                    (300, 223),
 72                    (300, 323),
 73                    (300, 373),
 74                    (300, 478),
 75                    (300, 528),
 76                    (535, 478),
 77                    (535, 528)]
 78
 79        return pos_list
 80
 81
 82    def update(self, pos_index):
 83        """Update arrow position"""
 84        state_function = self.state_dict[self.state]
 85        state_function(pos_index)
 86
 87
 88    def draw(self, surface):
 89        """Draw to surface"""
 90        surface.blit(self.image, self.rect)
 91
 92
 93
 94class GoldBox(pg.sprite.Sprite):
 95    def __init__(self, inventory):
 96        self.inventory = inventory
 97        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
 98        self.image, self.rect = self.make_image()
 99
100    def make_image(self):
101        """Make the surface for the gold box"""
102        image = setup.GFX['goldbox2']
103        rect = image.get_rect(left=10, top=234)
104
105        surface = pg.Surface(rect.size)
106        surface.set_colorkey(c.BLACK)
107        surface.blit(image, (0, 0))
108
109        text = "Gold: " + str(self.inventory['GOLD']['quantity'])
110        text_render = self.font.render(text, True, c.NEAR_BLACK)
111        text_rect = text_render.get_rect(centerx=130,
112                                         centery=35)
113        surface.blit(text_render, text_rect)
114
115        return surface, rect
116
117
118    def update(self):
119        """Update gold"""
120        self.image, self.rect = self.make_image()
121
122
123    def draw(self, surface):
124        """Draw to surface"""
125        surface.blit(self.image, self.rect)
126
127
128
129class InfoBox(pg.sprite.Sprite):
130    def __init__(self, inventory, player_stats):
131        super(InfoBox, self).__init__()
132        self.inventory = inventory
133        self.player_stats = player_stats
134        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
135        self.big_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 24)
136        self.title_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 28)
137        self.title_font.set_underline(True)
138        self.get_tile = tools.get_tile
139        self.sword = self.get_tile(48, 0, setup.GFX['shopsigns'], 16, 16, 2)
140        self.shield = self.get_tile(32, 0, setup.GFX['shopsigns'], 16, 16, 2)
141        self.potion = self.get_tile(16, 0, setup.GFX['shopsigns'], 16, 16, 2)
142        self.possible_potions = ['Healing Potion', 'ELIXIR', 'Ether Potion']
143        self.possible_armor = ['Wooden Shield', 'Chain Mail']
144        self.possible_weapons = ['Long Sword', 'Rapier']
145        self.possible_magic = ['Fire Blast', 'Cure']
146        self.quantity_items = ['Healing Potion', 'ELIXIR', 'Ether Potion']
147        self.slots = {}
148        self.state = 'stats'
149        self.state_dict = self.make_state_dict()
150        self.print_slots = True
151
152
153    def make_state_dict(self):
154        """Make the dictionary of state methods"""
155        state_dict = {'stats': self.show_player_stats,
156                      'items': self.show_items,
157                      'magic': self.show_magic}
158
159        return state_dict
160
161
162    def show_player_stats(self):
163        """Show the player's main stats"""
164        title = 'STATS'
165        stat_list = ['Level', 'health',
166                     'magic points', 'experience to next level']
167        surface, rect = self.make_blank_info_box(title)
168
169        for i, stat in enumerate(stat_list):
170            if stat == 'health' or stat == 'magic points':
171                text = "{}{}: {} / {}".format(stat[0].upper(),
172                                              stat[1:],
173                                              str(self.player_stats[stat]['current']),
174                                              str(self.player_stats[stat]['maximum']))
175            elif stat == 'experience to next level':
176                text = "{}{}: {}".format(stat[0].upper(),
177                                         stat[1:],
178                                         self.player_stats[stat])
179            else:
180                text = "{}: {}".format(stat, str(self.player_stats[stat]))
181            text_image = self.font.render(text, True, c.NEAR_BLACK)
182            text_rect = text_image.get_rect(x=50, y=80+(i*50))
183            surface.blit(text_image, text_rect)
184
185        self.image = surface
186        self.rect = rect
187
188
189    def show_items(self):
190        """Show list of items the player has"""
191        title = 'ITEMS'
192        potions = ['POTIONS']
193        weapons = ['WEAPONS']
194        armor = ['ARMOR']
195        for i, item in enumerate(self.inventory):
196            if item in self.possible_weapons:
197                if item == self.inventory['equipped weapon']:
198                    item += " (E)"
199                weapons.append(item)
200            elif item in self.possible_armor:
201                if item in self.inventory['equipped armor']:
202                    item += " (E)"
203                armor.append(item)
204            elif item in self.possible_potions:
205                potions.append(item)
206
207        self.slots = {}
208        self.assign_slots(weapons, 85)
209        self.assign_slots(armor, 235)
210        self.assign_slots(potions, 390)
211
212        surface, rect = self.make_blank_info_box(title)
213
214        self.blit_item_lists(surface)
215
216        self.sword['rect'].topleft = 40, 80
217        self.shield['rect'].topleft = 40, 230
218        self.potion['rect'].topleft = 40, 385
219        surface.blit(self.sword['surface'], self.sword['rect'])
220        surface.blit(self.shield['surface'], self.shield['rect'])
221        surface.blit(self.potion['surface'], self.potion['rect'])
222
223        self.image = surface
224        self.rect = rect
225
226
227    def assign_slots(self, item_list, starty, weapon_or_armor=False):
228        """Assign each item to a slot in the menu"""
229        if len(item_list) > 3:
230            for i, item in enumerate(item_list[:3]):
231                posx = 80
232                posy = starty + (i * 50)
233                self.slots[(posx, posy)] = item
234            for i, item in enumerate(item_list[3:]):
235                posx = 315
236                posy = (starty + 50) + (i * 5)
237                self.slots[(posx, posy)] = item
238        else:
239            for i, item in enumerate(item_list):
240                posx = 80
241                posy = starty + (i * 50)
242                self.slots[(posx, posy)] = item
243
244    def assign_magic_slots(self, magic_list, starty):
245        """
246        Assign each magic spell to a slot in the menu.
247        """
248        for i, spell in enumerate(magic_list):
249            posx = 120
250            posy = starty + (i * 50)
251            self.slots[(posx, posy)] = spell
252
253    def blit_item_lists(self, surface):
254        """Blit item list to info box surface"""
255        for coord in self.slots:
256            item = self.slots[coord]
257
258            if item in self.possible_potions:
259                text = "{}: {}".format(self.slots[coord],
260                                       self.inventory[item]['quantity'])
261            else:
262                text = "{}".format(self.slots[coord])
263            text_image = self.font.render(text, True, c.NEAR_BLACK)
264            text_rect = text_image.get_rect(topleft=coord)
265            surface.blit(text_image, text_rect)
266
267    def show_magic(self):
268        """Show list of magic spells the player knows"""
269        title = 'MAGIC'
270        item_list = []
271        for item in self.inventory:
272            if item in self.possible_magic:
273                item_list.append(item)
274                item_list = sorted(item_list)
275
276        self.slots = {}
277        self.assign_magic_slots(item_list, 80)
278
279        surface, rect = self.make_blank_info_box(title)
280
281        for i, item in enumerate(item_list):
282            text_image = self.font.render(item, True, c.NEAR_BLACK)
283            text_rect = text_image.get_rect(x=100, y=80+(i*50))
284            surface.blit(text_image, text_rect)
285
286        self.image = surface
287        self.rect = rect
288
289
290    def make_blank_info_box(self, title):
291        """Make an info box with title, otherwise blank"""
292        image = setup.GFX['playerstatsbox']
293        rect = image.get_rect(left=285, top=35)
294        centerx = rect.width / 2
295
296        surface = pg.Surface(rect.size)
297        surface.set_colorkey(c.BLACK)
298        surface.blit(image, (0,0))
299
300        title_image = self.title_font.render(title, True, c.NEAR_BLACK)
301        title_rect = title_image.get_rect(centerx=centerx, y=30)
302        surface.blit(title_image, title_rect)
303
304        return surface, rect
305
306
307    def update(self):
308        state_function = self.state_dict[self.state]
309        state_function()
310
311
312    def draw(self, surface):
313        """Draw to surface"""
314        surface.blit(self.image, self.rect)
315
316
317class SelectionBox(pg.sprite.Sprite):
318    def __init__(self):
319        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
320        self.image, self.rect = self.make_image()
321
322
323    def make_image(self):
324        choices = ['Stats', 'Items', 'Magic', 'Exit']
325        image = setup.GFX['selectionbox']
326        rect = image.get_rect(left=10, top=330)
327
328        surface = pg.Surface(rect.size)
329        surface.set_colorkey(c.BLACK)
330        surface.blit(image, (0, 0))
331
332        for i, choice in enumerate(choices):
333            choice_image = self.font.render(choice, True, c.NEAR_BLACK)
334            choice_rect = choice_image.get_rect(x=100, y=(25 + (i * 50)))
335            surface.blit(choice_image, choice_rect)
336
337        return surface, rect
338
339
340    def draw(self, surface):
341        """Draw to surface"""
342        surface.blit(self.image, self.rect)
343
344
345
346
347class MenuGui(object):
348    def __init__(self, level, inventory, stats):
349        self.level = level
350        self.game_data = self.level.game_data
351        self.inventory = inventory
352        self.stats = stats
353        self.info_box = InfoBox(inventory, stats)
354        self.gold_box = GoldBox(inventory)
355        self.selection_box = SelectionBox()
356        self.arrow = SmallArrow(self.info_box)
357        self.arrow_index = 0
358        self.allow_input = False
359        self.state = 'stats'
360
361
362    def check_for_input(self, keys):
363        """Check for input"""
364        if self.allow_input:
365            if keys[pg.K_DOWN]:
366                if self.arrow_index < len(self.arrow.pos_list) - 1:
367                    self.arrow_index += 1
368                    self.allow_input = False
369            elif keys[pg.K_UP]:
370                if self.arrow_index > 0:
371                    self.arrow_index -= 1
372                    self.allow_input = False
373            elif keys[pg.K_RIGHT]:
374                if self.info_box.state == 'items':
375                    if not self.arrow.state == 'itemsubmenu':
376                        self.arrow_index = 0
377                    self.arrow.state = 'itemsubmenu'
378                elif self.info_box.state == 'magic':
379                    if not self.arrow.state == 'magicsubmenu':
380                        self.arrow_index = 0
381                    self.arrow.state = 'magicsubmenu'
382
383            elif keys[pg.K_LEFT]:
384                self.arrow.state = 'selectmenu'
385                self.arrow_index = 0
386            elif keys[pg.K_SPACE]:
387                if self.arrow.state == 'selectmenu':
388                    if self.arrow_index == 0:
389                        self.info_box.state = 'stats'
390
391                    elif self.arrow_index == 1:
392                        self.info_box.state = 'items'
393
394                    elif self.arrow_index == 2:
395                        self.info_box.state = 'magic'
396
397                    elif self.arrow_index == 3:
398                        self.level.state = 'normal'
399                        self.arrow_index = 0
400                        self.info_box.state = 'stats'
401                elif self.arrow.state == 'itemsubmenu':
402                    self.select_item()
403                elif self.arrow.state == 'magicsubmenu':
404                    self.select_magic()
405
406                self.allow_input = False
407            elif keys[pg.K_RETURN]:
408                self.level.state = 'normal'
409                self.info_box.state = 'stats'
410                self.allow_input = False
411                self.arrow_index = 0
412                self.arrow.state = 'selectmenu'
413
414        if (not keys[pg.K_DOWN]
415                and not keys[pg.K_UP]
416                and not keys[pg.K_RETURN]
417                and not keys[pg.K_SPACE]):
418            self.allow_input = True
419
420    def select_item(self):
421        """
422        Select item from item menu.
423        """
424        health = self.game_data['player stats']['health']
425        posx = self.arrow.rect.x - 220
426        posy = self.arrow.rect.y - 38
427
428        if (posx, posy) in self.info_box.slots:
429            if self.info_box.slots[(posx, posy)][:7] == 'Healing':
430                potion = 'Healing Potion'
431                value = 30
432                self.drink_potion(potion, health, value)
433            elif self.info_box.slots[(posx, posy)][:5] == 'Ether':
434                potion = 'Ether Potion'
435                stat = self.game_data['player stats']['magic points']
436                value = 30
437                self.drink_potion(potion, stat, value)
438            elif self.info_box.slots[(posx, posy)][:10] == 'Long Sword':
439                self.inventory['equipped weapon'] = 'Long Sword'
440            elif self.info_box.slots[(posx, posy)][:6] == 'Rapier':
441                self.inventory['equipped weapon'] = 'Rapier'
442            elif self.info_box.slots[(posx, posy)][:13] == 'Wooden Shield':
443                if 'Wooden Shield' in self.inventory['equipped armor']:
444                    self.inventory['equipped armor'].remove('Wooden Shield')
445                else:
446                    self.inventory['equipped armor'].append('Wooden Shield')
447            elif self.info_box.slots[(posx, posy)][:10] == 'Chain Mail':
448                if 'Chain Mail' in self.inventory['equipped armor']:
449                    self.inventory['equipped armor'].remove('Chain Mail')
450                else:
451                    self.inventory['equipped armor'].append('Chain Mail')
452
453    def select_magic(self):
454        """
455        Select spell from magic menu.
456        """
457        health = self.game_data['player stats']['health']
458        magic = self.game_data['player stats']['magic points']
459        posx = self.arrow.rect.x - 190
460        posy = self.arrow.rect.y - 39
461
462        if (posx, posy) in self.info_box.slots:
463            if self.info_box.slots[(posx, posy)][:4] == 'Cure':
464               self.use_cure_spell()
465
466    def use_cure_spell(self):
467        """
468        Use cure spell to heal player.
469        """
470        health = self.game_data['player stats']['health']
471        magic = self.game_data['player stats']['magic points']
472        inventory = self.game_data['player inventory']
473
474        if magic['current'] > inventory['Cure']['magic points']:
475            magic['current'] -= inventory['Cure']['magic points']
476            health['current'] += inventory['Cure']['power']
477            if health['current'] > health['maximum']:
478                health['current'] = health['maximum']
479
480    def drink_potion(self, potion, stat, value):
481        """
482        Drink potion and change player stats.
483        """
484        self.inventory[potion]['quantity'] -= 1
485        stat['current'] += value
486        if stat['current'] > stat['maximum']:
487            stat['current'] = stat['maximum']
488        if not self.inventory[potion]['quantity']:
489            del self.inventory[potion]
490
491    def update(self, keys):
492        self.info_box.update()
493        self.gold_box.update()
494        self.arrow.update(self.arrow_index)
495        self.check_for_input(keys)
496
497
498    def draw(self, surface):
499        self.gold_box.draw(surface)
500        self.info_box.draw(surface)
501        self.selection_box.draw(surface)
502        self.arrow.draw(surface)