root/src/story.py @ 177

Revision 177, 18.2 KB (checked in by andefodahl, 23 months ago)

Score modification for failed story mode actions

Line 
1"""
2Story mode. Contains the different classes that form the hierarchy of
3story mode.
4"""
5
6import pygame
7from random import randint
8from gameobject import *
9from constants import BBUILDER
10from math import log
11import globalVars
12
13class Story:
14    """Story is the highest level class in the story. Keep track of
15        levels and changes between them."""
16    def __init__(self, difficulty=0):
17        """initializes a Story"""
18        self.score = 0
19        self.rank = 0
20        self.difficulty = difficulty
21        self.levelDict = {}
22        self.maxLevel = 3
23        for levelNum in range(self.maxLevel):
24            background = 'background'+str(levelNum)
25            level = Level(self.difficulty, levelNum, background)
26            self.levelDict[levelNum] = level
27        self.currentLevel = 0
28        self.exit = False #Exit flag
29
30    def update(self, valueChange):
31        """update function for Story. Calls currentLevel's update
32            and moves appropriately."""
33        if self.exit:
34            return self.score
35       
36        levelStatus = self.levelDict[self.currentLevel].update(valueChange)
37        if levelStatus[0] == "UpdateScore":
38            adjustment = float(10-levelStatus[1]) / 10.0
39            self.score += 1000*(self.currentLevel+1+self.difficulty)*(adjustment)
40        elif levelStatus == "IncrementLevel":
41            self.currentLevel += 1
42            if self.currentLevel >= self.maxLevel:
43                return self.score
44        return -1 #Recognized by EventHandler as incomplete Story
45
46    def draw(self):
47        """draw function for story."""
48        globalVars.graphics.drawImage(BBUILDER.STORY_BG_LIST[self.levelDict
49                                    [self.currentLevel].background], (0,0))
50        globalVars.graphics.drawText("Level: "+str(int(self.currentLevel)),
51                                     775, 10, 30, pygame.Color("black"), "right")
52        globalVars.graphics.drawText("Score: "+str(int(self.score)),
53                                     775, 35, 30, pygame.Color("black"),
54                                     "right")
55        self.levelDict[self.currentLevel].draw()
56       
57class Level:
58    """Levels are the next level down from Story. Levels contain puzzles."""
59    def __init__(self, difficulty, levelNum, background):
60        """initializes a Level"""
61        self.time = 60000
62        self.puzzlesCompleted = 0
63        self.difficulty = difficulty
64        self.levelNum = levelNum
65        self.currentPuzzle = self.generatePuzzle()
66        self.clock = pygame.time.Clock()
67        self.background = background
68        self.mistakes = 0
69
70    def generatePuzzle(self):
71        """generates a puzzle based on parameters."""
72        return Puzzle(randint(1,BBUILDER.MAXPUZZLESIZE[self.difficulty]), BBUILDER.INTRO, "cursor0.png",
73                      True, self.levelNum, self.puzzlesCompleted, difficulty=self.difficulty)
74        #second number is maximum supported puzzle value
75        #randint(0,2)+(1+2*self.puzzlesCompleted)
76
77    def update(self, valueChange):
78        """updates a Level"""
79        if self.currentPuzzle.mode == BBUILDER.PUZZLE:
80            self.time += -self.clock.tick()
81            if self.time < 0:
82                self.time = 0
83        puzzleComplete = self.currentPuzzle.update(valueChange)
84       
85        if puzzleComplete == "Next":
86            if self.puzzlesCompleted >= 3:
87                return "IncrementLevel"
88            self.currentPuzzle = self.generatePuzzle()
89           
90        if puzzleComplete == "Score++":
91            self.puzzlesCompleted += 1
92            mistakes = self.mistakes
93            self.mistakes = 0
94            return ("UpdateScore", mistakes)
95           
96        if puzzleComplete == False:
97            self.mistakes += 1
98       
99        return "None"
100   
101    def draw(self):
102        """draws a Level"""
103        self.currentPuzzle.draw()
104
105class Puzzle:
106    """Puzzle is a class that falls below Level. It contains individual
107        puzzles"""
108    def __init__(self, goalNumber, mode, cursor, showVicScreen = False,
109                 levelNum = -1, puzzleNum = -1, difficulty=0):
110        """initializes a Puzzle"""
111        self.goalNumber = goalNumber
112        self.binGoalNumber = self.getBinaryNumber()
113        self.currentCount = 0
114        self.difficulty = difficulty
115        if difficulty == 0:
116            self.toggleList = [Toggle(BBUILDER.TOGGLE_0, 1, (550, 430), (65,65), 0),
117                               Toggle(BBUILDER.TOGGLE_0, 2, (400, 430), (65,65), 1),
118                               Toggle(BBUILDER.TOGGLE_0, 4, (250, 430), (65,65), 2)]
119        elif difficulty == 1:
120            self.toggleList = [Toggle(BBUILDER.TOGGLE_0, 1, (650, 430), (65,65), 0),
121                               Toggle(BBUILDER.TOGGLE_0, 2, (550, 430), (65,65), 1),
122                               Toggle(BBUILDER.TOGGLE_0, 4, (450, 430), (65,65), 2),
123                               Toggle(BBUILDER.TOGGLE_0, 8, (350, 430), (65,65), 3),
124                               Toggle(BBUILDER.TOGGLE_0, 16, (250, 430), (65,65), 4),
125                               Toggle(BBUILDER.TOGGLE_0, 32, (150, 430), (65,65), 5)]
126                               
127        else:
128##            self.toggleList = [Toggle(BBUILDER.TOGGLE_0, 128, (25, 430), (65,65)),
129##                               Toggle(BBUILDER.TOGGLE_0, 64, (132, 430), (65,65)),
130##                               Toggle(BBUILDER.TOGGLE_0, 32, (239, 430), (65,65)),
131##                               Toggle(BBUILDER.TOGGLE_0, 16, (346, 430), (65,65)),
132##                               Toggle(BBUILDER.TOGGLE_0, 8, (453, 430), (65,65)),
133##                               Toggle(BBUILDER.TOGGLE_0, 4, (560, 430), (65,65)),
134##                               Toggle(BBUILDER.TOGGLE_0, 2, (667, 430), (65,65)),
135##                               Toggle(BBUILDER.TOGGLE_0, 1, (774, 430), (65,65))]
136
137
138            self.toggleList = [Toggle(BBUILDER.TOGGLE_0, 1, (650, 430), (65,65), 0),
139                               Toggle(BBUILDER.TOGGLE_0, 2, (550, 430), (65,65), 1),
140                               Toggle(BBUILDER.TOGGLE_0, 4, (450, 430), (65,65), 2),
141                               Toggle(BBUILDER.TOGGLE_0, 8, (350, 430), (65,65), 3),
142                               Toggle(BBUILDER.TOGGLE_0, 16, (250, 430), (65,65), 4),
143                               Toggle(BBUILDER.TOGGLE_0, 32, (150, 430), (65,65), 5)]
144                               
145       
146        self.exitButton = GameButton(BBUILDER.BUTTON_0,
147                                     (105,30), (200,50), "Quit")
148        self.selectedToggle = 0
149        self.puzzleGoal = self.generatePuzzleGoal()
150        self.selectedMenuButton = 0 #Cursor starts on button
151        self.cursor = "cursor0.png"
152       
153        self.mode = mode
154        self.showVicScreen = showVicScreen #Flag for showing the victory screen
155        self.introText = None
156        self.endText = None
157        if ((levelNum != -1) and (puzzleNum != -1)): #If they were set
158            self.introText = BBUILDER.INTROTEXT[levelNum][puzzleNum]
159            self.endText = BBUILDER.ENDTEXT[levelNum][puzzleNum]
160            self.introButtons = [GameButton(BBUILDER.BUTTON_0, (600,500),
161                                            (200,50), "Continue")]
162            self.endButtons = [GameButton(BBUILDER.BUTTON_0, (600,500),
163                                            (200,50), "Next Puzzle...")]
164
165        if self.mode == BBUILDER.INTRO and self.introText == None:
166            self.mode = BBUILDER.PUZZLE
167
168        if self.showVicScreen:
169            self.victoryButtons = [GameButton(BBUILDER.BUTTON_0, (650,365),
170                                            (200,50), "Continue")]
171
172    def generatePuzzleGoal(self):
173        """generates a PuzzleGoal object"""
174        puzzleNum = randint(0, BBUILDER.PUZZLETYPECOUNT-1)
175        puzzleType = BBUILDER.PUZZLETYPES[puzzleNum]
176        for sizeIndex in range(len(BBUILDER.MAXPUZZLESIZE)):
177            if self.goalNumber <= BBUILDER.MAXPUZZLESIZE[sizeIndex]:
178                break #Lowest sizeIndex that fits
179        blockCords = BBUILDER.PUZZLECORDS[puzzleNum][sizeIndex]
180        puzzlePos = BBUILDER.PUZZLEPOS[puzzleNum]
181        return PuzzleGoal(puzzlePos, puzzleType, self.goalNumber, blockCords, self.difficulty)
182
183    def update(self, valueChange):
184        """updates a Puzzle"""
185        if valueChange == "Continue": #Mode is Intro, Victory, or End
186            if self.mode == BBUILDER.INTRO:
187                self.mode = BBUILDER.PUZZLE
188            elif self.mode == BBUILDER.VICTORY:
189                self.mode = BBUILDER.END
190            else: #self.mode == BBUILDER.END
191                return "Next"
192        elif type(valueChange) == int: #mode is Puzzle
193            self.currentCount += valueChange
194            if (self.currentCount == self.goalNumber):
195                if self.showVicScreen:
196                    self.mode = BBUILDER.VICTORY
197                else:
198                    self.mode = BBUILDER.END
199                return "Score++"
200            if (valueChange > 0):
201                bitNumber = int(log(valueChange, 2))
202                if (bitNumber > len(self.binGoalNumber)-1):
203                    return False           
204                elif (self.binGoalNumber[-bitNumber -1] == '0'):
205                    return False
206                return True
207        if self.mode == BBUILDER.END and self.endText == None:
208            return "Next"
209
210    def selectTogglePrev(self):
211        """changes location of cursor. Called by EventHandler."""
212        if self.selectedToggle != None:
213            if self.selectedToggle != 0:
214                self.selectedToggle += -1
215            else: self.selectedToggle = len(self.toggleList) - 1
216        else:
217            self.selectedToggle = 0
218
219    def selectToggleNext(self):
220        """changes location of cursor. Called by EventHandler."""
221        if self.selectedToggle != None:
222            if self.selectedToggle != len(self.toggleList) - 1:
223                self.selectedToggle += 1
224            else: self.selectedToggle = 0
225        else:
226            self.selectedToggle = 0
227
228    def draw(self):
229        """draws a Puzzle by calling the appropriate function"""
230        if self.mode == BBUILDER.INTRO:
231            self.drawIntro()
232        elif self.mode == BBUILDER.END:
233            self.drawEnd()
234        else:
235            self.drawPuzzle()
236
237    def drawIntro(self):
238        """draws a Puzzle when in Intro mode"""
239        globalVars.graphics.drawImage("textBG_brown.png", (100,134))
240        if self.introText != None:
241            globalVars.graphics.drawText(self.introText, 150, 180, 30,
242                                         pygame.Color("black"), "left",
243                                         "fonts\coolvetica rg.ttf")
244        for button in self.introButtons:
245            button.draw()
246            globalVars.graphics.drawImage(self.cursor,(button.x-50, button.y))
247
248    def drawEnd(self):
249        """draws a Puzzle when in End mode"""
250        globalVars.graphics.drawImage("textBG_brown.png", (100,134))
251        if self.endText != None:
252            globalVars.graphics.drawText(self.endText, 150, 180, 30,
253                                         pygame.Color("black"), "left",
254                                         "fonts\coolvetica rg.ttf")
255        for button in self.endButtons:
256            button.draw()
257            globalVars.graphics.drawImage(self.cursor,(button.x-50, button.y))
258
259    def drawPuzzle(self):
260        """draws a Puzzle when in Puzzle mode or Victory Mode"""
261        for toggleNum in range(len(self.toggleList)):
262            currentToggle = toggleNum - len(self.toggleList)
263            toggle = self.toggleList[currentToggle]
264            toggle.draw()
265           
266            if toggleNum == self.selectedToggle and self.mode != BBUILDER.VICTORY:
267                globalVars.graphics.drawImage("cursor0.png",
268                                              (toggle.x-60, toggle.y)) #Magic!
269        self.exitButton.draw()
270
271        globalVars.graphics.drawText("Current: "+str(self.currentCount),
272                                     725, 225, 30, pygame.Color("black"),
273                                     "right")
274        globalVars.graphics.drawText("Remaining: "+str(
275                                     self.goalNumber-self.currentCount),
276                                     725, 250, 30, pygame.Color("black"),
277                                     "right")
278        if self.currentCount > self.goalNumber:
279            globalVars.graphics.drawText("Too many blocks!", 50, 210, 36, pygame.Color("red"))
280
281        if self.mode == BBUILDER.VICTORY: #Victory mode PuzzleGoal
282            self.drawVictory()
283                                                         
284        else:
285            self.puzzleGoal.draw(self.currentCount)
286            globalVars.graphics.drawText("Goal: " + str(self.goalNumber),
287                                     400, 110, 120, pygame.Color("black"),
288                                     "center")
289           
290
291    def drawVictory(self):
292        self.puzzleGoal.complete()
293        for button in self.victoryButtons:
294            button.draw()
295            globalVars.graphics.drawImage(self.cursor,(button.x-50, button.y))
296
297        if self.difficulty == 0:
298            textLeft = 200
299            buttonsLeft = 350
300        elif self.difficulty == 1:
301            textLeft = 150
302            buttonsLeft = 350
303        else:
304            textLeft = 50
305            buttonsLeft = 280
306
307        globalVars.graphics.drawText(str(self.goalNumber) + " = ", textLeft, 80, 120,
308                                     pygame.Color("black"), "left")
309        strBinaryNum = self.binGoalNumber
310
311        for i in range(len(strBinaryNum)):
312            if strBinaryNum[i] == '1':
313                imageName = "toggle0_depressed.png"
314            else:
315                imageName = "toggle0_neutral.png"
316            globalVars.graphics.drawImage(imageName,(buttonsLeft + 60*i, 90))
317            globalVars.graphics.drawText(strBinaryNum[i],
318                        25+buttonsLeft+60*i, 110, 40, pygame.Color("white"))
319           
320
321    def getBinaryNumber(self):
322        strBinaryNum = ""
323        n = self.goalNumber
324        while n > 0:
325            strBinaryNum = str(n % 2) + strBinaryNum
326            n = n >> 1
327        return strBinaryNum
328
329class Toggle(GameObject):
330    """used by Puzzle. Represents toggle buttons with values"""
331    def __init__(self, image, value, pos, size, index):
332        """initializes a Toggle"""
333        GameObject.__init__(self, image, pos, size) #How I super?
334        self.active = False
335        self.value = value
336        self.pos = pos
337        self.index = index
338       
339        # assume inactive type
340        self.imageBlock = BBUILDER.INACTIVE_TOGGLE_PIC[self.index]
341        self.imageBlockSize = BBUILDER.TOGGLE_PIC_SIZE[self.index]
342        self.imageBlockPos =(self.pos[0]-self.imageBlockSize[0]/2,
343                                 self.pos[1]+100-self.imageBlockSize[1]/2)
344       
345        self.rectList = [self.imageRect, pygame.Rect(self.imageBlockPos, self.imageBlockSize)]
346       
347        # activeDropValue is the amount by which the Toggle Blocks (not buttons)
348        # are lowered (y axis) when active.
349        self.activeDropValue = -20
350
351    def draw(self):
352        """draws a Toggle"""
353        if self.active:
354            text = pygame.font.Font(None, 40).render(
355                '1', 1, pygame.Color("white")) #Woo magic
356            self.imageBlock = BBUILDER.ACTIVE_TOGGLE_PIC[self.index] 
357            self.imageBlockPos = (self.pos[0]-self.imageBlockSize[0]/2,
358                                 self.pos[1]+100-self.imageBlockSize[1]/2 + self.activeDropValue)
359        else:
360            text = pygame.font.Font(None, 40).render('0', 1, pygame.Color("gray"))
361            self.imageBlock = BBUILDER.INACTIVE_TOGGLE_PIC[self.index]
362            self.imageBlockPos =(self.pos[0]-self.imageBlockSize[0]/2,
363                                 self.pos[1]+100-self.imageBlockSize[1]/2)
364           
365        globalVars.graphics.drawObject(self, text)
366        globalVars.graphics.drawImage(self.imageBlock, self.imageBlockPos)
367       
368
369
370class GameButton(GameObject):
371    """game button from a puzzle."""
372    def __init__(self, image, pos, size, text):
373        """initializes a GameButton"""
374        GameObject.__init__(self, image, pos, size) #How I super?
375        self.active = False
376        self.text = text
377        self.textSize = 25 #Magic!
378        self.textColor = pygame.Color("black") #Double magic!
379
380    def draw(self):
381        """draws a GameButton"""
382        text = pygame.font.Font(None, self.textSize).render(self.text, 1,
383                                                            self.textColor)
384        globalVars.graphics.drawObject(self, text)
385
386class PuzzleGoal:
387    """used by Puzzle. Represents the object being created by the player"""
388    def __init__(self, pos, objType, value, cords, difficulty):
389        """initializes a puzzleGoal"""
390        self.pos = pos
391        self.type = objType
392        self.value = value
393        self.cords = cords
394        self.difficulty = difficulty
395
396    def draw(self, currentCount):
397        """draws a puzzleGoal"""
398        try:
399            for i in range(self.value):
400                if i < currentCount and self.difficulty < 2:
401                    if len(self.cords) < 8:
402                        image = "activeGoalBlock.png"
403                    elif len(self.cords) < 64:
404                        image = "activeGoalBlock1.png"
405                    else:
406                        image = "activeGoalBlock2.png"
407                else:
408                    if len(self.cords) < 8:
409                        image = "inactiveGoalBlock.png"
410                    elif len(self.cords) < 64:
411                        image = "inactiveGoalBlock1.png"
412                    else:
413                        image = "inactiveGoalBlock2.png"
414                pos = (self.pos[0]+self.cords[i][0], self.pos[1]+self.cords[i][1])
415                globalVars.graphics.drawImage(image, pos)
416        except:
417            print "Error: Puzzle value too large for PuzzleGoal"
418
419    def complete(self):
420        """draws a PuzzleGoal in VictoryMode"""
421        globalVars.graphics.drawImage("puzzleComplete.png", (75,185))
422        globalVars.graphics.drawImage(self.type+".png", self.pos)
Note: See TracBrowser for help on using the browser.