all repos — Legends-RPG @ d96752daa4c3f2dd549a2434ddabf1086675b823

A fantasy mini-RPG built with Python and Pygame.

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.timer = current_time
 20        self.allow_input = False
 21        self.allow_info_box_change = False
 22        self.game_data = game_data
 23        self.background = self.make_background()
 24        self.enemy_group, self.enemy_pos_list, self.enemy_list = self.make_enemies()
 25        self.enemy_index = 0
 26        self.player = self.make_player()
 27        self.attack_animations = pg.sprite.Group()
 28        self.info_box = battlegui.InfoBox(game_data)
 29        self.arrow = battlegui.SelectArrow(self.enemy_pos_list,
 30                                           self.info_box)
 31        self.select_box = battlegui.SelectBox()
 32        self.player_health = battlegui.PlayerHealth(self.select_box.rect,
 33                                                    self.game_data)
 34        self.sword = attackitems.Sword(self.player)
 35        self.attacked_enemy = None
 36        self.attacking_enemy = None
 37        self.state = c.SELECT_ACTION
 38        self.select_action_state_dict = self.make_selection_state_dict()
 39        self.name = 'battle'
 40        self.next = game_data['last state']
 41        self.observers = [observer.Battle(self)]
 42        self.player.observers.extend(self.observers)
 43
 44    def make_background(self):
 45        """Make the blue/black background"""
 46        background = pg.sprite.Sprite()
 47        surface = pg.Surface(c.SCREEN_SIZE).convert()
 48        surface.fill(c.BLACK_BLUE)
 49        background.image = surface
 50        background.rect = background.image.get_rect()
 51        background_group = pg.sprite.Group(background)
 52
 53        return background_group
 54
 55    def make_enemies(self):
 56        """Make the enemies for the battle. Return sprite group"""
 57        pos_list  = []
 58
 59        for column in range(3):
 60            for row in range(3):
 61                x = (column * 100) + 100
 62                y = (row * 100) + 100
 63                pos_list.append([x,y])
 64
 65        enemy_group = pg.sprite.Group()
 66
 67        for enemy in range(random.randint(1, 6)):
 68            enemy_group.add(person.Person('devil', 0, 0,
 69                                          'down', 'battle resting'))
 70
 71        for i, enemy in enumerate(enemy_group):
 72            enemy.rect.topleft = pos_list[i]
 73            enemy.image = pg.transform.scale2x(enemy.image)
 74            enemy.index = i
 75
 76        enemy_list = [enemy for enemy in enemy_group]
 77
 78        return enemy_group, pos_list[0:len(enemy_group)], enemy_list
 79
 80    def make_player(self):
 81        """Make the sprite for the player's character"""
 82        player = person.Player('left', 630, 220, 'battle resting', 1)
 83        player.image = pg.transform.scale2x(player.image)
 84
 85        return player
 86
 87    def make_selection_state_dict(self):
 88        """
 89        Make a dictionary of states with arrow coordinates as keys.
 90        """
 91        pos_list = self.arrow.make_select_action_pos_list()
 92        state_list = [c.SELECT_ENEMY, c.SELECT_ITEM, c.SELECT_MAGIC, c.RUN_AWAY]
 93        return dict(zip(pos_list, state_list))
 94
 95    def update(self, surface, keys, current_time):
 96        """Update the battle state"""
 97        self.current_time = current_time
 98        self.check_input(keys)
 99        self.check_for_timed_events()
