9ba5ea279030242ffbc388b2dc80f7a0468c0fdb
[butaba-adventures.git] / maingame.py
1 import pygame
2 import sys
3 import random
4 import os.path
5 import cPickle
6
7 import level
8 import butaba
9 import utility
10 import gameobjects
11 import constants
12 import npcs
13 import gamestate
14
15 class MainGame:
16
17 # initialize the game
18 def __init__ (self):
19 pygame.init ()
20 self.screen = pygame.display.set_mode ((720, 512))
21 pygame.display.set_caption ("The Adventures of Butaba")
22
23 # initalize background graphics
24 self.img_tileset = pygame.image.load (os.path.join ("background", "tileset.png")).convert ()
25
26 self.img_menu = pygame.image.load (os.path.join ("background", "menu_screen.png")).convert ()
27
28 self.img_inventory = pygame.image.load (os.path.join ("background", "inventory.png")).convert ()
29
30 self.img_chestbg = pygame.image.load (os.path.join ("background", "chestcontent.png")).convert ()
31
32 self.img_dialogue = pygame.image.load (os.path.join ("background", "dialog_screen.png")).convert ()
33 self.img_dialogue.set_colorkey (pygame.Color (0, 255, 0))
34
35
36 # initialize object graphics
37 self.img_redpotion = pygame.image.load (os.path.join ("objects", "red-potion.png")).convert ()
38 self.img_redpotion.set_colorkey (pygame.Color (0, 255, 0))
39 self.img_goldcoins = pygame.image.load (os.path.join ("objects", "gold-coins.png")).convert ()
40 self.img_goldcoins.set_colorkey (pygame.Color (0, 255, 0))
41 self.img_wand = pygame.image.load (os.path.join ("objects", "wand.png")).convert ()
42 self.img_wand.set_colorkey (pygame.Color (0, 255, 0))
43 self.img_bulb = pygame.image.load (os.path.join ("objects", "bulb.png")).convert ()
44 self.img_bulb.set_colorkey (pygame.Color (0, 255, 0))
45 self.img_lightning = pygame.image.load (os.path.join ("objects", "lightning.png")).convert ()
46 self.img_lightning.set_colorkey (pygame.Color (0, 255, 0))
47 self.img_key = pygame.image.load (os.path.join ("objects", "key.png")).convert ()
48 self.img_key.set_colorkey (pygame.Color (0, 255, 0))
49 self.img_key2 = pygame.image.load (os.path.join ("objects", "key2.png")).convert ()
50 self.img_key2.set_colorkey (pygame.Color (0, 255, 0))
51 self.img_chest = pygame.image.load (os.path.join ("objects", "chest.png")).convert ()
52 self.img_chest.set_colorkey (pygame.Color (0, 255, 0))
53 self.img_bucket = pygame.image.load (os.path.join ("objects", "bucket.png")).convert ()
54 self.img_bucket.set_colorkey (pygame.Color (0, 255, 0))
55
56 # initialize player graphics
57 self.img_butabafront = pygame.image.load (os.path.join ("sprite", "butaba-front.png")).convert ()
58 self.img_butabafront.set_colorkey (pygame.Color (0, 255, 0))
59 self.img_butababack = pygame.image.load (os.path.join ("sprite", "butaba-back.png")).convert ()
60 self.img_butababack.set_colorkey (pygame.Color (0, 255, 0))
61 self.img_butabaleft = pygame.image.load (os.path.join ("sprite", "butaba-left.png")).convert ()
62 self.img_butabaleft.set_colorkey (pygame.Color (0, 255, 0))
63 self.img_butabaright = pygame.image.load (os.path.join ("sprite", "butaba-right.png")).convert ()
64 self.img_butabaright.set_colorkey (pygame.Color (0, 255, 0))
65
66 # initialize NPC graphics
67 self.img_bulisa = pygame.image.load (os.path.join ("sprite", "bulisa.png")).convert ()
68 self.img_bulisa.set_colorkey (pygame.Color (0, 255, 0))
69
70 # initialize portraits
71 self.img_butaba_portrait = pygame.image.load (os.path.join ("portraits", "butaba.png")).convert ()
72 self.img_bulisa_portrait = pygame.image.load (os.path.join ("portraits", "bulisa.png")).convert ()
73
74 # set level data
75 self.setup_levels ()
76 # set current level and position of our character
77 self.currentlevel = self.level1
78
79 # set the status message
80 self.status_message = "Game started"
81
82 self.butaba = butaba.Butaba (5,0, butaba.Butaba.RIGHT)
83
84 # set up the levels and their interactions
85 def setup_levels (self):
86 # set up the objects first
87 chest1 = gameobjects.Chest (2, 6, "chest", self.img_chest, constants.KEY_CHEST1, True)
88 chest2 = gameobjects.Chest (6, 6, "chest", self.img_chest, constants.KEY_CHEST2, True)
89 key1 = gameobjects.Key (5, 3, "a chest key", self.img_key2, constants.KEY_CHEST1)
90 key2 = gameobjects.Key (5, 3, "a chest key", self.img_key, constants.KEY_CHEST2)
91 potion = gameobjects.HealthPotion (5, 2, self.img_redpotion)
92 gold50 = gameobjects.GoldCoins (6, 2, self.img_goldcoins, 50)
93 gold25 = gameobjects.GoldCoins (6, 2, self.img_goldcoins, 25)
94 gold10 = gameobjects.GoldCoins (6, 2, self.img_goldcoins, 10)
95 bucket = gameobjects.Bucket (6, 3, self.img_bucket)
96
97 well1 = gameobjects.Well (4, 7)
98 well2 = gameobjects.Well (5, 7)
99 well3 = gameobjects.Well (4, 8)
100 well4 = gameobjects.Well (5, 8)
101
102 npc_bulisa = npcs.Bulisa (4, 3, self.img_bulisa, self.img_bulisa_portrait,
103 [ os.path.join ("dialogues", "bulisa1.dlg"),
104 os.path.join ("dialogues", "bulisa2.dlg"),
105 os.path.join ("dialogues", "bulisa3.dlg"),
106 os.path.join ("dialogues", "bulisa4.dlg") ] )
107
108 chest1.objects = [ gold50, gold25, key2, gold10 ]
109
110 # create the levels
111 self.level1 = level.Level (cPickle.load (file (os.path.join ("levels", "level1.dat"))),
112 objects = [ chest1 ] )
113
114 self.level1w = level.Level (cPickle.load (file (os.path.join ("levels", "level1w.dat"))))
115
116 self.level1e = level.Level (cPickle.load (file (os.path.join ("levels", "level1e.dat"))),
117 objects = [ key1, potion, chest2 ], npcs = [ npc_bulisa ])
118
119 self.level1ee = level.Level (cPickle.load (file (os.path.join ("levels", "level1ee.dat"))),
120 objects = [ well1, well2, well3, well4 ])
121
122 self.level1n = level.Level (cPickle.load (file (os.path.join ("levels", "level1n.dat"))),
123 objects = [ bucket ])
124
125 # set up the interaction between levels
126 self.level1.levelright = self.level1e
127 self.level1.levelleft = self.level1w
128 self.level1e.levelleft = self.level1
129 self.level1e.levelright = self.level1ee
130 self.level1ee.levelleft = self.level1e
131 self.level1w.levelright = self.level1
132 self.level1.leveltop = self.level1n
133 self.level1n.levelbottom = self.level1
134
135 def main_loop (self):
136 # main game loop
137 while 1:
138 # clear screen
139 self.screen.fill (pygame.Color (0,0,0))
140 # draw the level
141 self.draw_level_background (self.currentlevel)
142 # draw level objects
143 self.draw_level_objects (self.currentlevel)
144 # draw the NPCs in the level
145 self.draw_level_npcs (self.currentlevel)
146 # draw our character
147 self.draw_butaba ()
148 # display the character's inventory
149 self.draw_inventory ()
150 # draw the status info
151 self.draw_status ()
152 # update the display
153 pygame.display.update ()
154
155 # get keyboard events
156 for event in pygame.event.get ():
157 if event.type == pygame.QUIT:
158 sys.exit (0)
159 # if keyboard event
160 if event.type == pygame.KEYDOWN:
161 if event.key == pygame.K_UP:
162 self.move_butaba_up ()
163 elif event.key == pygame.K_DOWN:
164 self.move_butaba_down ()
165 elif event.key == pygame.K_LEFT:
166 self.move_butaba_left ()
167 elif event.key == pygame.K_RIGHT:
168 self.move_butaba_right ()
169 # drinking health potion in inventory
170 elif event.key == ord ("h") or event.key == ord ("H"):
171 self.inventory_drink_health_potion ()
172 # quit the game
173 elif event.key == ord ("q") or event.key == ord ("Q"):
174 sys.exit (0)
175
176 # drink a health potion if it is in the player's inventory
177 def inventory_drink_health_potion (self):
178 # look for a health potion
179 for item in self.butaba.objects:
180 if isinstance (item, gameobjects.HealthPotion) is True:
181 self.use_object (self.butaba, item)
182 break
183
184 def move_butaba_up (self):
185 # clear any status messages
186 self.status_message = None
187 # first if butaba is not facing up, make him face up
188 if self.butaba.position <> butaba.Butaba.BACK:
189 self.butaba.position = butaba.Butaba.BACK
190 return
191
192 # if butaba is trying to move off the top of the screen
193 if self.butaba.row <= 0:
194 # if there is a level above set current level to that one
195 if self.currentlevel.leveltop is not None:
196 lastrow = len (self.currentlevel.leveltop.background) - 1
197 # interact with objects
198 if self.level_interact (self.currentlevel.leveltop, lastrow, self.butaba.col) is False:
199 return
200
201 # make sure there is no obstacle
202 if self.check_background_obstacle (self.currentlevel.leveltop, lastrow, self.butaba.col) is False:
203 self.currentlevel = self.currentlevel.leveltop
204 self.butaba.row = lastrow
205 # normal upward movement
206 else:
207 # if there is any object in that place interact with it
208 # if any object is a blocking object then avoid movement
209 if self.level_interact (self.currentlevel, self.butaba.row-1, self.butaba.col) is False:
210 return
211
212 if self.check_background_obstacle (self.currentlevel, self.butaba.row-1, self.butaba.col) is False:
213 self.butaba.row -= 1
214
215 def move_butaba_down (self):
216 # clear any status messages
217 self.status_message = None
218 # first if butaba is not facing forward, make him face forward/down
219 if self.butaba.position <> butaba.Butaba.FRONT:
220 self.butaba.position = butaba.Butaba.FRONT
221 return
222
223 # if butaba is trying to move off the bottom of the screen
224 if self.butaba.row >= len (self.currentlevel.background)-1:
225 # if there is a level below set current level to that one
226 if self.currentlevel.levelbottom is not None:
227 # interact with objects if any
228 # if any object is a blocking object then avoid movement
229 if self.level_interact (self.currentlevel.levelbottom, 0, self.butaba.col) is False:
230 return
231 # make sure there is no obstacle at that position
232 if self.check_background_obstacle (self.currentlevel.levelbottom, 0, self.butaba.col) is False:
233 self.currentlevel = self.currentlevel.levelbottom
234 self.butaba.row = 0
235 # normal downward movement
236 else:
237 # interact with objects if any
238 # if any object is a blocking object then avoid movement
239 if self.level_interact (self.currentlevel, self.butaba.row+1, self.butaba.col) is False:
240 return
241 if self.check_background_obstacle (self.currentlevel, self.butaba.row+1, self.butaba.col) is False:
242 self.butaba.row += 1
243
244 # check if a background tile is an obstacle
245 def check_background_obstacle (self, level, row, col):
246 if (level.background[row][col][2] == 1):
247 return True
248 else:
249 return False
250
251 # get and interact with objects and characters if present in a particular row/col
252 def level_interact (self, level, row, col):
253 objs = []
254 # get list of objects at current location
255 for obj in level.objects:
256 if obj.row == row and obj.col == col:
257 objs.append (obj)
258
259 notblock = self.interact_objects (level, objs)
260
261 # get npc at current location
262 current_npc = None
263 for npc in level.npcs:
264 if npc.row == row and npc.col == col:
265 current_npc = npc
266 break
267
268 # npcs always block the tile. So return false if there is an NPC
269 # at the location
270 if current_npc is not None:
271 self.interact_npc (current_npc)
272 return False
273
274 return notblock
275
276 # interaction with npcs
277 def interact_npc (self, npc):
278 # interact with NPC and get the response ID
279 # if the NPC is Bulisa
280 if isinstance (npc, npcs.Bulisa):
281 self.interact_npc_bulisa (npc)
282
283 # interact with NPC Bulisa
284 def interact_npc_bulisa (self, npc):
285 # set initial response ID to none
286 resp_id = None
287 # not yet started mission drawing water from well and not refused it
288 if (gamestate.mission_bulisa_water_from_well is False
289 and gamestate.mission_bulisa_water_from_well_refused is False):
290 # set the current dialogue
291 npc.currentdialog = 0
292 # get the response ID
293 resp_id = utility.dialogue_play (self.screen, self.img_dialogue, npc, self.img_butaba_portrait, 0, 90)
294 if (gamestate.mission_bulisa_water_from_well_refused is True and
295 gamestate.mission_bulisa_water_from_well is False):
296 # set the current dialog
297 npc.currentdialog = 2
298 resp_id = utility.dialogue_play (self.screen, self.img_dialogue, npc, self.img_butaba_portrait, 0, 90)
299 # mission accepted but not completed - check if completed and set value
300 # accordingly
301 elif (gamestate.mission_bulisa_water_from_well is True
302 and gamestate.mission_bulisa_water_from_well_complete is False):
303 for invobj in self.butaba.objects:
304 if isinstance (invobj, gameobjects.Bucket) is True:
305 if invobj.liquid == "water":
306 gamestate.mission_bulisa_water_from_well_complete = True
307 self.butaba.objects.remove (invobj)
308 break
309 # water mission is not completed yet
310 if gamestate.mission_bulisa_water_from_well_complete is False:
311 npc.currentdialog = 1
312 else:
313 npc.currentdialog = 3
314
315 # get the response ID
316 resp_id = utility.dialogue_play (self.screen, self.img_dialogue, npc, self.img_butaba_portrait, 0, 90)
317
318 # if response ID is 12, then drawing water from well mission is refused
319 if resp_id == "12" or resp_id == "18":
320 gamestate.mission_bulisa_water_from_well_refused = True
321 # if response ID is 13: that is accepted the drawing water from well mission begins
322 if resp_id == "13" or resp_id == "17":
323 gamestate.mission_bulisa_water_from_well = True
324 # if response ID is none
325 elif resp_id is None:
326 self.status_message = "You cannot initiate a conversation with %s" % npc.charname
327
328 # interaction with objects
329 def interact_objects (self, container, objs):
330 # overall flag for blocking/non-blocking objects
331 notblock = True
332
333 # now perform interaction
334 for obj in objs:
335 # run the object interact function
336 if obj.interact () is False:
337 notblock = False
338 # if object can be picked up ask
339 if obj.can_pickup is True:
340 ans = utility.ask_question (self.screen, "Found %s." % obj.text, ["Pick up", obj.use_str, "Ignore"], self.img_menu)
341 # if the answer is "pick up"
342 if ans == 1:
343 self.pickup_object (container, obj)
344 elif ans == 2:
345 # use the object according to its type
346 self.use_object (container, obj)
347 # if it cannot be picked up, try to use it anyway
348 else:
349 ans = utility.ask_question (self.screen, "Found %s." % obj.text, [obj.use_str, "Ignore"], self.img_menu)
350 if ans == 1:
351 self.use_object (container, obj)
352
353 return notblock
354
355 # transfer an object from one container to another
356 # container must have an objects list
357 def transfer_object (self, source, obj, dest):
358 # remove object from source
359 source.objects.remove (obj)
360 # add object to destination
361 dest.objects.append (obj)
362
363 # picking up an object
364 def pickup_object (self, container, obj):
365 # only if object can be picked up, pick it up or use it
366 if obj.can_pickup is True:
367 # check if the inventory is full
368 if len (self.butaba.objects) >= butaba.Butaba.MAXITEMS:
369 self.status_message = "Cannot pick up item. Inventory full"
370 else:
371 # add item to inventory
372 self.transfer_object (container, obj, self.butaba)
373
374 self.status_message = "You picked up %s" % obj.text
375
376 # this method uses the object first by calling the object use () method
377 # and then performing specific actions as necessary
378 def use_object (self, container, obj):
379 # if the object is a health potion
380 if isinstance (obj, gameobjects.HealthPotion) is True:
381 if self.butaba.health < butaba.Butaba.MAXHEALTH:
382 obj.use (self.butaba)
383 container.objects.remove (obj)
384 self.status_message = "You gained health"
385 else:
386 self.status_message = "You already have maximum health!"
387 # if the object is a chest
388 elif isinstance (obj, gameobjects.Chest) is True:
389 # if chest is locked, try to open it
390 if obj.locked is True:
391 # try opening the chest with every item 9the use () function
392 # of the chest determines if item is a key anyway
393 fittedkey = None
394 for invobj in self.butaba.objects:
395 fittedkey = obj.use (invobj)
396 # if a key fits
397 if fittedkey is not None:
398 break
399 # if no key found
400 if fittedkey is None:
401 self.status_message = "No key found to open %s" % obj.text
402 # chest successfully unlocked
403 else:
404 self.status_message = "You unlocked the %s" % obj.text
405 # remove the key from Butaba
406 self.butaba.objects.remove (fittedkey)
407 # add an experience point for unlocking chest subject
408 # to a limit of KNOWLEDGEMAX_CHEST_UNLOCK
409 if self.butaba.experience < constants.KNOWLEDGEMAX_CHEST_UNLOCK:
410 self.butaba.experience += 1
411 self.status_message += " and gained experience!"
412 # display the contents of the chest
413 else:
414 item = utility.get_container_object (self.screen, obj, self.img_chestbg, 30)
415 if item is not None:
416 self.interact_objects (obj, [ item, ])
417
418 # if the object is gold coins
419 elif isinstance (obj, gameobjects.GoldCoins) is True:
420 obj.use (self.butaba)
421 self.status_message = "You picked up %d gold." % obj.value
422 # remove the gold coins after adding it to Butaba's gold
423 container.objects.remove (obj)
424 # using a bucket means emptying it
425 elif isinstance (obj, gameobjects.Bucket) is True:
426 if obj.liquid is not None:
427 self.status_message = "You emptied the bucket of %s" % obj.liquid
428 obj.use (self.butaba)
429 else:
430 self.status_message = "Bucket is already empty."
431 # using a well
432 elif isinstance (obj, gameobjects.Well) is True:
433 # if the well is not dry, i.e. it has some liquid
434 if obj.liquid is not None:
435 # search butaba inventory for an empty bucket
436 for invobj in self.butaba.objects:
437 # bucket found, now check if it is empty
438 if isinstance (invobj, gameobjects.Bucket) is True:
439 # if empty fill it
440 if invobj.liquid is None:
441 obj.use (invobj)
442 self.status_message = "You successfully filled the %s with %s" % (invobj.text, obj.liquid)
443 if self.butaba.strength < constants.STRENGTHMAX_DRAW_WELL_WATER:
444 self.butaba.strength += 2
445 self.status_message += " and gained strength!"
446 return
447 self.status_message = "You have no empty bucket to draw %s with!" % obj.liquid
448 else:
449 self.status_message = "%s appears to be dry!" % obj.text
450
451 def move_butaba_left (self):
452 # clear any status messages
453 self.status_message = None
454
455 # first if Butaba is not facing left, make him face left
456 if self.butaba.position <> butaba.Butaba.LEFT:
457 self.butaba.position = butaba.Butaba.LEFT
458 return
459
460 # if butaba is trying to move off the left edge
461 if self.butaba.col <= 0:
462 # if there is a level to the right set current level to that one
463 if self.currentlevel.levelleft is not None:
464 # get the last column of the previous level
465 lastcol = len (self.currentlevel.levelleft.background[0]) - 1
466 # interact with objects if any
467 # if any object is a blocking object then avoid movement
468 if self.level_interact (self.currentlevel.levelleft, self.butaba.row, lastcol) is False:
469 return
470 # make sure there is no obstacle at that position of movement
471 if self.check_background_obstacle (self.currentlevel.levelleft, self.butaba.row, lastcol) is False:
472 self.currentlevel = self.currentlevel.levelleft
473 self.butaba.col = lastcol
474 # normal left movement
475 else:
476 # interact with objects if any
477 # if any object is a blocking object then avoid movement
478 if self.level_interact (self.currentlevel, self.butaba.row, self.butaba.col-1) is False:
479 return
480 if self.check_background_obstacle (self.currentlevel, self.butaba.row, self.butaba.col-1) is False:
481 self.butaba.col -= 1
482
483 def move_butaba_right (self):
484 # clear any status messages
485 self.status_message = None
486
487 # First if Butaba is not facing right make him face right
488 if self.butaba.position <> butaba.Butaba.RIGHT:
489 self.butaba.position = butaba.Butaba.RIGHT
490 return
491
492 # if butaba is trying to move off the right edge
493 if self.butaba.col >= len (self.currentlevel.background[0])-1:
494 # if there is a level to the right swap current level with that one
495 if self.currentlevel.levelright is not None:
496 # interact with objects if any
497 # if any object is a blocking object then avoid movement
498 if self.level_interact (self.currentlevel.levelright, self.butaba.row, 0) is False:
499 return
500
501 # make sure there is no obstacle at that position of movement
502 # get the last column of the previous level
503 if self.check_background_obstacle (self.currentlevel.levelright, self.butaba.row, 0) is False:
504 self.currentlevel = self.currentlevel.levelright
505 self.butaba.col = 0
506 # normal right movement
507 else:
508 # interact with objects if any
509 # if any object is a blocking object then avoid moving
510 if self.level_interact (self.currentlevel, self.butaba.row, self.butaba.col + 1) is False:
511 return
512 if self.check_background_obstacle (self.currentlevel, self.butaba.row, self.butaba.col + 1) is False:
513 self.butaba.col += 1
514
515 def draw_butaba (self):
516 if self.butaba.position == butaba.Butaba.FRONT:
517 self.screen.blit (self.img_butabafront, (self.butaba.col*48, self.butaba.row*48))
518 elif self.butaba.position == butaba.Butaba.BACK:
519 self.screen.blit (self.img_butababack, (self.butaba.col*48, self.butaba.row*48))
520 elif self.butaba.position == butaba.Butaba.LEFT:
521 self.screen.blit (self.img_butabaleft, (self.butaba.col*48, self.butaba.row*48))
522 elif self.butaba.position == butaba.Butaba.RIGHT:
523 self.screen.blit (self.img_butabaright, (self.butaba.col*48, self.butaba.row*48))
524
525
526 # Draw the status infodisplay
527 def draw_status (self):
528 self.screen.blit (self.img_redpotion, (485, 10))
529 utility.put_text (self.screen, 550, 25, 20, (255, 0, 0), "%d" % self.butaba.health)
530
531 self.screen.blit (self.img_lightning, (620, 10))
532 utility.put_text (self.screen, 660, 25, 20, (255,255,255), "%d" % self.butaba.strength)
533
534 self.screen.blit (self.img_wand, (485, 65))
535 utility.put_text (self.screen, 550, 75, 20, (0, 0, 255), "%d" % self.butaba.magic)
536
537 self.screen.blit (self.img_bulb, (620, 65))
538 utility.put_text (self.screen, 660, 75, 20, (0, 255, 0), "%d" % self.butaba.experience)
539
540 self.screen.blit (self.img_goldcoins, (485, 110))
541 utility.put_text (self.screen, 550, 130, 20, (255, 255, 0), "%d" % self.butaba.gold)
542
543 if self.status_message is not None:
544 utility.put_text (self.screen, 10, 485, 10, (255,255, 0), "%s" % self.status_message)
545
546 # display the inventory of the player
547 def draw_inventory (self):
548 # draw the inventory slots
549 r = 1
550 c = 1
551 utility.put_text (self.screen, 490, 170, 16, (255,255 , 0), "Inventory")
552 for i in range (butaba.Butaba.MAXITEMS):
553 self.screen.blit (self.img_inventory, (440+c*54, 150+r*54))
554 if c % 4 == 0:
555 r += 1
556 c = 1
557 else:
558 c += 1
559
560 r = 1
561 c = 1
562 for obj in self.butaba.objects:
563 self.screen.blit (obj.image, (440+c*54+2, 150+r*54+2))
564 if c % 4 == 0:
565 r += 1
566 c = 1
567 else:
568 c += 1
569
570 # Draw the level background tiles on surface
571 def draw_level_background (self, level):
572 i = 0
573 for row in level.background:
574 j = 0
575 for tilerow, tilecol, is_solid in row:
576 tilex = tilecol * 48
577 tiley = tilerow * 48
578 self.screen.blit (self.img_tileset, (j*48, i*48), pygame.Rect (tilex, tiley, 48, 48))
579
580 j += 1
581 i += 1
582
583 # Draw the level objects
584 def draw_level_objects (self, level):
585 for obj in level.objects:
586 if obj.image is not None:
587 self.screen.blit (obj.image, (obj.col*48, obj.row*48))
588
589
590 # Draw the NPCs in the level
591 def draw_level_npcs (self, level):
592 for npc in level.npcs:
593 if npc.image is not None:
594 self.screen.blit (npc.image, (npc.col*48, npc.row*48))