data/battlegui.py (view raw)
1"""
2GUI components for battle states.
3"""
4import sys
5import pygame as pg
6from . import setup
7from . import constants as c
8
9#Python 2/3 compatibility.
10if sys.version_info[0] == 2:
11 range = xrange
12
13class InfoBox(object):
14 """
15 Info box that describes attack damage and other battle
16 related information.
17 """
18 def __init__(self, game_data, experience):
19 self.game_data = game_data
20 self.enemy_damage = 0
21 self.player_damage = 0
22 self.state = c.SELECT_ACTION
23 self.title_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
24 self.title_font.set_underline(True)
25 self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 18)
26 self.experience_points = experience
27 self.state_dict = self.make_state_dict()
28 self.image = self.make_image()
29 self.rect = self.image.get_rect(bottom=608)
30 self.item_text_list = self.make_item_text()[1:]
31 self.magic_text_list = self.make_magic_text()[1:]
32
33 def make_state_dict(self):
34 """
35 Make dictionary of states Battle info can be in.
36 """
37 state_dict = {c.SELECT_ACTION: 'Select an action.',
38 c.SELECT_MAGIC: 'Select a magic spell.',
39 c.SELECT_ITEM: 'Select an item.',
40 c.SELECT_ENEMY: 'Select an enemy.',
41 c.ENEMY_ATTACK: 'Enemy attacks player!',
42 c.PLAYER_ATTACK: 'Player attacks enemy.',
43 c.RUN_AWAY: 'RUN AWAY!!!',
44 c.ENEMY_DAMAGED: self.enemy_damaged(),
45 c.ENEMY_DEAD: 'Enemy killed.',
46 c.PLAYER_DAMAGED: self.player_hit(),
47 c.DRINK_HEALING_POTION: 'Player healed.',
48 c.DRINK_ETHER_POTION: 'Magic Points Increased.',
49 c.FIRE_SPELL: 'FIRE BLAST!',
50 c.BATTLE_WON: 'Battle won!',
51 c.SHOW_EXPERIENCE: self.show_experience(),
52 c.LEVEL_UP: self.level_up()}
53
54 return state_dict
55
56 def enemy_damaged(self):
57 """
58 Return text of enemy being hit using calculated damage.
59 """
60 return "Enemy hit with {} damage.".format(self.enemy_damage)
61
62 def make_item_text(self):
63 """
64 Make the text for when the player selects items.
65 """
66 inventory = self.game_data['player inventory']
67 allowed_item_list = ['Healing Potion', 'Ether Potion']
68 title = 'SELECT ITEM'
69 item_text_list = [title]
70
71 for item in allowed_item_list:
72 if item in inventory:
73 text = item + ": " + str(inventory[item]['quantity'])
74 item_text_list.append(text)
75
76 item_text_list.append('BACK')
77
78 return item_text_list
79
80 def make_magic_text(self):
81 """
82 Make the text for when the player selects magic.
83 """
84 inventory = self.game_data['player inventory']
85 allowed_item_list = ['Fire Blast', 'Cure']
86 title = 'SELECT MAGIC SPELL'
87 magic_text_list = [title]
88 spell_list = [item for item in inventory if item in allowed_item_list]
89 magic_text_list.extend(spell_list)
90 magic_text_list.append('BACK')
91
92 return magic_text_list
93
94 def make_text_sprites(self, text_list):
95 """
96 Make sprites out of text.
97 """
98 sprite_group = pg.sprite.Group()
99
100 for i, text in enumerate(text_list):
101 sprite = pg.sprite.Sprite()
102
103 if i == 0:
104 x = 195
105 y = 10
106 surface = self.title_font.render(text, True, c.NEAR_BLACK)
107 rect = surface.get_rect(x=x, y=y)
108 else:
109 x = 100
110 y = (i * 30) + 20
111 surface = self.font.render(text, True, c.NEAR_BLACK)
112 rect = surface.get_rect(x=x, y=y)
113 sprite.image = surface
114 sprite.rect = rect
115 sprite_group.add(sprite)
116
117 return sprite_group
118
119 def make_image(self):
120 """
121 Make image out of box and message.
122 """
123 image = setup.GFX['shopbox']
124 rect = image.get_rect(bottom=608)
125 surface = pg.Surface(rect.size)
126 surface.set_colorkey(c.BLACK)
127 surface.blit(image, (0, 0))
128
129 if self.state == c.SELECT_ITEM:
130 text_sprites = self.make_text_sprites(self.make_item_text())
131 text_sprites.draw(surface)
132 elif self.state == c.SELECT_MAGIC:
133 text_sprites = self.make_text_sprites(self.make_magic_text())
134 text_sprites.draw(surface)
135 else:
136 text_surface = self.font.render(self.state_dict[self.state], True, c.NEAR_BLACK)
137 text_rect = text_surface.get_rect(x=50, y=50)
138 surface.blit(text_surface, text_rect)
139
140 return surface
141
142 def set_enemy_damage(self, enemy_damage):
143 """
144 Set enemy damage in state dictionary.
145 """
146 self.enemy_damage = enemy_damage
147 self.state_dict[c.ENEMY_DAMAGED] = self.enemy_damaged()
148
149 def set_player_damage(self, player_damage):
150 """
151 Set player damage in state dictionary.
152 """
153 self.player_damage = player_damage
154 self.state_dict[c.PLAYER_DAMAGED] = self.player_hit()
155
156 def player_hit(self):
157 if self.player_damage:
158 return "Player hit with {} damage".format(self.player_damage)
159 else:
160 return "Enemy missed!"
161
162 def update(self):
163 """Updates info box"""
164 self.image = self.make_image()
165
166 def show_experience(self):
167 """
168 Show how much experience the player earned.
169 """
170 return "You earned {} experience points this battle!".format(self.experience_points)
171
172 def level_up(self):
173 """
174 Return message indicating a level up for player.
175 """
176 return "You leveled up to Level {}!".format(self.game_data['player stats']['Level'])
177
178 def reset_level_up_message(self):
179 self.state_dict[c.LEVEL_UP] = self.level_up()
180
181
182
183class SelectBox(object):
184 """
185 Box to select whether to attack, use item, use magic or run away.
186 """
187 def __init__(self):
188 self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
189 self.slots = self.make_slots()
190 self.image = self.make_image()
191 self.rect = self.image.get_rect(bottom=608,
192 right=800)
193
194 def make_image(self):
195 """
196 Make the box image for
197 """
198 image = setup.GFX['goldbox']
199 rect = image.get_rect(bottom=608)
200 surface = pg.Surface(rect.size)
201 surface.set_colorkey(c.BLACK)
202 surface.blit(image, (0, 0))
203
204 for text in self.slots:
205 text_surface = self.font.render(text, True, c.NEAR_BLACK)
206 text_rect = text_surface.get_rect(x=self.slots[text]['x'],
207 y=self.slots[text]['y'])
208 surface.blit(text_surface, text_rect)
209
210 return surface
211
212 def make_slots(self):
213 """
214 Make the slots that hold the text selections, and locations.
215 """
216 slot_dict = {}
217 selections = ['Attack', 'Items', 'Magic', 'Run']
218
219 for i, text in enumerate(selections):
220 slot_dict[text] = {'x': 150,
221 'y': (i*34)+10}
222
223 return slot_dict
224
225
226class SelectArrow(object):
227 """Small arrow for menu"""
228 def __init__(self, enemy_pos_list, info_box):
229 self.info_box = info_box
230 self.image = setup.GFX['smallarrow']
231 self.rect = self.image.get_rect()
232 self.state = 'select action'
233 self.state_dict = self.make_state_dict()
234 self.pos_list = self.make_select_action_pos_list()
235 self.index = 0
236 self.rect.topleft = self.pos_list[self.index]
237 self.allow_input = False
238 self.enemy_pos_list = enemy_pos_list
239
240 def make_state_dict(self):
241 """Make state dictionary"""
242 state_dict = {'select action': self.select_action,
243 'select enemy': self.select_enemy,
244 'select item': self.select_item,
245 'select magic': self.select_magic,
246 'invisible': self.become_invisible_surface}
247
248 return state_dict
249
250 def select_action(self, keys):
251 """
252 Select what action the player should take.
253 """
254 self.pos_list = self.make_select_action_pos_list()
255 if self.index > (len(self.pos_list) - 1):
256 print self.pos_list, self.index
257 self.rect.topleft = self.pos_list[self.index]
258
259 self.check_input(keys)
260
261 def make_select_action_pos_list(self):
262 """
263 Make the list of positions the arrow can be in.
264 """
265 pos_list = []
266
267 for i in range(4):
268 x = 590
269 y = (i * 34) + 472
270 pos_list.append((x, y))
271
272 return pos_list
273
274 def select_enemy(self, keys):
275 """
276 Select what enemy you want to take action on.
277 """
278 self.pos_list = self.enemy_pos_list
279
280 if self.pos_list:
281 pos = self.pos_list[self.index]
282 self.rect.x = pos[0] - 60
283 self.rect.y = pos[1] + 20
284
285 self.check_input(keys)
286
287 def check_input(self, keys):
288 if self.allow_input:
289 if keys[pg.K_DOWN] and self.index < (len(self.pos_list) - 1):
290 self.index += 1
291 self.allow_input = False
292 elif keys[pg.K_UP] and self.index > 0:
293 self.index -= 1
294 self.allow_input = False
295
296
297 if keys[pg.K_DOWN] == False and keys[pg.K_UP] == False \
298 and keys[pg.K_RIGHT] == False and keys[pg.K_LEFT] == False:
299 self.allow_input = True
300
301 def select_item(self, keys):
302 """
303 Select item to use.
304 """
305 self.pos_list = self.make_select_item_pos_list()
306
307 pos = self.pos_list[self.index]
308 self.rect.x = pos[0] - 60
309 self.rect.y = pos[1] + 20
310
311 self.check_input(keys)
312
313 def make_select_item_pos_list(self):
314 """
315 Make the coordinates for the arrow for the item select screen.
316 """
317 pos_list = []
318 text_list = self.info_box.make_item_text()
319 text_list = text_list[1:]
320
321 for i in range(len(text_list)):
322 left = 90
323 top = (i * 29) + 488
324 pos_list.append((left, top))
325
326 return pos_list
327
328 def select_magic(self, keys):
329 """
330 Select magic to use.
331 """
332 self.pos_list = self.make_select_magic_pos_list()
333
334 pos = self.pos_list[self.index]
335 self.rect.x = pos[0] - 60
336 self.rect.y = pos[1] + 20
337
338 self.check_input(keys)
339
340 def make_select_magic_pos_list(self):
341 """
342 Make the coordinates for the arrow for the magic select screen.
343 """
344 pos_list = []
345 text_list = self.info_box.make_magic_text()
346 text_list = text_list[1:]
347
348 for i in range(len(text_list)):
349 left = 90
350 top = (i * 29) + 488
351 pos_list.append((left, top))
352
353 return pos_list
354
355
356 def become_invisible_surface(self, *args):
357 """
358 Make image attribute an invisible surface.
359 """
360 self.image = pg.Surface(self.rect.size)
361 self.image.set_colorkey(c.BLACK)
362
363 def become_select_item_state(self):
364 self.index = 0
365 self.state = c.SELECT_ITEM
366
367 def become_select_magic_state(self):
368 self.index = 0
369 self.state = c.SELECT_MAGIC
370
371 def enter_select_action(self):
372 """
373 Assign values for the select action state.
374 """
375 pass
376
377 def enter_select_enemy(self):
378 """
379 Assign values for the select enemy state.
380 """
381 pass
382
383 def update(self, keys):
384 """
385 Update arrow position.
386 """
387 self.image = setup.GFX['smallarrow']
388 state_function = self.state_dict[self.state]
389 state_function(keys)
390
391 def draw(self, surface):
392 """
393 Draw to surface.
394 """
395 surface.blit(self.image, self.rect)
396
397 def remove_pos(self, enemy):
398 enemy_list = self.enemy_pos_list
399 enemy_pos = list(enemy.rect.topleft)
400
401 self.enemy_pos_list = [pos for pos in enemy_list if pos != enemy_pos]
402
403
404class PlayerHealth(object):
405 """
406 Basic health meter for player.
407 """
408 def __init__(self, select_box_rect, game_data):
409 self.health_stats = game_data['player stats']['health']
410 self.magic_stats = game_data['player stats']['magic points']
411 self.title_font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
412 self.posx = select_box_rect.centerx
413 self.posy = select_box_rect.y - 5
414
415 @property
416 def image(self):
417 """
418 Make the image surface for the player
419 """
420 current_health = str(self.health_stats['current'])
421 max_health = str(self.health_stats['maximum'])
422 if len(current_health) == 2:
423 buffer = ' '
424 elif len(current_health) == 1:
425 buffer = ' '
426 else:
427 buffer = ''
428 health_string = "Health: {}{}/{}".format(buffer, current_health, max_health)
429 health_surface = self.title_font.render(health_string, True, c.NEAR_BLACK)
430 health_rect = health_surface.get_rect(x=20, y=9)
431
432 current_magic = str(self.magic_stats['current'])
433 if len(current_magic) == 2:
434 buffer = ' '
435 elif len(current_magic) == 1:
436 buffer = ' '
437 else:
438 buffer = ''
439 max_magic = str(self.magic_stats['maximum'])
440 magic_string = "Magic: {}{}/{}".format(buffer, current_magic, max_magic)
441 magic_surface = self.title_font.render(magic_string, True, c.NEAR_BLACK)
442 magic_rect = magic_surface.get_rect(x=20, top=health_rect.bottom)
443
444 box_surface = setup.GFX['battlestatbox']
445 box_rect = box_surface.get_rect()
446
447 parent_surface = pg.Surface(box_rect.size)
448 parent_surface.blit(box_surface, box_rect)
449 parent_surface.blit(health_surface, health_rect)
450 parent_surface.blit(magic_surface, magic_rect)
451
452 return parent_surface
453
454 @property
455 def rect(self):
456 """
457 Make the rect object for image surface.
458 """
459 return self.image.get_rect(centerx=self.posx, bottom=self.posy)
460
461 def draw(self, surface):
462 """
463 Draw health to surface.
464 """
465 surface.blit(self.image, self.rect)