all repos — Legends-RPG @ c5d70de66c1b6acc4456bef4e66bb278f0375c37

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):
 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.pos_list = []
 21
 22
 23    def make_state_dict(self):
 24        """Make state dictionary"""
 25        state_dict = {'selectmenu': self.navigate_select_menu,
 26                      'itemsubmenu': self.navigate_item_submenu}
 27
 28        return state_dict
 29
 30
 31    def navigate_select_menu(self, pos_index):
 32        """Nav the select menu"""
 33        self.pos_list = self.make_select_menu_pos_list()
 34        self.rect.topleft = self.pos_list[pos_index]
 35
 36
 37    def navigate_item_submenu(self, pos_index):
 38        """Nav the item submenu"""
 39        self.pos_list = self.make_item_menu_pos_list()
 40        self.rect.topleft = self.pos_list[pos_index]
 41
 42
 43    def make_select_menu_pos_list(self):
 44        """Make the list of possible arrow positions"""
 45        pos_list = []
 46
 47        for i in range(4):
 48            pos = (35, 356 + (i * 50))
 49            pos_list.append(pos)
 50
 51        return pos_list
 52
 53
 54    def make_item_menu_pos_list(self):
 55        """Make the list of arrow positions in the item submenu"""
 56        pos_list = [(310, 173),
 57                    (310, 223),
 58                    (310, 323),
 59                    (310, 373),
 60                    (310, 478),
 61                    (310, 528)]
 62
 63        return pos_list
 64
 65
 66    def update(self, pos_index):
 67        """Update arrow position"""
 68        state_function = self.state_dict[self.state]
 69        state_function(pos_index)
 70
 71
 72    def draw(self, surface):
 73        """Draw to surface"""
 74        surface.blit(self.image, self.rect)
 75
 76
 77
 78class GoldBox(pg.sprite.Sprite):
 79    def __init__(self, inventory):
 80        self.inventory = inventory
 81        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
 82        self.image, self.rect = self.make_image()
 83
 84    def make_image(self):
 85        """Make the surface for the gold box"""
 86        image = setup.GFX['goldbox2']
 87        rect = image.get_rect(left=10, top=234)
 88
 89        surface = pg.Surface(rect.size)
 90        surface.set_colorkey(c.BLACK)
 91        surface.blit(image, (0, 0))
 92
 93        text = "Gold: " + str(self.inventory['GOLD']['quantity'])
 94        text_render = self.font.render(text, True, c.NEAR_BLACK)
 95        text_rect = text_render.get_rect(centerx=130,
 96                                         centery=35)
 97        surface.blit(text_render, text_rect)
 98
 99        return surface, rect
