all repos — Legends-RPG @ 6a76a9050bb2ef8e1763815358e329c5556c86f8

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, 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