all repos — Legends-RPG @ 322ed0813ca073c324e0476bbf9412b05c1d71e0

A fantasy mini-RPG built with Python and Pygame.

data/states/levels.py (view raw)

  1__author__ = 'justinarmstrong'
  2"""
  3This is the base class all level states (i.e. states
  4where the player can move around the screen) inherit
  5from.  This class inherits from the generic state class
  6found in the tools.py module.
  7"""
  8
  9import copy
 10import pygame as pg
 11from .. import tools, collision
 12from .. components import person, textbox, portal
 13from . import player_menu
 14from .. import tilerender
 15from .. import setup
 16
 17
 18class LevelState(tools._State):
 19    def __init__(self, name):
 20        super(LevelState, self).__init__()
 21        self.name = name
 22        self.tmx_map = setup.TMX[name]
 23        self.map_width = None
 24        self.map_height = None
 25
 26    def startup(self, current_time, game_data):
 27        """Called when the State object is created"""
 28        self.game_data = game_data
 29        self.current_time = current_time
 30        self.state = 'normal'
 31        self.allow_input = False
 32        self.renderer = tilerender.Renderer(self.tmx_map)
 33        self.map_image = self.renderer.make_2x_map()
 34
 35        self.viewport = self.make_viewport(self.map_image)
 36        self.level_surface = self.make_level_surface(self.map_image)
 37        self.level_rect = self.level_surface.get_rect()
 38        self.player = None
 39        self.portals = None
 40        self.player = person.Player(game_data['last direction'])
 41        self.player = self.make_player()
 42        self.blockers = self.make_blockers()
 43        self.sprites = self.make_sprites()
 44
 45        self.collision_handler = collision.CollisionHandler(self.player,
 46                                                            self.blockers,
 47                                                            self.sprites)
 48
 49        self.dialogue_handler = textbox.TextHandler(self)
 50        self.state_dict = self.make_state_dict()
 51        self.portals = self.make_level_portals()
 52        self.menu_screen = player_menu.Player_Menu(game_data, self)
 53
 54    def make_viewport(self, map_image):
 55        """Create the viewport to view the level through"""
 56        map_rect = map_image.get_rect()
 57        return setup.SCREEN.get_rect(bottom=map_rect.bottom)
 58
 59    def make_level_surface(self, map_image):
 60        """Creates the surface all images are blitted to"""
 61        map_rect = map_image.get_rect()
 62        map_width = map_rect.width
 63        if self.name == 'town':
 64            map_height = map_rect.height - 32
 65        else:
 66            map_height = map_rect.height
 67        size = map_width, map_height
 68        return pg.Surface(size).convert()
 69
 70    def make_player(self):
 71        """Makes the player and sets location"""
 72        player = person.Player(self.game_data['last direction'])
 73        last_state = self.game_data['last state']
 74
 75        for object in self.renderer.tmx_data.getObjects():
 76            properties = object.__dict__
 77            if properties['name'] == 'start point':
 78                if last_state == properties['state']:
 79                    posx = properties['x'] * 2
 80                    posy = (properties['y'] * 2) - 32
 81                    player.rect.x = posx
 82                    player.rect.y = posy
 83
 84        return player
 85
 86    def make_blockers(self):
 87        """Make the blockers for the level"""
 88        blockers = []
 89
 90        for object in self.renderer.tmx_data.getObjects():
 91            properties = object.__dict__
 92            if properties['name'] == 'blocker':
 93                left = properties['x'] * 2
 94                top = ((properties['y']) * 2) - 32
 95                blocker = pg.Rect(left, top, 32, 32)
 96                blockers.append(blocker)
 97
 98        return blockers
 99