100        self.check_if_battle_won()
101        self.enemy_group.update(current_time)
102        self.player.update(keys, current_time)
103        self.attack_animations.update()
104        self.info_box.update()
105        self.arrow.update(keys)
106
107        self.draw_battle(surface)
108
109    def check_input(self, keys):
110        """
111        Check user input to navigate GUI.
112        """
113        if self.allow_input:
114            if keys[pg.K_RETURN]:
115                self.notify(c.END_BATTLE)
116
117            elif keys[pg.K_SPACE]:
118                if self.state == c.SELECT_ACTION:
119                    self.state = self.select_action_state_dict[
120                        self.arrow.rect.topleft]
121                    self.notify(self.state)
122
123                elif self.state == c.SELECT_ENEMY:
124                    self.state = c.PLAYER_ATTACK
125                    self.notify(self.state)
126
127                elif self.state == c.PLAYER_ATTACK:
128                    self.state = c.ENEMY_DEAD
129                    self.info_box.state = c.ENEMY_DEAD
130
131                elif self.state == c.SELECT_ITEM or self.state == c.SELECT_MAGIC:
132                    if self.arrow.index == (len(self.arrow.pos_list) - 1):
133                        self.state = c.SELECT_ACTION
134                        self.notify(self.state)
135
136            self.allow_input = False
137
138        if keys[pg.K_RETURN] == False and keys[pg.K_SPACE] == False:
139            self.allow_input = True
140
141    def check_for_timed_events(self):
142        """
143        Check if amount of time has passed for timed events.
144        """
145        timed_states = [c.DISPLAY_ENEMY_ATTACK_DAMAGE, c.ENEMY_HIT, c.ENEMY_DEAD]
146
147        if self.state in timed_states:
148            if (self.current_time - self.timer) > 1500:
149                if self.state == c.DISPLAY_ENEMY_ATTACK_DAMAGE:
150                    if self.enemy_index == (len(self.enemy_list) - 1):
151                        self.state = c.SELECT_ACTION
152                    else:
153                        self.state = c.SWITCH_ENEMY
154                elif self.state == c.ENEMY_HIT:
155                    self.state = c.ENEMY_DEAD
156                elif self.state == c.ENEMY_DEAD:
157                    if len(self.enemy_list):
158                        self.state = c.ENEMY_ATTACK
159                    else:
160                        self.state = c.BATTLE_WON
161
162                self.notify(self.state)
163
164
165    def check_if_battle_won(self):
166        """
167        Check if state is SELECT_ACTION and there are no enemies left.
168        """
169        if self.state == c.SELECT_ACTION:
170            if len(self.enemy_group) == 0:
171                self.notify(c.BATTLE_WON)
172
173    def notify(self, event):
174        """
175        Notify observer of event.
176        """
177        for observer in self.observers:
178            observer.on_notify(event)
179
180    def end_battle(self):
181        """
182        End battle and flip back to previous state.
183        """
184        self.game_data['last state'] = self.name
185        self.done = True
186
187    def attack_enemy(self):
188        enemy = self.player.attacked_enemy
189        self.set_enemy_indices()
190
191        if enemy:
192            enemy.kill()
193            self.enemy_list.pop(enemy.index)
194            self.enemy_index = 0
195            posx = enemy.rect.x - 32
196            posy = enemy.rect.y - 64
197            fire_sprite = attack.Fire(posx, posy)
198            self.attack_animations.add(fire_sprite)
199            self.player.attacked_enemy = None
200
201    def set_enemy_indices(self):
202        for i, enemy in enumerate(self.enemy_list):
203            enemy.index = i
204
205
206    def draw_battle(self, surface):
207        """Draw all elements of battle state"""
208        self.background.draw(surface)
209        self.enemy_group.draw(surface)
210        self.attack_animations.draw(surface)
211        surface.blit(self.player.image, self.player.rect)
212        surface.blit(self.info_box.image, self.info_box.rect)
213        surface.blit(self.select_box.image, self.select_box.rect)
214        surface.blit(self.arrow.image, self.arrow.rect)
215        self.player_health.draw(surface)
216        self.sword.draw(surface)
217
218    def player_damaged(self, damage):
219        self.game_data['player stats']['Health']['current'] -= damage
220
221    def set_timer_to_current_time(self):
222        """Set the timer to the current time."""
223        self.timer = self.current_time
224
225