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