data/states/levels.py (view raw)
1"""
2This is the base class for all level states (i.e. states
3where the player can move around the screen). Levels are
4differentiated by self.name and self.tmx_map.
5This 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
24 def startup(self, current_time, game_data):
25 """
26 Call when the State object is flipped to.
27 """
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 self.dialogue_handler = textbox.TextHandler(self)
49 self.state_dict = self.make_state_dict()
50 self.portals = self.make_level_portals()
51 self.menu_screen = player_menu.Player_Menu(game_data, self)
52
53 def make_viewport(self, map_image):
54 """
55 Create the viewport to view the level through.
56 """
57 map_rect = map_image.get_rect()
58 return setup.SCREEN.get_rect(bottom=map_rect.bottom)
59
60 def make_level_surface(self, map_image):
61 """
62 Create the surface all images are blitted to.
63 """
64 map_rect = map_image.get_rect()
65 map_width = map_rect.width
66 if self.name == 'town':
67 map_height = map_rect.height - 32
68 else:
69 map_height = map_rect.height
70 size = map_width, map_height
71
72 return pg.Surface(size).convert()
73
74 def make_player(self):
75 """
76 Make the player and sets location.
77 """
78 player = person.Player(self.game_data['last direction'])
79 last_state = self.game_data['last state']
80
81 for object in self.renderer.tmx_data.getObjects():
82 properties = object.__dict__
83 if properties['name'] == 'start point':
84 if last_state == properties['state']:
85 posx = properties['x'] * 2
86 posy = (properties['y'] * 2) - 32
87 player.rect.x = posx
88 player.rect.y = posy
89
90 return player
91
92 def make_blockers(self):
93 """
94 Make the blockers for the level.
95 """
96 blockers = []
97
98 for object in self.renderer.tmx_data.getObjects():
99 properties = object.__dict__
100 if properties['name'] == 'blocker':
101 left = properties['x'] * 2
102 top = ((properties['y']) * 2) - 32
103 blocker = pg.Rect(left, top, 32, 32)
104 blockers.append(blocker)
105
106 return blockers
107
108 def make_sprites(self):
109 """
110 Make any sprites for the level as needed.
111 """
112 sprites = pg.sprite.Group()
113
114 for object in self.renderer.tmx_data.getObjects():
115 properties = object.__dict__
116 if properties['name'] == 'sprite':
117 x = properties['x'] * 2
118 y = ((properties['y']) * 2) - 32
119
120 sprite_dict = {'oldman': person.Person('oldman',
121 x, y, 'down'),
122 'bluedressgirl': person.Person('femalevillager',
123 x, y, 'right',
124 'resting', 1),
125 'femalewarrior': person.Person('femvillager2',
126 x, y, 'down',
127 'autoresting'),
128 'devil': person.Person('devil', x, y,
129 'down', 'autoresting'),
130 'oldmanbrother': person.Person('oldmanbrother',
131 x, y, 'down'),
132 'soldier': person.Person('soldier',
133 x, y, 'down')}
134
135 sprite = sprite_dict[properties['type']]
136 self.assign_dialogue(sprite, properties)
137 sprites.add(sprite)
138
139 return sprites
140
141 def assign_dialogue(self, sprite, property_dict):
142 """
143 Assign dialogue from object property dictionaries in tmx maps to sprites.
144 """
145 dialogue_list = []
146 for i in range(int(property_dict['dialogue length'])):
147 dialogue_list.append(property_dict['dialogue'+str(i)])
148 sprite.dialogue = dialogue_list
149
150 def make_state_dict(self):
151 """
152 Make a dictionary of states the level can be in.
153 """
154 state_dict = {'normal': self.running_normally,
155 'dialogue': self.handling_dialogue,
156 'menu': self.goto_menu}
157
158 return state_dict
159
160 def make_level_portals(self):
161 """
162 Make the portals to switch state.
163 """
164 portal_group = pg.sprite.Group()
165
166 for object in self.renderer.tmx_data.getObjects():
167 properties = object.__dict__
168 if properties['name'] == 'portal':
169 posx = properties['x'] * 2
170 posy = (properties['y'] * 2) - 32
171 new_state = properties['type']
172 portal_group.add(portal.Portal(posx, posy, new_state))
173
174
175 return portal_group
176
177 def running_normally(self, surface, keys, current_time):
178 """
179 Update level normally.
180 """
181 self.check_for_dialogue()
182 self.check_for_portals()
183 self.player.update(keys, current_time)
184 self.sprites.update(current_time)
185 self.collision_handler.update(keys, current_time)
186 self.dialogue_handler.update(keys, current_time)
187 self.check_for_menu(keys)
188 self.viewport_update()
189
190 self.draw_level(surface)
191
192
193 def check_for_portals(self):
194 """
195 Check if the player walks into a door, requiring a level change.
196 """
197 portal = pg.sprite.spritecollideany(self.player, self.portals)
198
199 if portal and self.player.state == 'resting':
200 self.player.location = self.player.get_tile_location()
201 self.next = portal.name
202 self.update_game_data()
203 self.done = True
204
205
206 def check_for_menu(self, keys):
207 """
208 Check if player hits enter to go to menu.
209 """
210 if keys[pg.K_RETURN] and self.allow_input:
211 if self.player.state == 'resting':
212 self.state = 'menu'
213 self.allow_input = False
214
215 if not keys[pg.K_RETURN]:
216 self.allow_input = True
217
218
219 def update_game_data(self):
220 """
221 Update the persistant game data dictionary.
222 """
223 self.game_data['last location'] = self.player.location
224 self.game_data['last direction'] = self.player.direction
225 self.game_data['last state'] = self.name
226 self.set_new_start_pos()
227
228
229 def set_new_start_pos(self):
230 """
231 Set new start position based on previous state.
232 """
233 location = copy.deepcopy(self.game_data['last location'])
234 direction = self.game_data['last direction']
235
236 if self.next == 'player menu':
237 pass
238 elif direction == 'up':
239 location[1] += 1
240 elif direction == 'down':
241 location[1] -= 1
242 elif direction == 'left':
243 location[0] += 1
244 elif direction == 'right':
245 location[0] -= 1
246
247
248
249 def handling_dialogue(self, surface, keys, current_time):
250 """
251 Update only dialogue boxes.
252 """
253 self.dialogue_handler.update(keys, current_time)
254 self.draw_level(surface)
255
256
257 def goto_menu(self, surface, keys, *args):
258 """
259 Go to menu screen.
260 """
261 self.menu_screen.update(surface, keys)
262 self.menu_screen.draw(surface)
263
264
265 def check_for_dialogue(self):
266 """
267 Check if the level needs to freeze.
268 """
269 if self.dialogue_handler.textbox:
270 self.state = 'dialogue'
271
272 def update(self, surface, keys, current_time):
273 """
274 Update state.
275 """
276 state_function = self.state_dict[self.state]
277 state_function(surface, keys, current_time)
278
279 def viewport_update(self):
280 """
281 Update viewport so it stays centered on character,
282 unless at edge of map.
283 """
284 self.viewport.center = self.player.rect.center
285 self.viewport.clamp_ip(self.level_rect)
286
287 def draw_level(self, surface):
288 """
289 Blit all images to screen.
290 """
291 self.level_surface.blit(self.map_image, self.viewport, self.viewport)
292 self.level_surface.blit(self.player.image, self.player.rect)
293 self.sprites.draw(self.level_surface)
294
295 surface.blit(self.level_surface, (0, 0), self.viewport)
296 self.dialogue_handler.draw(surface)
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312