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