data/states/battle.py (view raw)
1"""This is the state that handles battles against
2monsters"""
3
4import random
5import pygame as pg
6from .. import tools, setup
7from .. components import person
8from .. import constants as c
9
10#STATES
11
12SELECT_ACTION = 'select action'
13SELECT_ENEMY = 'select enemy'
14ENEMY_ATTACK = 'enemy attack'
15PLAYER_ATTACK = 'player attack'
16SELECT_ITEM = 'select item'
17SELECT_MAGIC = 'select magic'
18RUN_AWAY = 'run away'
19
20#EVENTS
21
22END_BATTLE = 'end battle'
23
24
25class Battle(tools._State):
26 def __init__(self):
27 super(Battle, self).__init__()
28
29 def startup(self, current_time, game_data):
30 """Initialize state attributes"""
31 self.current_time = current_time
32 self.game_data = game_data
33 self.background = self.make_background()
34 self.enemy_pos_list = []
35 self.enemy_group = self.make_enemies()
36 self.player_group = self.make_player()
37 self.info_box = InfoBox()
38 self.arrow = SelectArrow(self.enemy_group)
39 self.select_box = SelectBox()
40 self.state = SELECT_ACTION
41 self.select_action_state_dict = self.make_selection_state_dict()
42 self.name = 'battle'
43 self.next = game_data['last state']
44 self.observer = Observer(self)
45
46 def make_background(self):
47 """Make the blue/black background"""
48 background = pg.sprite.Sprite()
49 surface = pg.Surface(c.SCREEN_SIZE).convert()
50 surface.fill(c.BLACK_BLUE)
51 background.image = surface
52 background.rect = background.image.get_rect()
53 background_group = pg.sprite.Group(background)
54
55 return background_group
56
57 def make_enemies(self):
58 """Make the enemies for the battle. Return sprite group"""
59 group = pg.sprite.Group()
60 columns = random.randint(1,3)
61 rows = random.randint(1,3)
62
63 for column in range(columns):
64 for row in range(rows):
65 x = (column * 100) + 100
66 y = (row * 100) + 100
67 enemy = person.Person('devil', x, y, 'down', 'battle resting')
68 enemy.image = pg.transform.scale2x(enemy.image)
69 group.add(enemy)
70 self.enemy_pos_list.append(enemy.rect.topleft)
71
72 return group
73
74 def make_player(self):
75 """Make the sprite for the player's character"""
76 player = person.Player('left', 630, 220, 'battle resting', 1)
77 player.image = pg.transform.scale2x(player.image)
78 player_group = pg.sprite.Group(player)
79
80 return player_group
81
82 def make_selection_state_dict(self):
83 """
84 Make a dictionary of states with arrow coordinates as keys.
85 """
86 pos_list = self.arrow.make_select_action_pos_list()
87 state_list = [SELECT_ENEMY, SELECT_ITEM, SELECT_MAGIC, RUN_AWAY]
88 return dict(zip(pos_list, state_list))
89
90 def update(self, surface, keys, current_time):
91 """Update the battle state"""
92 self.check_input(keys)
93 self.enemy_group.update(current_time)
94 self.player_group.update(keys, current_time)
95 self.select_box.update()
96 self.arrow.update(keys)
97 self.info_box.update(self.state)
98 self.draw_battle(surface)
99
100 def check_input(self, keys):
101 """
102 Check user input to navigate GUI.
103 """
104 if keys[pg.K_RETURN]:
105 self.notify(END_BATTLE)
106
107 elif keys[pg.K_SPACE] and self.state == SELECT_ACTION:
108 self.state = self.select_action_state_dict[self.arrow.rect.topleft]
109 self.notify(self.state)
110
111 def notify(self, event):
112 """
113 Notify observer of event.
114 """
115 self.observer.on_notify(event)
116
117 def end_battle(self):
118 """
119 End battle and flip back to previous state.
120 """
121 self.game_data['last state'] = self.name
122 self.done = True
123
124 def draw_battle(self, surface):
125 """Draw all elements of battle state"""
126 self.background.draw(surface)
127 self.enemy_group.draw(surface)
128 self.player_group.draw(surface)
129 surface.blit(self.info_box.image, self.info_box.rect)
130 surface.blit(self.select_box.image, self.select_box.rect)
131 surface.blit(self.arrow.image, self.arrow.rect)
132
133
134class Observer(object):
135 """
136 Observes events of battle and passes info to components.
137 """
138 def __init__(self, level):
139 self.level = level
140 self.info_box = level.info_box
141 self.select_box = level.info_box
142 self.arrow = level.arrow
143 self.player = level.player_group
144 self.enemies = level.enemy_group
145 self.event_dict = self.make_event_dict()
146
147 def make_event_dict(self):
148 """
149 Make a dictionary of events the Observer can
150 receive.
151 """
152 event_dict = {END_BATTLE: self.end_battle,
153 SELECT_ACTION: self.select_action,
154 SELECT_ENEMY: self.select_enemy,
155 ENEMY_ATTACK: self.enemy_attack,
156 PLAYER_ATTACK: self.player_attack,
157 RUN_AWAY: self.run_away}
158
159 return event_dict
160
161 def on_notify(self, event):
162 """
163 Notify Observer of event.
164 """
165 if event in self.event_dict:
166 self.event_dict[event]()
167
168 def end_battle(self):
169 """
170 End Battle and flip to previous state.
171 """
172 self.level.end_battle()
173
174 def select_action(self):
175 """
176 Set components to select action.
177 """
178 self.level.state = SELECT_ACTION
179 self.arrow.index = 0
180
181 def select_enemy(self):
182 self.level.state = SELECT_ENEMY
183 self.arrow.state = SELECT_ENEMY
184
185 def enemy_attack(self):
186 pass
187
188 def player_attack(self):
189 pass
190
191 def run_away(self):
192 pass
193
194
195class InfoBox(object):
196 """
197 Info box that describes attack damage and other battle
198 related information.
199 """
200 def __init__(self):
201 self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
202 self.message_dict = self.make_message_dict()
203 self.image = self.make_image('select action')
204 self.rect = self.image.get_rect(bottom=608)
205
206 def make_message_dict(self):
207 """
208 Make dictionary of states Battle info can be in.
209 """
210 message_dict = {SELECT_ACTION: 'Select an action.',
211 SELECT_MAGIC: 'Select a magic spell.',
212 SELECT_ITEM: 'Select an item.',
213 SELECT_ENEMY: 'Select an enemy.',
214 ENEMY_ATTACK: 'The enemy attacks player!',
215 PLAYER_ATTACK: 'Player attacks enemy.',
216 RUN_AWAY: 'Run away'}
217
218 return message_dict
219
220 def make_image(self, state):
221 """
222 Make image out of box and message.
223 """
224 image = setup.GFX['shopbox']
225 rect = image.get_rect(bottom=608)
226 surface = pg.Surface(rect.size)
227 surface.set_colorkey(c.BLACK)
228 surface.blit(image, (0, 0))
229
230 text_surface = self.font.render(self.message_dict[state], True, c.NEAR_BLACK)
231 text_rect = text_surface.get_rect(x=50, y=50)
232 surface.blit(text_surface, text_rect)
233
234 return surface
235
236 def update(self, state):
237 self.image = self.make_image(state)
238
239
240class SelectBox(object):
241 """
242 Box to select whether to attack, use item, use magic or run away.
243 """
244 def __init__(self):
245 self.font = pg.font.Font(setup.FONTS[c.MAIN_FONT], 22)
246 self.slots = self.make_slots()
247 self.image = self.make_image()
248 self.rect = self.image.get_rect(bottom=608,
249 right=800)
250
251 def make_image(self):
252 """
253 Make the box image for
254 """
255 image = setup.GFX['goldbox']
256 rect = image.get_rect(bottom=608)
257 surface = pg.Surface(rect.size)
258 surface.set_colorkey(c.BLACK)
259 surface.blit(image, (0, 0))
260
261 for text in self.slots:
262 text_surface = self.font.render(text, True, c.NEAR_BLACK)
263 text_rect = text_surface.get_rect(x=self.slots[text]['x'],
264 y=self.slots[text]['y'])
265 surface.blit(text_surface, text_rect)
266
267 return surface
268
269 def make_slots(self):
270 """
271 Make the slots that hold the text selections, and locations.
272 """
273 slot_dict = {}
274 selections = ['Attack', 'Items', 'Magic', 'Run']
275
276 for i, text in enumerate(selections):
277 slot_dict[text] = {'x': 150,
278 'y': (i*34)+10}
279
280 return slot_dict
281
282 def update(self):
283 """
284 Update components.
285 """
286 self.image = self.make_image()
287
288
289class SelectArrow(object):
290 """Small arrow for menu"""
291 def __init__(self, enemy_group):
292 self.image = setup.GFX['smallarrow']
293 self.rect = self.image.get_rect()
294 self.state = 'select action'
295 self.state_dict = self.make_state_dict()
296 self.pos_list = self.make_select_action_pos_list()
297 self.index = 0
298 self.rect.topleft = self.pos_list[self.index]
299 self.allow_input = False
300 self.enemies = enemy_group
301
302 def make_state_dict(self):
303 """Make state dictionary"""
304 state_dict = {'select action': self.select_action,
305 'select enemy': self.select_enemy}
306
307 return state_dict
308
309 def select_action(self, keys):
310 """
311 Select what action the player should take.
312 """
313 self.pos_list = self.make_select_action_pos_list()
314 self.rect.topleft = self.pos_list[self.index]
315
316 if self.allow_input:
317 if keys[pg.K_DOWN] and self.index < (len(self.pos_list) - 1):
318 self.index += 1
319 self.allow_input = False
320 elif keys[pg.K_UP] and self.index > 0:
321 self.index -= 1
322 self.allow_input = False
323
324 if keys[pg.K_DOWN] == False and keys[pg.K_UP] == False:
325 self.allow_input = True
326
327
328 def make_select_action_pos_list(self):
329 """
330 Make the list of positions the arrow can be in.
331 """
332 pos_list = []
333
334 for i in range(4):
335 x = 590
336 y = (i * 34) + 472
337 pos_list.append((x, y))
338
339 return pos_list
340
341 def make_select_enemy_pos_list(self):
342 """
343 Make the list of positions the arrow can be when selecting
344 enemy.
345 """
346 pos_list = []
347
348 for enemy in self.enemies:
349 x = enemy.rect.x - 10
350 y = enemy.rect.y - 10
351 pos_list.append((x, y))
352
353 print pos_list
354
355 return pos_list
356
357
358 def select_enemy(self, keys):
359 """
360 Select what enemy you want to take action on.
361 """
362 self.pos_list = self.make_select_enemy_pos_list()
363 self.rect.topleft = self.pos_list[self.index]
364
365 if self.allow_input:
366 if keys[pg.K_DOWN] and self.index < (len(self.pos_list) - 1):
367 self.index += 1
368 self.allow_input = False
369 elif keys[pg.K_UP] and self.index > 0:
370 self.index -= 1
371 self.allow_input = False
372 elif keys[pg.K_RIGHT] and self.index < (len(self.pos_list) - 4):
373 self.index += 3
374 self.allow_input = False
375 elif keys[pg.K_RIGHT] and self.index >= 3:
376 self.index -= 3
377 self.allow_input = False
378
379 if keys[pg.K_DOWN] == False and keys[pg.K_UP] == False \
380 and keys[pg.K_RIGHT] and keys[pg.K_LEFT]:
381 self.allow_input = True
382
383
384 def enter_select_action(self):
385 """
386 Assign values for the select action state.
387 """
388 pass
389
390 def enter_select_enemy(self):
391 """
392 Assign values for the select enemy state.
393 """
394 pass
395
396 def update(self, keys):
397 """
398 Update arrow position.
399 """
400 state_function = self.state_dict[self.state]
401 state_function(keys)
402
403 def draw(self, surface):
404 """
405 Draw to surface.
406 """
407 surface.blit(self.image, self.rect)
408