all repos — Legends-RPG @ c5dc6b5321b8c948f5f1becc48ffa927c3b73209

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