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