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