100    def make_sprites(self):
101        """
102        Make any sprites for the level as needed.
103        """
104        sprites = pg.sprite.Group()
105
106        for object in self.renderer.tmx_data.getObjects():
107            properties = object.__dict__
108            if properties['name'] == 'sprite':
109                x = properties['x'] * 2
110                y = ((properties['y']) * 2) - 32
111
112                sprite_dict = {'oldman': person.Person('oldman', x, y, 'down'),
113                               'bluedressgirl': person.Person('femalevillager', x, y, 'right', 'resting', 1),
114                               'femalewarrior': person.Person('femvillager2', x, y, 'down', 'autoresting'),
115                               'devil': person.Person('devil', x, y, 'down', 'autoresting'),
116                               'oldmanbrother': person.Person('oldmanbrother', x, y, 'down')}
117                
118                sprite = sprite_dict[properties['type']]
119                self.assign_dialogue(sprite, properties)
120                sprites.add(sprite)
121
122        return sprites
123
124    def assign_dialogue(self, sprite, property_dict):
125        """
126        Assign dialogue from object property dictionaries in tmx maps to sprites.
127        """
128        dialogue_list = []
129        for i in range(int(property_dict['dialogue length'])):
130            dialogue_list.append(property_dict['dialogue'+str(i)])
131            sprite.dialogue = dialogue_list
132
133    def make_state_dict(self):
134        """Make a dictionary of states the level can be in"""
135        state_dict = {'normal': self.running_normally,
136                      'dialogue': self.handling_dialogue,
137                      'menu': self.goto_menu}
138
139        return state_dict
140
141    def make_level_portals(self):
142        """Make the portals to switch state"""
143        portal_group = pg.sprite.Group()
144
145        for object in self.renderer.tmx_data.getObjects():
146            properties = object.__dict__
147            if properties['name'] == 'portal':
148                posx = properties['x'] * 2
149                posy = (properties['y'] * 2) - 32
150                new_state = properties['type']
151                portal_group.add(portal.Portal(posx, posy, new_state))
152
153
154        return portal_group
155
156    def running_normally(self, surface, keys, current_time):
157        """
158        Update level normally.
159        """
160        self.check_for_dialogue()
161        self.check_for_portals()
162        self.player.update(keys, current_time)
163        self.sprites.update(current_time)
164        self.collision_handler.update(keys, current_time)
165        self.dialogue_handler.update(keys, current_time)
166        self.check_for_menu(keys)
167        self.viewport_update()
168
169        self.draw_level(surface)
170
171
172    def check_for_portals(self):
173        """
174        Check if the player walks into a door, requiring a level change.
175        """
176        portal = pg.sprite.spritecollideany(self.player, self.portals)
177
178        if portal and self.player.state == 'resting':
179            self.player.location = self.player.get_tile_location()
180            self.next = portal.name
181            self.update_game_data()
182            self.done = True
183
184
185    def check_for_menu(self, keys):
186        """
187        Check if player hits enter to go to menu.
188        """
189        if keys[pg.K_RETURN] and self.allow_input:
190            if self.player.state == 'resting':
191                self.state = 'menu'
192                self.allow_input = False
193
194        if not keys[pg.K_RETURN]:
195            self.allow_input = True
196
197
198    def update_game_data(self):
199        """
200        Update the persistant game data dictionary.
201        """
202        self.game_data['last location'] = self.player.location
203        self.game_data['last direction'] = self.player.direction
204        self.game_data['last state'] = self.name
205        self.set_new_start_pos()
206
207
208    def set_new_start_pos(self):
209        """Set new start position based on previous state"""
210        location = copy.deepcopy(self.game_data['last location'])
211        direction = self.game_data['last direction']
212
213        if self.next == 'player menu':
214            pass
215        elif direction == 'up':
216            location[1] += 1
217        elif direction == 'down':
218            location[1] -= 1
219        elif direction == 'left':
220            location[0] += 1
221        elif direction == 'right':
222            location[0] -= 1
223
224
225
226    def handling_dialogue(self, surface, keys, current_time):
227        """Update only dialogue boxes"""
228        self.dialogue_handler.update(keys, current_time)
229        self.draw_level(surface)
230
231
232    def goto_menu(self, surface, keys, *args):
233        """Go to menu screen"""
234        self.menu_screen.update(surface, keys)
235        self.menu_screen.draw(surface)
236
237
238    def check_for_dialogue(self):
239        """Check if the level needs to freeze"""
240        if self.dialogue_handler.textbox:
241            self.state = 'dialogue'
242
243    def update(self, surface, keys, current_time):
244        """Updates state"""
245        state_function = self.state_dict[self.state]
246        state_function(surface, keys, current_time)
247
248    def viewport_update(self):
249        """Viewport stays centered on character, unless at edge of map"""
250        self.viewport.center = self.player.rect.center
251        self.viewport.clamp_ip(self.level_rect)
252
253    def draw_level(self, surface):
254        """Blits all images to screen"""
255        self.level_surface.blit(self.map_image, self.viewport, self.viewport)
256        self.level_surface.blit(self.player.image, self.player.rect)
257        self.sprites.draw(self.level_surface)
258
259        surface.blit(self.level_surface, (0, 0), self.viewport)
260        self.dialogue_handler.draw(surface)
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276