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