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