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, battlegui, observer
7from .. components import person, attack, attackitems
8from .. import constants as c
9
10
11
12class Battle(tools._State):
13 def __init__(self):
14 super(Battle, self).__init__()
15
16 def startup(self, current_time, game_data):
17 """Initialize state attributes"""
18 self.current_time = current_time
19 self.allow_input = False
20 self.allow_info_box_change = False
21 self.game_data = game_data
22 self.background = self.make_background()
23 self.enemy_group, self.enemy_pos_list, self.enemy_list = self.make_enemies()
24 self.enemy_index = 0
25 self.player = self.make_player()
26 self.attack_animations = pg.sprite.Group()
27 self.info_box = battlegui.InfoBox(game_data)
28 self.arrow = battlegui.SelectArrow(self.enemy_pos_list,
29 self.info_box)
30 self.select_box = battlegui.SelectBox()
31 self.player_health = battlegui.PlayerHealth(self.select_box.rect,
32 self.game_data)
33 self.sword = attackitems.Sword(self.player)
34 self.attacked_enemy = None
35 self.attacking_enemy = None
36 self.state = c.SELECT_ACTION
37 self.select_action_state_dict = self.make_selection_state_dict()
38 self.name = 'battle'
39 self.next = game_data['last state']
40 self.observers = [observer.Battle(self)]
41 self.player.observers.extend(self.observers)
42
43 def make_background(self):
44 """Make the blue/black background"""
45 background = pg.sprite.Sprite()
46 surface = pg.Surface(c.SCREEN_SIZE).convert()
47 surface.fill(c.BLACK_BLUE)
48 background.image = surface
49 background.rect = background.image.get_rect()
50 background_group = pg.sprite.Group(background)
51
52 return background_group
53
54 def make_enemies(self):
55 """Make the enemies for the battle. Return sprite group"""
56 pos_list = []
57
58 for column in range(3):
59 for row in range(3):
60 x = (column * 100) + 100
61 y = (row * 100) + 100
62 pos_list.append([x,y])
63
64 enemy_group = pg.sprite.Group()
65
66 for enemy in range(random.randint(1, 6)):
67 enemy_group.add(person.Person('devil', 0, 0,
68 'down', 'battle resting'))
69
70 for i, enemy in enumerate(enemy_group):
71 enemy.rect.topleft = pos_list[i]
72 enemy.image = pg.transform.scale2x(enemy.image)
73 enemy.index = i
74
75 enemy_list = [enemy for enemy in enemy_group]
76
77 return enemy_group, pos_list[0:len(enemy_group)], enemy_list
78
79 def make_player(self):
80 """Make the sprite for the player's character"""
81 player = person.Player('left', 630, 220, 'battle resting', 1)
82 player.image = pg.transform.scale2x(player.image)
83
84 return player
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 = [c.SELECT_ENEMY, c.SELECT_ITEM, c.SELECT_MAGIC, c.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.check_if_battle_won()
98 self.enemy_group.update(current_time)
99 self.player.update(keys, current_time)
100 self.attack_animations.update()
101 self.info_box.update()
102 self.arrow.update(keys)
103
104 self.draw_battle(surface)
105
106 def check_input(self, keys):
107 """
108 Check user input to navigate GUI.
109 """
110 if self.allow_input:
111 if keys[pg.K_RETURN]:
112 self.notify(c.END_BATTLE)
113
114 elif keys[pg.K_SPACE]:
115 if self.state == c.SELECT_ACTION:
116 self.state = self.select_action_state_dict[
117 self.arrow.rect.topleft]
118 self.notify(self.state)
119
120 elif self.state == c.SELECT_ENEMY:
121 self.state = c.PLAYER_ATTACK
122 self.notify(self.state)
123
124 elif self.state == c.PLAYER_ATTACK:
125 self.state = c.ENEMY_DEAD
126 self.info_box.state = c.ENEMY_DEAD
127
128 elif self.state == c.ENEMY_DEAD:
129 if len(self.enemy_list):
130 self.state = c.ENEMY_ATTACK
131 else:
132 self.state = c.BATTLE_WON
133 self.notify(self.state)
134
135 elif self.state == c.SELECT_ITEM or self.state == c.SELECT_MAGIC:
136 if self.arrow.index == (len(self.arrow.pos_list) - 1):
137 self.state = c.SELECT_ACTION
138 self.notify(self.state)
139
140 self.allow_input = False
141
142 if keys[pg.K_RETURN] == False and keys[pg.K_SPACE] == False:
143 self.allow_input = True
144
145 def check_if_battle_won(self):
146 """
147 Check if state is SELECT_ACTION and there are no enemies left.
148 """
149 if self.state == c.SELECT_ACTION:
150 if len(self.enemy_group) == 0:
151 self.notify(c.BATTLE_WON)
152
153 def notify(self, event):
154 """
155 Notify observer of event.
156 """
157 for observer in self.observers:
158 observer.on_notify(event)
159
160 def end_battle(self):
161 """
162 End battle and flip back to previous state.
163 """
164 self.game_data['last state'] = self.name
165 self.done = True
166
167 def attack_enemy(self):
168 enemy = self.player.attacked_enemy
169 self.set_enemy_indices()
170
171 if enemy:
172 enemy.kill()
173 self.enemy_list.pop(enemy.index)
174 self.enemy_index = 0
175 posx = enemy.rect.x - 32
176 posy = enemy.rect.y - 64
177 fire_sprite = attack.Fire(posx, posy)
178 self.attack_animations.add(fire_sprite)
179 self.player.attacked_enemy = None
180
181 def set_enemy_indices(self):
182 for i, enemy in enumerate(self.enemy_list):
183 enemy.index = i
184
185
186 def draw_battle(self, surface):
187 """Draw all elements of battle state"""
188 self.background.draw(surface)
189 self.enemy_group.draw(surface)
190 self.attack_animations.draw(surface)
191 surface.blit(self.player.image, self.player.rect)
192 surface.blit(self.info_box.image, self.info_box.rect)
193 surface.blit(self.select_box.image, self.select_box.rect)
194 surface.blit(self.arrow.image, self.arrow.rect)
195 self.player_health.draw(surface)
196 self.sword.draw(surface)
197
198