Added the inventory system (basic)
[butaba-adventures.git] / maingame.py
1 import pygame
2 import sys
3 import random
4 import os.path
5
6 import level
7 import butaba
8 import utility
9 import gameobjects
10
11 class MainGame:
12
13 # initialize the game
14 def __init__ (self):
15 pygame.init ()
16 self.screen = pygame.display.set_mode ((720, 512))
17 pygame.display.set_caption ("The Adventures of Butaba")
18
19 # initalize background graphics
20 self.img_tileset = pygame.image.load (os.path.join ("background", "tileset.png")).convert ()
21
22 self.img_menu = pygame.image.load (os.path.join ("background", "menu_screen.png")).convert ()
23
24 self.img_inventory = pygame.image.load (os.path.join ("background", "inventory.png")).convert ()
25
26
27 # initialize object graphics
28 self.img_redpotion = pygame.image.load (os.path.join ("objects", "red-potion.png")).convert ()
29 self.img_redpotion.set_colorkey (pygame.Color (0, 255, 0))
30 self.img_goldcoins = pygame.image.load (os.path.join ("objects", "gold-coins.png")).convert ()
31 self.img_goldcoins.set_colorkey (pygame.Color (0, 255, 0))
32 self.img_wand = pygame.image.load (os.path.join ("objects", "wand.png")).convert ()
33 self.img_wand.set_colorkey (pygame.Color (0, 255, 0))
34 self.img_bulb = pygame.image.load (os.path.join ("objects", "bulb.png")).convert ()
35 self.img_bulb.set_colorkey (pygame.Color (0, 255, 0))
36 self.img_lightning = pygame.image.load (os.path.join ("objects", "lightning.png")).convert ()
37 self.img_lightning.set_colorkey (pygame.Color (0, 255, 0))
38
39 self.img_key = pygame.image.load (os.path.join ("objects", "key.png")).convert ()
40 self.img_key.set_colorkey (pygame.Color (0, 255, 0))
41
42 # initialize player graphics
43 self.img_butabafront = pygame.image.load (os.path.join ("sprite", "butaba-front.png")).convert ()
44 self.img_butabafront.set_colorkey (pygame.Color (0, 255, 0))
45 self.img_butababack = pygame.image.load (os.path.join ("sprite", "butaba-back.png")).convert ()
46 self.img_butababack.set_colorkey (pygame.Color (0, 255, 0))
47 self.img_butabaleft = pygame.image.load (os.path.join ("sprite", "butaba-left.png")).convert ()
48 self.img_butabaleft.set_colorkey (pygame.Color (0, 255, 0))
49 self.img_butabaright = pygame.image.load (os.path.join ("sprite", "butaba-right.png")).convert ()
50 self.img_butabaright.set_colorkey (pygame.Color (0, 255, 0))
51
52 # set level data
53 self.setup_levels ()
54 # set current level and position of our character
55 self.currentlevel = self.level1
56
57 # set the status message
58 self.status_message = "Game started"
59
60 self.butaba = butaba.Butaba (5,0, butaba.Butaba.RIGHT)
61
62 # set up the levels and their interactions
63 def setup_levels (self):
64
65 self.level1 = level.Level (level.LEVEL_1,
66 objects = [gameobjects.HealthPotion (4, 3, self.img_redpotion) ])
67 self.level1e = level.Level (level.LEVEL_1E,
68 objects = [ gameobjects.Key (4, 3, "a chest key", self.img_key, level.KEY_CHEST1),
69 gameobjects.Key (4, 3, "a room key", self.img_key, level.KEY_ROOM1)]
70 )
71 self.level1.levelright = self.level1e
72 self.level1e.levelleft = self.level1
73
74 def main_loop (self):
75 # main game loop
76 while 1:
77 # clear screen
78 self.screen.fill (pygame.Color (0,0,0))
79 # draw the level
80 self.draw_level_background (self.currentlevel)
81 # draw level objects
82 self.draw_level_objects (self.currentlevel)
83 # draw our character
84 self.draw_butaba ()
85 # display the character's inventory
86 self.draw_inventory ()
87 # draw the status info
88 self.draw_status ()
89 # update the display
90 pygame.display.update ()
91
92 # get keyboard events
93 for event in pygame.event.get ():
94 if event.type == pygame.QUIT:
95 sys.exit (0)
96 if event.type == pygame.KEYDOWN:
97 if event.key == pygame.K_UP:
98 self.move_butaba_up ()
99 elif event.key == pygame.K_DOWN:
100 self.move_butaba_down ()
101 elif event.key == pygame.K_LEFT:
102 self.move_butaba_left ()
103 elif event.key == pygame.K_RIGHT:
104 self.move_butaba_right ()
105
106 def move_butaba_up (self):
107 # clear any status messages
108 self.status_message = None
109 # first if butaba is not facing up, make him face up
110 if self.butaba.position <> butaba.Butaba.BACK:
111 self.butaba.position = butaba.Butaba.BACK
112 return
113
114 # if butaba is trying to move off the top of the screen
115 if self.butaba.row <= 0:
116 # if there is a level above set current level to that one
117 if self.currentlevel.leveltop is not None:
118 lastrow = len (self.currentlevel.leveltop.background) - 1
119 # if there is any object in that place interact with it
120 # if any object is a blocking object then avoid movement
121 if self.interact_objects (self.currentlevel.leveltop, lastrow, self.butaba.col) is False:
122 return
123
124 # make sure there is no obstacle
125 if self.check_background_obstacle (self.currentlevel.leveltop, lastrow, self.butaba.col) is False:
126 self.currentlevel = self.currentlevel.leveltop
127 self.butaba.row = lastrow
128 # normal upward movement
129 else:
130 # if there is any object in that place interact with it
131 # if any object is a blocking object then avoid movement
132 if self.interact_objects (self.currentlevel, self.butaba.row-1, self.butaba.col) is False:
133 return
134
135 if self.check_background_obstacle (self.currentlevel, self.butaba.row-1, self.butaba.col) is False:
136 self.butaba.row -= 1
137
138 def move_butaba_down (self):
139 # clear any status messages
140 self.status_message = None
141 # first if butaba is not facing forward, make him face forward/down
142 if self.butaba.position <> butaba.Butaba.FRONT:
143 self.butaba.position = butaba.Butaba.FRONT
144 return
145
146 # if butaba is trying to move off the bottom of the screen
147 if self.butaba.row >= len (self.currentlevel.background)-1:
148 # if there is a level below set current level to that one
149 if self.currentlevel.levelbottom is not None:
150 # interact with objects if any
151 # if any object is a blocking object then avoid movement
152 if self.interact_objects (self.currentlevel.levelbottom, 0, self.butaba.col) is False:
153 return
154 # make sure there is no obstacle at that position
155 if self.check_background_obstacle (self.currentlevel.levelbottom, 0, self.butaba.col) is False:
156 self.currentlevel = self.currentlevel.levelbottom
157 self.butaba.row = 0
158 # normal downward movement
159 else:
160 # interact with objects if any
161 # if any object is a blocking object then avoid movement
162 if self.interact_objects (self.currentlevel, self.butaba.row+1, self.butaba.col) is False:
163 return
164 if self.check_background_obstacle (self.currentlevel, self.butaba.row+1, self.butaba.col) is False:
165 self.butaba.row += 1
166
167 # check if a background tile is an obstacle
168 def check_background_obstacle (self, level, row, col):
169 if (level.background[row][col][2] == 1):
170 return True
171 else:
172 return False
173
174 # get and interact with objects if present in a particular row/col
175 def interact_objects (self, level, row, col):
176 objs = []
177 # get list of objects at current location
178 for obj in level.objects:
179 if obj.row == row and obj.col == col:
180 objs.append (obj)
181
182 # overall flag for blocking/non-blocking objects
183 notblock = True
184 # now perform interaction
185 for obj in objs:
186 # run the object interact function
187 if obj.interact () is False:
188 notblock = False
189 # if object can be picked up ask
190 self.pickup_object (obj)
191
192 return notblock
193
194 # picking up an object
195 def pickup_object (self, obj):
196 # only if object can be picked up, pick it up
197 if obj.can_pickup is True:
198 ans = utility.ask_question (self.screen, "Found %s." % obj.text, ["Carry", "Ignore"], self.img_menu)
199 # if the answer is "take"
200 if ans == 1:
201 # check if the inventory is full
202 if len (self.butaba.inventory) >= butaba.Butaba.MAXITEMS:
203 self.status_message = "Failed. Inventory full"
204 else:
205 # add item to inventory
206 self.butaba.inventory.append (obj)
207 self.currentlevel.objects.remove (obj)
208
209 self.status_message = "You picked up %s" % obj.text
210
211
212 def move_butaba_left (self):
213 # clear any status messages
214 self.status_message = None
215
216 # first if Butaba is not facing left, make him face left
217 if self.butaba.position <> butaba.Butaba.LEFT:
218 self.butaba.position = butaba.Butaba.LEFT
219 return
220
221 # if butaba is trying to move off the left edge
222 if self.butaba.col <= 0:
223 # if there is a level to the right set current level to that one
224 if self.currentlevel.levelleft is not None:
225 # get the last column of the previous level
226 lastcol = len (self.currentlevel.levelleft.background[0]) - 1
227 # interact with objects if any
228 # if any object is a blocking object then avoid movement
229 if self.interact_objects (self.currentlevel.levelleft, self.butaba.row, lastcol) is False:
230 return
231 # make sure there is no obstacle at that position of movement
232 if self.check_background_obstacle (self.currentlevel.levelleft, self.butaba.row, lastcol) is False:
233 self.currentlevel = self.currentlevel.levelleft
234 self.butaba.col = lastcol
235 # normal left movement
236 else:
237 # interact with objects if any
238 # if any object is a blocking object then avoid movement
239 if self.interact_objects (self.currentlevel, self.butaba.row, self.butaba.col-1) is False:
240 return
241 if self.check_background_obstacle (self.currentlevel, self.butaba.row, self.butaba.col-1) is False:
242 self.butaba.col -= 1
243
244 def move_butaba_right (self):
245 # clear any status messages
246 self.status_message = None
247
248 # First if Butaba is not facing right make him face right
249 if self.butaba.position <> butaba.Butaba.RIGHT:
250 self.butaba.position = butaba.Butaba.RIGHT
251 return
252
253 # if butaba is trying to move off the right edge
254 if self.butaba.col >= len (self.currentlevel.background[0])-1:
255 # if there is a level to the right swap current level with that one
256 if self.currentlevel.levelright is not None:
257 # interact with objects if any
258 # if any object is a blocking object then avoid movement
259 if self.interact_objects (self.currentlevel.levelright, self.butaba.row, 0) is False:
260 return
261
262 # make sure there is no obstacle at that position of movement
263 # get the last column of the previous level
264 if self.check_background_obstacle (self.currentlevel.levelright, self.butaba.row, 0) is False:
265 self.currentlevel = self.currentlevel.levelright
266 self.butaba.col = 0
267 # normal right movement
268 else:
269 # interact with objects if any
270 # if any object is a blocking object then avoid moving
271 if self.interact_objects (self.currentlevel, self.butaba.row, self.butaba.col + 1) is False:
272 return
273 if self.check_background_obstacle (self.currentlevel, self.butaba.row, self.butaba.col + 1) is False:
274 self.butaba.col += 1
275
276 def draw_butaba (self):
277 if self.butaba.position == butaba.Butaba.FRONT:
278 self.screen.blit (self.img_butabafront, (self.butaba.col*48, self.butaba.row*48))
279 elif self.butaba.position == butaba.Butaba.BACK:
280 self.screen.blit (self.img_butababack, (self.butaba.col*48, self.butaba.row*48))
281 elif self.butaba.position == butaba.Butaba.LEFT:
282 self.screen.blit (self.img_butabaleft, (self.butaba.col*48, self.butaba.row*48))
283 elif self.butaba.position == butaba.Butaba.RIGHT:
284 self.screen.blit (self.img_butabaright, (self.butaba.col*48, self.butaba.row*48))
285
286
287 # Draw the status infodisplay
288 def draw_status (self):
289 self.screen.blit (self.img_redpotion, (485, 10))
290 utility.put_text (self.screen, 550, 25, 24, (255, 0, 0), "%d" % self.butaba.health)
291
292 self.screen.blit (self.img_lightning, (620, 10))
293 utility.put_text (self.screen, 660, 20, 24, (255,255,255), "%d" % self.butaba.strength)
294
295 self.screen.blit (self.img_wand, (485, 65))
296 utility.put_text (self.screen, 550, 75, 24, (0, 0, 255), "%d" % self.butaba.magic)
297
298 self.screen.blit (self.img_bulb, (620, 65))
299 utility.put_text (self.screen, 660, 75, 24, (0, 255, 0), "%d" % self.butaba.experience)
300
301 self.screen.blit (self.img_goldcoins, (485, 110))
302 utility.put_text (self.screen, 550, 130, 24, (255, 255, 0), "%d" % self.butaba.gold)
303
304 if self.status_message is not None:
305 utility.put_text (self.screen, 10, 485, 18, (255,255, 0), "%s" % self.status_message)
306
307 # display the inventory of the player
308 def draw_inventory (self):
309 # draw the inventory slots
310 r = 1
311 c = 1
312 utility.put_text (self.screen, 490, 170, 22, (255,255 , 0), "Inventory")
313 for i in range (butaba.Butaba.MAXITEMS):
314 self.screen.blit (self.img_inventory, (440+c*54, 150+r*54))
315 if c % 4 == 0:
316 r += 1
317 c = 1
318 else:
319 c += 1
320
321 r = 1
322 c = 1
323 for obj in self.butaba.inventory:
324 self.screen.blit (obj.image, (440+c*54+2, 150+r*54+2))
325 if c % 4 == 0:
326 r += 1
327 c = 1
328 else:
329 c += 1
330
331 # Draw the level background tiles on surface
332 def draw_level_background (self, level):
333 i = 0
334 for row in level.background:
335 j = 0
336 for tilerow, tilecol, is_solid in row:
337 tilex = tilecol * 48
338 tiley = tilerow * 48
339 self.screen.blit (self.img_tileset, (j*48, i*48), pygame.Rect (tilex, tiley, 48, 48))
340
341 j += 1
342 i += 1
343
344 # Draw the level objects
345 def draw_level_objects (self, level):
346 for obj in level.objects:
347 if obj.image is not None:
348 self.screen.blit (obj.image, (obj.col*48, obj.row*48))