root/src/story.py @ 177

Revision 177, 18.2 KB (checked in by andefodahl, 2 years 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.