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