18 self
.screen
= pygame
.display
.set_mode ((720, 512))
19 pygame
.display
.set_caption ("The Adventures of Butaba")
21 # initalize background graphics
22 self
.img_tileset
= pygame
.image
.load (os
.path
.join ("background", "tileset.png")).convert ()
24 self
.img_menu
= pygame
.image
.load (os
.path
.join ("background", "menu_screen.png")).convert ()
26 self
.img_inventory
= pygame
.image
.load (os
.path
.join ("background", "inventory.png")).convert ()
28 self
.img_chestbg
= pygame
.image
.load (os
.path
.join ("background", "chestcontent.png")).convert ()
31 # initialize object graphics
32 self
.img_redpotion
= pygame
.image
.load (os
.path
.join ("objects", "red-potion.png")).convert ()
33 self
.img_redpotion
.set_colorkey (pygame
.Color (0, 255, 0))
34 self
.img_goldcoins
= pygame
.image
.load (os
.path
.join ("objects", "gold-coins.png")).convert ()
35 self
.img_goldcoins
.set_colorkey (pygame
.Color (0, 255, 0))
36 self
.img_wand
= pygame
.image
.load (os
.path
.join ("objects", "wand.png")).convert ()
37 self
.img_wand
.set_colorkey (pygame
.Color (0, 255, 0))
38 self
.img_bulb
= pygame
.image
.load (os
.path
.join ("objects", "bulb.png")).convert ()
39 self
.img_bulb
.set_colorkey (pygame
.Color (0, 255, 0))
40 self
.img_lightning
= pygame
.image
.load (os
.path
.join ("objects", "lightning.png")).convert ()
41 self
.img_lightning
.set_colorkey (pygame
.Color (0, 255, 0))
42 self
.img_key
= pygame
.image
.load (os
.path
.join ("objects", "key.png")).convert ()
43 self
.img_key
.set_colorkey (pygame
.Color (0, 255, 0))
44 self
.img_key2
= pygame
.image
.load (os
.path
.join ("objects", "key2.png")).convert ()
45 self
.img_key2
.set_colorkey (pygame
.Color (0, 255, 0))
46 self
.img_chest
= pygame
.image
.load (os
.path
.join ("objects", "chest.png")).convert ()
47 self
.img_chest
.set_colorkey (pygame
.Color (0, 255, 0))
49 # initialize player graphics
50 self
.img_butabafront
= pygame
.image
.load (os
.path
.join ("sprite", "butaba-front.png")).convert ()
51 self
.img_butabafront
.set_colorkey (pygame
.Color (0, 255, 0))
52 self
.img_butababack
= pygame
.image
.load (os
.path
.join ("sprite", "butaba-back.png")).convert ()
53 self
.img_butababack
.set_colorkey (pygame
.Color (0, 255, 0))
54 self
.img_butabaleft
= pygame
.image
.load (os
.path
.join ("sprite", "butaba-left.png")).convert ()
55 self
.img_butabaleft
.set_colorkey (pygame
.Color (0, 255, 0))
56 self
.img_butabaright
= pygame
.image
.load (os
.path
.join ("sprite", "butaba-right.png")).convert ()
57 self
.img_butabaright
.set_colorkey (pygame
.Color (0, 255, 0))
61 # set current level and position of our character
62 self
.currentlevel
= self
.level1
64 # set the status message
65 self
.status_message
= "Game started"
67 self
.butaba
= butaba
.Butaba (5,0, butaba
.Butaba
.RIGHT
)
69 # set up the levels and their interactions
70 def setup_levels (self
):
71 # set up the objects first
72 chest1
= gameobjects
.Chest (2, 6, "chest", self
.img_chest
, constants
.KEY_CHEST1
, True)
73 chest2
= gameobjects
.Chest (6, 6, "chest", self
.img_chest
, constants
.KEY_CHEST2
, True)
74 key1
= gameobjects
.Key (5, 3, "a chest key", self
.img_key2
, constants
.KEY_CHEST1
)
75 key2
= gameobjects
.Key (5, 3, "a chest key", self
.img_key
, constants
.KEY_CHEST2
)
76 potion
= gameobjects
.HealthPotion (5, 2, self
.img_redpotion
)
77 gold50
= gameobjects
.GoldCoins (6, 2, self
.img_goldcoins
, 50)
78 gold75
= gameobjects
.GoldCoins (6, 2, self
.img_goldcoins
, 75)
80 chest1
.objects
= [ gold50
, gold75
]
83 self
.level1
= level
.Level (cPickle
.load (file ("levels/level1.dat")),
84 objects
= [ chest1
] )
86 self
.level1w
= level
.Level (cPickle
.load (file ("levels/level1w.dat")))
88 self
.level1e
= level
.Level (cPickle
.load (file ("levels/level1e.dat")),
89 objects
= [ key1
, key2
, potion
, chest2
])
91 # set up the interaction between levels
92 self
.level1
.levelright
= self
.level1e
93 self
.level1
.levelleft
= self
.level1w
94 self
.level1e
.levelleft
= self
.level1
95 self
.level1w
.levelright
= self
.level1
101 self
.screen
.fill (pygame
.Color (0,0,0))
103 self
.draw_level_background (self
.currentlevel
)
105 self
.draw_level_objects (self
.currentlevel
)
108 # display the character's inventory
109 self
.draw_inventory ()
110 # draw the status info
113 pygame
.display
.update ()
115 # get keyboard events
116 for event
in pygame
.event
.get ():
117 if event
.type == pygame
.QUIT
:
120 if event
.type == pygame
.KEYDOWN
:
121 if event
.key
== pygame
.K_UP
:
122 self
.move_butaba_up ()
123 elif event
.key
== pygame
.K_DOWN
:
124 self
.move_butaba_down ()
125 elif event
.key
== pygame
.K_LEFT
:
126 self
.move_butaba_left ()
127 elif event
.key
== pygame
.K_RIGHT
:
128 self
.move_butaba_right ()
129 # drinking health potion in inventory
130 elif event
.key
== ord ("h") or event
.key
== ord ("H"):
131 self
.inventory_drink_health_potion ()
133 elif event
.key
== ord ("q") or event
.key
== ord ("Q"):
136 # drink a health potion if it is in the player's inventory
137 def inventory_drink_health_potion (self
):
138 # if health is maxed out then ignore
139 if self
.butaba
.health
== butaba
.Butaba
.MAXHEALTH
:
140 self
.status_message
= "You already have maximum health."
142 # look for a health potion
143 for item
in self
.butaba
.inventory
:
144 if isinstance (item
, gameobjects
.HealthPotion
) is True:
145 self
.use_object (self
.butaba
, item
)
148 def move_butaba_up (self
):
149 # clear any status messages
150 self
.status_message
= None
151 # first if butaba is not facing up, make him face up
152 if self
.butaba
.position
<> butaba
.Butaba
.BACK
:
153 self
.butaba
.position
= butaba
.Butaba
.BACK
156 # if butaba is trying to move off the top of the screen
157 if self
.butaba
.row
<= 0:
158 # if there is a level above set current level to that one
159 if self
.currentlevel
.leveltop
is not None:
160 lastrow
= len (self
.currentlevel
.leveltop
.background
) - 1
161 # if there is any object in that place interact with it
162 # if any object is a blocking object then avoid movement
163 if self
.interact_objects (self
.currentlevel
.leveltop
, lastrow
, self
.butaba
.col
) is False:
166 # make sure there is no obstacle
167 if self
.check_background_obstacle (self
.currentlevel
.leveltop
, lastrow
, self
.butaba
.col
) is False:
168 self
.currentlevel
= self
.currentlevel
.leveltop
169 self
.butaba
.row
= lastrow
170 # normal upward movement
172 # if there is any object in that place interact with it
173 # if any object is a blocking object then avoid movement
174 if self
.interact_objects (self
.currentlevel
, self
.butaba
.row
-1, self
.butaba
.col
) is False:
177 if self
.check_background_obstacle (self
.currentlevel
, self
.butaba
.row
-1, self
.butaba
.col
) is False:
180 def move_butaba_down (self
):
181 # clear any status messages
182 self
.status_message
= None
183 # first if butaba is not facing forward, make him face forward/down
184 if self
.butaba
.position
<> butaba
.Butaba
.FRONT
:
185 self
.butaba
.position
= butaba
.Butaba
.FRONT
188 # if butaba is trying to move off the bottom of the screen
189 if self
.butaba
.row
>= len (self
.currentlevel
.background
)-1:
190 # if there is a level below set current level to that one
191 if self
.currentlevel
.levelbottom
is not None:
192 # interact with objects if any
193 # if any object is a blocking object then avoid movement
194 if self
.interact_objects (self
.currentlevel
.levelbottom
, 0, self
.butaba
.col
) is False:
196 # make sure there is no obstacle at that position
197 if self
.check_background_obstacle (self
.currentlevel
.levelbottom
, 0, self
.butaba
.col
) is False:
198 self
.currentlevel
= self
.currentlevel
.levelbottom
200 # normal downward movement
202 # interact with objects if any
203 # if any object is a blocking object then avoid movement
204 if self
.interact_objects (self
.currentlevel
, self
.butaba
.row
+1, self
.butaba
.col
) is False:
206 if self
.check_background_obstacle (self
.currentlevel
, self
.butaba
.row
+1, self
.butaba
.col
) is False:
209 # check if a background tile is an obstacle
210 def check_background_obstacle (self
, level
, row
, col
):
211 if (level
.background
[row
][col
][2] == 1):
216 # get and interact with objects if present in a particular row/col
217 def interact_objects (self
, level
, row
, col
):
219 # get list of objects at current location
220 for obj
in level
.objects
:
221 if obj
.row
== row
and obj
.col
== col
:
224 # overall flag for blocking/non-blocking objects
226 # now perform interaction
228 # run the object interact function
229 if obj
.interact () is False:
231 # if object can be picked up ask
232 if obj
.can_pickup
is True:
233 ans
= utility
.ask_question (self
.screen
, "Found %s." % obj
.text
, ["Pick up", "Use", "Ignore"], self
.img_menu
)
234 # if the answer is "pick up"
236 self
.pickup_object (self
.currentlevel
, obj
)
238 # use the object according to its type
239 self
.use_object (self
.currentlevel
, obj
)
240 # if it cannot be picked up, try to use it anyway
242 self
.use_object (self
.currentlevel
, obj
)
246 # picking up an object
247 def pickup_object (self
, container
, obj
):
248 # only if object can be picked up, pick it up or use it
249 if obj
.can_pickup
is True:
250 # check if the inventory is full
251 if len (self
.butaba
.objects
) >= butaba
.Butaba
.MAXITEMS
:
252 self
.status_message
= "Cannot pick up item. Inventory full"
254 # add item to inventory
255 self
.butaba
.objects
.append (obj
)
256 # remove from container
257 container
.objects
.remove (obj
)
259 self
.status_message
= "You picked up %s" % obj
.text
261 # this method uses the object first by calling the object use () method
262 # and then performing specific actions as necessary
263 def use_object (self
, container
, obj
):
264 # if the object is a health potion
265 if isinstance (obj
, gameobjects
.HealthPotion
) is True:
266 obj
.use (self
.butaba
)
267 container
.objects
.remove (obj
)
268 self
.status_message
= "You gained health"
269 # if the object is a chest
270 elif isinstance (obj
, gameobjects
.Chest
) is True:
271 # if chest is locked, try to open it
272 if obj
.locked
is True:
273 # try opening the chest with every item 9the use () function
274 # of the chest determines if item is a key anyway
276 for invobj
in self
.butaba
.objects
:
277 fittedkey
= obj
.use (invobj
)
279 if fittedkey
is not None:
282 if fittedkey
is None:
283 self
.status_message
= "No key found to open %s" % obj
.text
284 # chest successfully unlocked
286 self
.status_message
= "You unlocked the %s" % obj
.text
287 # remove the key from Butaba
288 self
.butaba
.objects
.remove (fittedkey
)
289 # add an experience point for unlocking chest subject
290 # to a limit of KNOWLEDGEMAX_CHEST_UNLOCK
291 if self
.butaba
.experience
< constants
.KNOWLEDGEMAX_CHEST_UNLOCK
:
292 self
.butaba
.experience
+= 1
293 self
.status_message
+= " and gained experience!"
294 # display the contents of the chest
296 utility
.display_container_contents (self
.screen
, obj
, self
.img_chestbg
, 30)
298 # if the object is gold coins
299 elif isinstance (obj
, gameobjects
.GoldCoins
) is True:
300 obj
.use (self
.butaba
)
301 self
.status_message
= "You picked up %d gold." % obj
.value
302 # remove the gold coins after adding it to Butaba's gold
303 container
.remove (obj
)
305 def move_butaba_left (self
):
306 # clear any status messages
307 self
.status_message
= None
309 # first if Butaba is not facing left, make him face left
310 if self
.butaba
.position
<> butaba
.Butaba
.LEFT
:
311 self
.butaba
.position
= butaba
.Butaba
.LEFT
314 # if butaba is trying to move off the left edge
315 if self
.butaba
.col
<= 0:
316 # if there is a level to the right set current level to that one
317 if self
.currentlevel
.levelleft
is not None:
318 # get the last column of the previous level
319 lastcol
= len (self
.currentlevel
.levelleft
.background
[0]) - 1
320 # interact with objects if any
321 # if any object is a blocking object then avoid movement
322 if self
.interact_objects (self
.currentlevel
.levelleft
, self
.butaba
.row
, lastcol
) is False:
324 # make sure there is no obstacle at that position of movement
325 if self
.check_background_obstacle (self
.currentlevel
.levelleft
, self
.butaba
.row
, lastcol
) is False:
326 self
.currentlevel
= self
.currentlevel
.levelleft
327 self
.butaba
.col
= lastcol
328 # normal left movement
330 # interact with objects if any
331 # if any object is a blocking object then avoid movement
332 if self
.interact_objects (self
.currentlevel
, self
.butaba
.row
, self
.butaba
.col
-1) is False:
334 if self
.check_background_obstacle (self
.currentlevel
, self
.butaba
.row
, self
.butaba
.col
-1) is False:
337 def move_butaba_right (self
):
338 # clear any status messages
339 self
.status_message
= None
341 # First if Butaba is not facing right make him face right
342 if self
.butaba
.position
<> butaba
.Butaba
.RIGHT
:
343 self
.butaba
.position
= butaba
.Butaba
.RIGHT
346 # if butaba is trying to move off the right edge
347 if self
.butaba
.col
>= len (self
.currentlevel
.background
[0])-1:
348 # if there is a level to the right swap current level with that one
349 if self
.currentlevel
.levelright
is not None:
350 # interact with objects if any
351 # if any object is a blocking object then avoid movement
352 if self
.interact_objects (self
.currentlevel
.levelright
, self
.butaba
.row
, 0) is False:
355 # make sure there is no obstacle at that position of movement
356 # get the last column of the previous level
357 if self
.check_background_obstacle (self
.currentlevel
.levelright
, self
.butaba
.row
, 0) is False:
358 self
.currentlevel
= self
.currentlevel
.levelright
360 # normal right movement
362 # interact with objects if any
363 # if any object is a blocking object then avoid moving
364 if self
.interact_objects (self
.currentlevel
, self
.butaba
.row
, self
.butaba
.col
+ 1) is False:
366 if self
.check_background_obstacle (self
.currentlevel
, self
.butaba
.row
, self
.butaba
.col
+ 1) is False:
369 def draw_butaba (self
):
370 if self
.butaba
.position
== butaba
.Butaba
.FRONT
:
371 self
.screen
.blit (self
.img_butabafront
, (self
.butaba
.col
*48, self
.butaba
.row
*48))
372 elif self
.butaba
.position
== butaba
.Butaba
.BACK
:
373 self
.screen
.blit (self
.img_butababack
, (self
.butaba
.col
*48, self
.butaba
.row
*48))
374 elif self
.butaba
.position
== butaba
.Butaba
.LEFT
:
375 self
.screen
.blit (self
.img_butabaleft
, (self
.butaba
.col
*48, self
.butaba
.row
*48))
376 elif self
.butaba
.position
== butaba
.Butaba
.RIGHT
:
377 self
.screen
.blit (self
.img_butabaright
, (self
.butaba
.col
*48, self
.butaba
.row
*48))
380 # Draw the status infodisplay
381 def draw_status (self
):
382 self
.screen
.blit (self
.img_redpotion
, (485, 10))
383 utility
.put_text (self
.screen
, 550, 25, 20, (255, 0, 0), "%d" % self
.butaba
.health
)
385 self
.screen
.blit (self
.img_lightning
, (620, 10))
386 utility
.put_text (self
.screen
, 660, 25, 20, (255,255,255), "%d" % self
.butaba
.strength
)
388 self
.screen
.blit (self
.img_wand
, (485, 65))
389 utility
.put_text (self
.screen
, 550, 75, 20, (0, 0, 255), "%d" % self
.butaba
.magic
)
391 self
.screen
.blit (self
.img_bulb
, (620, 65))
392 utility
.put_text (self
.screen
, 660, 75, 20, (0, 255, 0), "%d" % self
.butaba
.experience
)
394 self
.screen
.blit (self
.img_goldcoins
, (485, 110))
395 utility
.put_text (self
.screen
, 550, 130, 20, (255, 255, 0), "%d" % self
.butaba
.gold
)
397 if self
.status_message
is not None:
398 utility
.put_text (self
.screen
, 10, 485, 10, (255,255, 0), "%s" % self
.status_message
)
400 # display the inventory of the player
401 def draw_inventory (self
):
402 # draw the inventory slots
405 utility
.put_text (self
.screen
, 490, 170, 16, (255,255 , 0), "Inventory")
406 for i
in range (butaba
.Butaba
.MAXITEMS
):
407 self
.screen
.blit (self
.img_inventory
, (440+c
*54, 150+r
*54))
416 for obj
in self
.butaba
.objects
:
417 self
.screen
.blit (obj
.image
, (440+c
*54+2, 150+r
*54+2))
424 # Draw the level background tiles on surface
425 def draw_level_background (self
, level
):
427 for row
in level
.background
:
429 for tilerow
, tilecol
, is_solid
in row
:
432 self
.screen
.blit (self
.img_tileset
, (j
*48, i
*48), pygame
.Rect (tilex
, tiley
, 48, 48))
437 # Draw the level objects
438 def draw_level_objects (self
, level
):
439 for obj
in level
.objects
:
440 if obj
.image
is not None:
441 self
.screen
.blit (obj
.image
, (obj
.col
*48, obj
.row
*48))