all repos — Legends-RPG @ 68aafd99d9f82e78e31817a43b72cdd0d7ce9900

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                left = properties['x'] * 2
110                top = ((properties['y']) * 2) - 32
111
112                sprite_dict = {'oldman': person.OldMan(left, top),
113                               'bluedressgirl': person.FemaleVillager(left, top, 'right'),
114                               'femalewarrior': person.FemaleVillager2(left, top),
115                               'devil': person.Devil(left, top)}
116
117                sprite = sprite_dict[properties['type']]
118                self.assign_dialogue(sprite, properties)
119                sprites.add(sprite)
120
121        return sprites
122
123    def assign_dialogue(self, sprite, property_dict):
124        """
125        Assign dialogue from object property dictionaries in tmx maps to sprites.
126        """
127        dialogue_list = []
128        for i in range(int(property_dict['dialogue length'])):
129            dialogue_list.append(property_dict['dialogue'+str(i)])
130            sprite.dialogue = dialogue_list
131
132    def make_state_dict(self):
133        """Make a dictionary of states the level can be in"""
134        state_dict = {'normal': self.running_normally,
135                      'dialogue': self.handling_dialogue,
136                      'menu': self.goto_menu}
137
138        return state_dict
139
140    def make_level_portals(self):
141        """Make the portals to switch state"""
142        portal_group = pg.sprite.Group()
143
144        for object in self.renderer.tmx_data.getObjects():
145            properties = object.__dict__
146            if properties['name'] == 'portal':
147                posx = properties['x'] * 2
148                posy = (properties['y'] * 2) - 32
149                new_state = properties['type']
150                portal_group.add(portal.Portal(posx, posy, new_state))
151
152
153        return portal_group
154
155    def running_normally(self, surface, keys, current_time):
156        """
157        Update level normally.
158        """
159        self.check_for_dialogue()
160        self.check_for_portals()
161        self.player.update(keys, current_time)
162        self.sprites.update(current_time)
163        self.collision_handler.update(keys, current_time)
164        self.dialogue_handler.update(keys, current_time)
165        self.check_for_menu(keys)
166        self.viewport_update()
167
168        self.draw_level(surface)
169
170
171    def check_for_portals(self):
172        """
173        Check if the player walks into a door, requiring a level change.
174        """
175        portal = pg.sprite.spritecollideany(self.player, self.portals)
176
177        if portal and self.player.state == 'resting':
178            self.player.location = self.player.get_tile_location()
179            self.next = portal.name
180            self.update_game_data()
181            self.done = True
182
183
184    def check_for_menu(self, keys):
185        """
186        Check if player hits enter to go to menu.
187        """
188        if keys[pg.K_RETURN] and self.allow_input:
189            if self.player.state == 'resting':
190                self.state = 'menu'
191                self.allow_input = False
192
193        if not keys[pg.K_RETURN]:
194            self.allow_input = True
195
196
197    def update_game_data(self):
198        """
199        Update the persistant game data dictionary.
200        """
201        self.game_data['last location'] = self.player.location
202        self.game_data['last direction'] = self.player.direction
203        self.game_data['last state'] = self.name
204        self.set_new_start_pos()
205
206
207    def set_new_start_pos(self):
208        """Set new start position based on previous state"""
209        location = copy.deepcopy(self.game_data['last location'])
210        direction = self.game_data['last direction']
211
212        if self.next == 'player menu':
213            pass
214        elif direction == 'up':
215            location[1] += 1
216        elif direction == 'down':
217            location[1] -= 1
218        elif direction == 'left':
219            location[0] += 1
220        elif direction == 'right':
221            location[0] -= 1
222
223
224
225    def handling_dialogue(self, surface, keys, current_time):
226        """Update only dialogue boxes"""
227        self.dialogue_handler.update(keys, current_time)
228        self.draw_level(surface)
229
230
231    def goto_menu(self, surface, keys, *args):
232        """Go to menu screen"""
233        self.menu_screen.update(surface, keys)
234        self.menu_screen.draw(surface)
235
236
237    def check_for_dialogue(self):
238        """Check if the level needs to freeze"""
239        if self.dialogue_handler.textbox:
240            self.state = 'dialogue'
241
242    def update(self, surface, keys, current_time):
243        """Updates state"""
244        state_function = self.state_dict[self.state]
245        state_function(surface, keys, current_time)
246
247    def viewport_update(self):
248        """Viewport stays centered on character, unless at edge of map"""
249        self.viewport.center = self.player.rect.center
250        self.viewport.clamp_ip(self.level_rect)
251
252    def draw_level(self, surface):
253        """Blits all images to screen"""
254        self.level_surface.blit(self.map_image, self.viewport, self.viewport)
255        self.level_surface.blit(self.player.image, self.player.rect)
256        self.sprites.draw(self.level_surface)
257
258        surface.blit(self.level_surface, (0, 0), self.viewport)
259        self.dialogue_handler.draw(surface)
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275