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