100
101
102    def update(self):
103        """Update gold"""
104        self.image, self.rect = self.make_image()
105
106
107    def draw(self, surface):
108        """Draw to surface"""
109        surface.blit(self.image, self.rect)
110
111
112
113class InfoBox(pg.sprite.Sprite):
114    def __init__(self, inventory, player_stats):
115        super(InfoBox, self).__init__()
116        self.inventory = inventory
117        self.player_stats = player_stats
118        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
119        self.big_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 24)
120        self.title_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 28)
121        self.title_font.set_underline(True)
122        self.get_tile = tools.get_tile
123        self.sword = self.get_tile(48, 0, setup.GFX['shopsigns'], 16, 16, 2)
124        self.shield = self.get_tile(32, 0, setup.GFX['shopsigns'], 16, 16, 2)
125        self.potion = self.get_tile(16, 0, setup.GFX['shopsigns'], 16, 16, 2)
126        self.possible_potions = ['Healing Potion', 'ELIXIR']
127        self.possible_armor = ['Wooden Shield', 'Chain Mail']
128        self.possible_weapons = ['Long Sword', 'Rapier']
129        self.possible_magic = ['Fire Blast', 'Cure']
130        self.quantity_items = ['Healing Potion', 'ELIXIR']
131        self.slots = [None for i in range(6)]
132        self.state = 'stats'
133        self.state_dict = self.make_state_dict()
134        self.print_slots = True
135
136
137    def make_state_dict(self):
138        """Make the dictionary of state methods"""
139        state_dict = {'stats': self.show_player_stats,
140                      'items': self.show_items,
141                      'magic': self.show_magic}
142
143        return state_dict
144
145
146    def show_player_stats(self):
147        """Show the player's main stats"""
148        title = 'STATS'
149        stat_list = ['Level', 'health',
150                     'magic points', 'experience to next level']
151        surface, rect = self.make_blank_info_box(title)
152
153        for i, stat in enumerate(stat_list):
154            if stat == 'health' or stat == 'magic points':
155                text = "{}{}: {} / {}".format(stat[0].upper(),
156                                              stat[1:],
157                                              str(self.player_stats[stat]['current']),
158                                              str(self.player_stats[stat]['maximum']))
159            elif stat == 'experience to next level':
160                text = "{}{}: {}".format(stat[0].upper(),
161                                         stat[1:],
162                                         self.player_stats[stat])
163            else:
164                text = "{}: {}".format(stat, str(self.player_stats[stat]))
165            text_image = self.font.render(text, True, c.NEAR_BLACK)
166            text_rect = text_image.get_rect(x=50, y=80+(i*50))
167            surface.blit(text_image, text_rect)
168
169        self.image = surface
170        self.rect = rect
171
172
173    def show_items(self):
174        """Show list of items the player has"""
175        title = 'ITEMS'
176        potions = ['POTIONS']
177        weapons = ['WEAPONS']
178        armor = ['ARMOR']
179        for i, item in enumerate(self.inventory):
180            if item in self.possible_weapons:
181                weapons.append(item)
182            elif item in self.possible_armor:
183                armor.append(item)
184            elif item in self.possible_potions:
185                potions.append(item)
186
187        self.assign_slots(weapons, armor, potions)
188
189        surface, rect = self.make_blank_info_box(title)
190
191        surface = self.blit_item_list(surface, weapons, 85)
192        surface = self.blit_item_list(surface, armor, 235)
193        surface = self.blit_item_list(surface, potions, 390)
194
195        self.sword['rect'].topleft = 50, 80
196        self.shield['rect'].topleft = 50, 230
197        self.potion['rect'].topleft = 50, 385
198        surface.blit(self.sword['surface'], self.sword['rect'])
199        surface.blit(self.shield['surface'], self.shield['rect'])
200        surface.blit(self.potion['surface'], self.potion['rect'])
201
202        self.image = surface
203        self.rect = rect
204
205
206    def assign_slots(self, weapons, armor, potions):
207        """Assign each item to a slot in the menu"""
208        if len(weapons) == 2:
209            self.slots[0] = weapons[1]
210        elif len(weapons) == 3:
211            self.slots[0] = weapons[1]
212            self.slots[1] = weapons[2]
213
214        if len(armor) == 2:
215            self.slots[2] = armor[1]
216        elif len(armor) == 3:
217            self.slots[2] = armor[1]
218            self.slots[3] = armor[2]
219
220        if len(potions) == 2:
221            self.slots[4] = potions[1]
222        elif len(potions) == 3:
223            self.slots[4] = potions[1]
224            self.slots[5] = potions[2]
225
226
227
228
229    def blit_item_list(self, surface, item_list, starty):
230        """Blit item list to info box surface"""
231        for i, item in enumerate(item_list):
232            if item in self.quantity_items:
233                text = item + ": " + str(self.inventory[item]['quantity'])
234                text_image = self.font.render(text, True, c.NEAR_BLACK)
235                text_rect = text_image.get_rect(x=90, y=starty+(i*50))
236                surface.blit(text_image, text_rect)
237            elif i == 0:
238                text = item
239                text_image = self.big_font.render(text, True, c.NEAR_BLACK)
240                text_rect = text_image.get_rect(x=90, y=starty)
241                surface.blit(text_image, text_rect)
242            else:
243                text = item
244                text_image = self.font.render(text, True, c.NEAR_BLACK)
245                text_rect = text_image.get_rect(x=90, y=starty+(i*50))
246                surface.blit(text_image, text_rect)
247
248        return surface
249
250
251    def show_magic(self):
252        """Show list of magic spells the player knows"""
253        title = 'MAGIC'
254        item_list = []
255        for item in self.inventory:
256            if item in self.possible_magic:
257                item_list.append(item)
258                item_list = sorted(item_list)
259
260        surface, rect = self.make_blank_info_box(title)
261
262        for i, item in enumerate(item_list):
263            text_image = self.font.render(item, True, c.NEAR_BLACK)
264            text_rect = text_image.get_rect(x=50, y=80+(i*50))
265            surface.blit(text_image, text_rect)
266
267        self.image = surface
268        self.rect = rect
269
270
271    def make_blank_info_box(self, title):
272        """Make an info box with title, otherwise blank"""
273        image = setup.GFX['playerstatsbox']
274        rect = image.get_rect(left=285, top=35)
275        centerx = rect.width / 2
276
277        surface = pg.Surface(rect.size)
278        surface.set_colorkey(c.BLACK)
279        surface.blit(image, (0,0))
280
281        title_image = self.title_font.render(title, True, c.NEAR_BLACK)
282        title_rect = title_image.get_rect(centerx=centerx, y=30)
283        surface.blit(title_image, title_rect)
284
285        return surface, rect
286
287
288    def update(self):
289        state_function = self.state_dict[self.state]
290        state_function()
291
292
293    def draw(self, surface):
294        """Draw to surface"""
295        surface.blit(self.image, self.rect)
296
297
298class SelectionBox(pg.sprite.Sprite):
299    def __init__(self):
300        self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
301        self.image, self.rect = self.make_image()
302
303
304    def make_image(self):
305        choices = ['Stats', 'Items', 'Magic', 'Exit']
306        image = setup.GFX['selectionbox']
307        rect = image.get_rect(left=10, top=330)
308
309        surface = pg.Surface(rect.size)
310        surface.set_colorkey(c.BLACK)
311        surface.blit(image, (0, 0))
312
313        for i, choice in enumerate(choices):
314            choice_image = self.font.render(choice, True, c.NEAR_BLACK)
315            choice_rect = choice_image.get_rect(x=100, y=(25 + (i * 50)))
316            surface.blit(choice_image, choice_rect)
317
318        return surface, rect
319
320
321    def draw(self, surface):
322        """Draw to surface"""
323        surface.blit(self.image, self.rect)
324
325
326
327
328class MenuGui(object):
329    def __init__(self, level, inventory, stats):
330        self.level = level
331        self.inventory = inventory
332        self.stats = stats
333        self.info_box = InfoBox(inventory, stats)
334        self.gold_box = GoldBox(inventory)
335        self.selection_box = SelectionBox()
336        self.arrow = SmallArrow()
337        self.arrow_index = 0
338        self.allow_input = False
339        self.state = 'stats'
340
341
342    def check_for_input(self, keys):
343        """Check for input"""
344        if self.allow_input:
345            if keys[pg.K_DOWN]:
346                if self.arrow_index < len(self.arrow.pos_list) - 1:
347                    self.arrow_index += 1
348                    self.allow_input = False
349            elif keys[pg.K_UP]:
350                if self.arrow_index > 0:
351                    self.arrow_index -= 1
352                    self.allow_input = False
353            elif keys[pg.K_RIGHT]:
354                if self.info_box.state == 'items':
355                    if not self.arrow.state == 'itemsubmenu':
356                        self.arrow_index = 0
357                    self.arrow.state = 'itemsubmenu'
358
359            elif keys[pg.K_LEFT]:
360                self.arrow.state = 'selectmenu'
361                self.arrow_index = 0
362            elif keys[pg.K_SPACE]:
363                if self.arrow.state == 'selectmenu':
364                    if self.arrow_index == 0:
365                        self.info_box.state = 'stats'
366
367                    elif self.arrow_index == 1:
368                        self.info_box.state = 'items'
369
370                    elif self.arrow_index == 2:
371                        self.info_box.state = 'magic'
372
373                    elif self.arrow_index == 3:
374                        self.level.state = 'normal'
375                        self.arrow_index = 0
376                        self.info_box.state = 'stats'
377
378
379                self.allow_input = False
380            elif keys[pg.K_RETURN]:
381                self.level.state = 'normal'
382                self.info_box.state = 'stats'
383                self.allow_input = False
384                self.arrow_index = 0
385
386        if (not keys[pg.K_DOWN]
387                and not keys[pg.K_UP]
388                and not keys[pg.K_RETURN]
389                and not keys[pg.K_SPACE]):
390            self.allow_input = True
391
392
393    def update(self, keys):
394        self.info_box.update()
395        self.gold_box.update()
396        self.arrow.update(self.arrow_index)
397        self.check_for_input(keys)
398
399
400    def draw(self, surface):
401        self.gold_box.draw(surface)
402        self.info_box.draw(surface)
403        self.selection_box.draw(surface)
404        self.arrow.draw(surface)