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)