source: src/eventhandler.py @ 253

Last change on this file since 253 was 253, checked in by andefodahl, 3 years ago
File size: 27.6 KB
Line 
1"""
2eventhandler.py is the core of the game. It controls what is drawn,
3user input, and changing modes.
4"""
5
6import pygame
7from pygame.locals import QUIT, MOUSEMOTION, MOUSEBUTTONDOWN, MOUSEBUTTONUP
8from pygame.locals import KEYDOWN, KMOD_CAPS, KMOD_LSHIFT, KMOD_RSHIFT
9import sys
10from graphics import *
11from sound import *
12from menu import MenuHandler
13from story import *
14from survival import *
15from constants import BBUILDER
16import globalVars
17from transition import *
18
19#set globalVars
20globalVars.screen = pygame.display.set_mode((800, 600))
21globalVars.graphics = Graphics()
22globalVars.menuHandler  = MenuHandler()
23globalVars.soundPlayer = SoundPlayer()
24
25class EventHandler:
26    """The EventHandler class is the overseer for everything that happens in
27        the game. There is a single instance of it."""
28    def __init__(self):
29        """initializes EventHandler"""
30        self.mouseDown = False
31        self.dest = None
32        self.running = True
33        self.lastClicked = None
34        self.game = None
35        self.difficulty = None
36        self.mode = BBUILDER.MENU
37        self.transition = Transition()
38        self.transitionComplete = False
39        self.transitionComplete2 = False
40        self.transitioning = False
41
42    def update(self):
43        """updates the EventHandler. Key function. Acts based on self.mode"""
44        #Menu case
45        if self.mode == BBUILDER.MENU:
46            self.processMenuEvents()
47            if self.dest == "exit":
48                self.exit()
49                sys.exit()
50            elif self.dest != None and "play" in self.dest: #Game mode
51                if self.manageTransition():
52                    self.transitionComplete = True
53                   
54                if "Game" in self.dest:
55                    self.mode = BBUILDER.STORY
56                elif "Survival" in self.dest:
57                    self.mode = BBUILDER.SURVIVAL
58                   
59                if "Easy" in self.dest:
60                    self.difficulty = BBUILDER.EASY
61                elif "Medium" in self.dest:
62                    self.difficulty = BBUILDER.MEDIUM
63                elif "Hard" in self.dest:
64                    self.difficulty = BBUILDER.HARD
65
66                self.dest = None
67               
68            elif self.dest != None: #New Page
69                if globalVars.menuHandler.update(self.dest, globalVars.menuHandler.currentPage):
70                    # Reset keyboard-selected button
71                    self.dest = None
72            globalVars.menuHandler.draw()
73
74        #Story case
75        if self.mode == BBUILDER.STORY and self.transitionComplete:
76            self.transitionComplete2 = False
77            valueChange = self.processGameEvents()
78            score = self.game.update(valueChange)
79            if score == -1:
80                self.game.draw()
81            elif score == "Exit event":
82                self.transitioning = True
83                self.manageScoresTransition()
84            elif (score != -1): #Final score returned
85                globalVars.menuHandler.updateUnlock(self.difficulty, score) 
86                globalVars.menuHandler.currentPage = "enterName"
87                currentPage = globalVars.menuHandler.pageLibrary[
88                    globalVars.menuHandler.currentPage]
89                if self.game.exit:
90                    currentPage.textList[0].text = ""
91                else:
92                    currentPage.textList[0].text = "You win!"
93                currentPage.modeStr = "Story"
94                currentPage.score = int(score)
95                currentPage.textList[1].text = "Your score is "+str(score)
96                currentPage.textList[4].text = ""
97                self.game = None
98                self.transitionComplete = False
99                self.transitioning = True
100                self.mode = BBUILDER.INPUT
101                self.timer = 0
102                self.dest = None
103
104        #Survival case
105        if self.mode == BBUILDER.SURVIVAL and self.transitionComplete:
106            self.transitionComplete2 = False
107            self.game.draw()
108            valueChange = self.processGameEvents()
109            score = self.game.update(valueChange)
110            if score == "Exit event":
111                self.transitioning = True
112                self.manageScoresTransition()
113            elif (score != -1): #Final score returned
114                globalVars.menuHandler.currentPage = "enterName"
115                currentPage = globalVars.menuHandler.pageLibrary[
116                    globalVars.menuHandler.currentPage]
117                if self.game.exit:
118                    currentPage.textList[0].text = ""
119                else:
120                    currentPage.textList[0].text = "Time's up!"
121                currentPage.modeStr = "Survival"
122                currentPage.score = int(score[0])
123                currentPage.textList[1].text = "Your score is "+str(int(
124                    score[0]))
125                currentPage.textList[4].text = ""
126                self.game = None
127                self.transitionComplete = False
128                self.mode = BBUILDER.INPUT
129                self.timer = 0
130                self.dest = None
131       
132        if (self.mode == BBUILDER.SURVIVAL and not self.transitionComplete):
133            self.transitionComplete = self.manageTransition()
134
135        if (self.mode == BBUILDER.STORY and not self.transitionComplete):
136            self.transitionComplete = self.manageTransition()
137           
138        #Input case
139        if self.mode == BBUILDER.INPUT  and self.transitionComplete2:
140            self.processInput()
141            if self.dest == "exit":
142                self.exit()
143                sys.exit()
144            elif self.dest != None: #Mode on from Input
145                if self.dest == "scorePage":
146                    globalVars.menuHandler.pageLibrary[
147                        globalVars.menuHandler.currentPage].registerScore()
148                # Reset keyboard-selected button
149                globalVars.menuHandler.currentPage = self.dest
150                self.dest = None
151                self.mode = BBUILDER.MENU
152            globalVars.menuHandler.draw()
153       
154
155        if not self.transitionComplete2 and self.transitioning:
156            self.transitionComplete2 = self.manageScoresTransition()
157            if self.transitionComplete2:
158                self.transitioning = False
159
160        #Final action is to update screen
161        pygame.display.flip()
162
163    def processMenuEvents(self):
164        """processMenuEvents reads the necessary input for the menu mode.
165            If needed, it will change self.dest in order to change the page"""
166        currentPage = globalVars.menuHandler.pageLibrary[
167            globalVars.menuHandler.currentPage]
168        unlock = globalVars.menuHandler.unlock
169        for event in pygame.event.get():
170            if event.type == QUIT:
171                self.exit()
172                sys.exit()
173           
174            visibleButtons = []
175            for button in currentPage.menuButtonList:
176                if (button.unlock <= unlock):
177                    visibleButtons.append(button)
178                   
179            if event.type == MOUSEMOTION:
180                for buttonNum in range(len(visibleButtons)):
181                    button = visibleButtons[buttonNum]
182                    button.hover = False
183                    button.play = False
184                    if button.imageRect.collidepoint(event.pos):
185                        currentPage.selectedButton = button
186                        button.hover = True
187                        button.play = True
188                       
189            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
190                for button in visibleButtons:
191                    if button.imageRect.collidepoint(event.pos):
192#                        globalVars.soundPlayer.playSound("click.mp3")
193                        self.mouseDown = True
194                        button.active = True
195                        self.lastClicked = button
196                for clickableObject in currentPage.clickableObjects:
197                    if clickableObject.imageRect.collidepoint(event.pos):
198                        self.mouseDown = True
199                        self.lastClicked = clickableObject
200                       
201            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
202                for button in visibleButtons:
203                    if button == self.lastClicked:
204                        self.lastClicked.active = False
205                        if button.imageRect.collidepoint(event.pos):
206                            self.mouseDown = False
207                            button.clicked = False
208                            if globalVars.menuHandler.transition.isInactive():
209                                self.dest = button.dest
210                for clickableObject in currentPage.clickableObjects:
211                    if clickableObject == self.lastClicked:
212                        if clickableObject.imageRect.collidepoint(event.pos):
213                            clickableObject.clicked()
214                            self.mouseDown = False
215                self.lastClicked = None
216               
217            elif event.type == KEYDOWN:
218                key = pygame.key.name(event.key)
219                if key == "up" or key == "left":
220                    currentPage.selectButton(BBUILDER.BUTTON_PREV)
221                elif key == "down" or key == "right":
222                    currentPage.selectButton(BBUILDER.BUTTON_NEXT)
223                elif (key == "space" or key == "return") and currentPage.selectedButton != None:
224#                    globalVars.soundPlayer.playSound("click.mp3")
225                    self.dest = currentPage.selectedButton.dest
226
227    def processGameEvents(self):
228        """processGameEvents calls the appropriate processing function
229            based on the state of the game. Returns the change in value
230            from toggling blocks"""
231        #Sets currentPuzzles based on mode
232        if self.mode == BBUILDER.STORY:
233            currentPuzzle = self.game.levelDict[
234                self.game.currentLevel].currentPuzzle
235        elif self.mode == BBUILDER.SURVIVAL or self.mode == BBUILDER.BONUS:
236            currentPuzzle = self.game.currentPuzzle
237
238        curState = currentPuzzle.puzzleState
239           
240        if curState == BBUILDER.PUZZLE:
241            return self.processToggleEvents(currentPuzzle)
242        if curState == BBUILDER.INTRO or  curState == BBUILDER.END or curState == BBUILDER.VICTORY:
243            return self.processGameMenuEvents(currentPuzzle)
244        elif curState == BBUILDER.BONUS:
245            return self.processBonusEvents(currentPuzzle)
246        elif curState == BBUILDER.BONUS_INTRO:
247            return self.processGameMenuEvents(self.game.levelDict[
248                self.game.currentLevel])
249           
250
251    def processGameMenuEvents(self, currentPuzzle):
252        """event reader for game menus (if mode is not Puzzle)
253            returns 'Continue' if button is clicked, else 'No'"""
254        if currentPuzzle.puzzleState == BBUILDER.INTRO or currentPuzzle.puzzleState == BBUILDER.BONUS_INTRO:
255            buttonList = currentPuzzle.introButtons
256        elif currentPuzzle.puzzleState == BBUILDER.VICTORY:
257            buttonList = currentPuzzle.victoryButtons
258        else:
259            buttonList = currentPuzzle.endButtons
260
261        for event in pygame.event.get():
262            if event.type == QUIT:
263                self.exit()
264                sys.exit()
265            if event.type == MOUSEMOTION:
266                for button in buttonList:
267                    button.hover = False
268                    button.play = False
269                    if button.imageRect.collidepoint(event.pos):
270                        button.hover = True
271                        button.play = True
272                       
273            if event.type == MOUSEBUTTONDOWN and event.button == 1:
274                for button in buttonList:
275                    if button.imageRect.collidepoint(event.pos):
276#                        globalVars.soundPlayer.playSound("click.mp3")
277                        self.mouseDown = True
278                        button.active = True
279                        self.lastClicked = button
280                if currentPuzzle.puzzleState == BBUILDER.VICTORY and currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
281#                    globalVars.soundPlayer.playSound("click.mp3")
282                    self.mouseDown = True
283                    self.lastClicked = currentPuzzle.exitButton
284                       
285            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
286                for button in buttonList:
287                    if button == self.lastClicked:
288                        self.lastClicked.active = False
289                        self.lastClicked = None
290                        if button.imageRect.collidepoint(event.pos):
291                            self.mouseDown = False
292                            button.clicked = False
293                            return "Continue"
294                if currentPuzzle.puzzleState == BBUILDER.VICTORY and currentPuzzle.exitButton == self.lastClicked:
295                    if currentPuzzle.exitButton.imageRect.collidepoint(
296                        event.pos):
297                        self.mouseDown = False
298                        self.transitioning = True
299                        self.manageScoresTransition()
300                self.lastClicked = None
301
302            elif event.type == KEYDOWN:
303                key = pygame.key.name(event.key)
304                if key == "space" or key == "return":
305#                    globalVars.soundPlayer.playSound("click.mp3")
306                    return "Continue"
307
308        return "No"
309       
310    def processBonusEvents(self, currentPuzzle):
311        for event in pygame.event.get():
312            if event.type == QUIT:
313                self.exit()
314                sys.exit()
315            if event.type == MOUSEMOTION:
316                for toggleNum in range(len(currentPuzzle.choiceList)):
317                    toggle = currentPuzzle.choiceList[toggleNum]
318                    toggle.hover = False
319                    toggle.play = False
320                    for rect in toggle.rectList:
321                        if rect.collidepoint(event.pos):
322                            toggle.hover = True
323                            toggle.play = True
324                            currentPuzzle.selectedToggle = toggleNum
325                           
326            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
327                for toggle in currentPuzzle.choiceList:
328                    if not toggle.locked:
329                        for rect in toggle.rectList:
330                            if rect.collidepoint(event.pos):
331                                self.mouseDown = True
332                                self.lastClicked = toggle
333                if currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
334                    self.mouseDown = True
335                    self.lastClicked = currentPuzzle.exitButton
336                       
337            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
338                for toggle in currentPuzzle.choiceList:
339                    if toggle != self.lastClicked:
340                        if toggle.active:
341                            toggle.active = not toggle.active
342                    else:
343                        for rect in toggle.rectList : 
344                            if rect.collidepoint(event.pos):
345                                self.mouseDown = False
346                                if toggle.active:
347                                    valueChange = -1*toggle.value
348                                else: 
349                                    valueChange = toggle.value
350                                    toggle.active = not toggle.active
351                                return valueChange
352                if currentPuzzle.exitButton == self.lastClicked:
353                    if currentPuzzle.exitButton.imageRect.collidepoint(
354                        event.pos):
355                        self.mouseDown = False
356                        self.transitioning = True
357                        self.manageScoresTransition()
358                self.lastClicked = None
359           
360            elif event.type == KEYDOWN:
361                key = pygame.key.name(event.key)
362                if key == "right":
363                    currentPuzzle.selectToggleNext()
364                elif key == "down" or key == "up":
365                    currentPuzzle.selectToggleNext()
366                    currentPuzzle.selectToggleNext()
367                elif key == "left":
368                    currentPuzzle.selectTogglePrev()
369                elif (key == "space" or key == "return") and currentPuzzle.selectedToggle != None:
370#                    globalVars.soundPlayer.playSound("click.mp3")
371                    toggle = currentPuzzle.choiceList[
372                        currentPuzzle.selectedToggle]
373                    if toggle.active:
374                        valueChange = -1*toggle.value
375                    else: valueChange = toggle.value
376                    toggle.active = not toggle.active
377                    return valueChange
378                       
379
380    def processToggleEvents(self, currentPuzzle):
381        """event reader for actually playing the game (mode is Puzzle)
382            returns change in currentcount, else 0"""
383        for event in pygame.event.get():
384            if event.type == QUIT:
385                self.exit()
386                sys.exit()
387            if event.type == MOUSEMOTION:
388                for toggleNum in range(len(currentPuzzle.toggleList)):
389                    toggle = currentPuzzle.toggleList[toggleNum]
390                    toggle.hover = False
391                    toggle.play = False
392                    for rect in toggle.rectList : 
393                        if rect.collidepoint(event.pos):
394                            currentPuzzle.selectedToggle = toggleNum
395                            toggle.hover = True
396                            toggle.play = True
397                exitButton = currentPuzzle.exitButton
398                exitButton.hover = False
399                exitButton.play = False
400                if exitButton.imageRect.collidepoint(event.pos):
401                    exitButton.hover = True
402                    exitButton.play = True
403                           
404               
405
406            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
407                for toggle in currentPuzzle.toggleList:
408                    for rect in toggle.rectList : 
409                        if rect.collidepoint(event.pos):
410    #                        globalVars.soundPlayer.playSound("click.mp3")
411                            self.mouseDown = True
412                            self.lastClicked = toggle
413                if currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
414#                    globalVars.soundPlayer.playSound("click.mp3")
415                    self.mouseDown = True
416                    self.lastClicked = currentPuzzle.exitButton
417                       
418            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
419                for toggle in currentPuzzle.toggleList:
420                    if toggle == self.lastClicked:
421                        for rect in toggle.rectList : 
422                            if rect.collidepoint(event.pos):
423                                self.mouseDown = False
424                                if toggle.active and not toggle.locked:
425                                    valueChange = -1*toggle.value
426                                    toggle.active = not toggle.active
427                                elif not toggle.active and currentPuzzle.usedOnes < currentPuzzle.totalOnes:
428                                    valueChange = toggle.value
429                                    toggle.active = not toggle.active
430                                    if currentPuzzle.mode == BBUILDER.STORY:
431                                        currentPuzzle.usedOnes += 1
432                                else:
433                                    valueChange = 0
434                               
435                                return valueChange
436                if currentPuzzle.exitButton == self.lastClicked:
437                    if currentPuzzle.exitButton.imageRect.collidepoint(
438                        event.pos):
439                        self.mouseDown = False
440                        self.transitioning = True
441                        self.manageScoresTransition()
442                self.lastClicked = None
443               
444            elif event.type == KEYDOWN:
445                key = pygame.key.name(event.key)
446                if key == "up" or key == "left":
447                    currentPuzzle.selectToggleNext()
448                elif key == "down" or key == "right":
449                    currentPuzzle.selectTogglePrev()
450                elif (key == "space" or key == "return") and currentPuzzle.selectedToggle != None:
451#                    globalVars.soundPlayer.playSound("click.mp3")
452                    toggle = currentPuzzle.toggleList[
453                        currentPuzzle.selectedToggle]
454                    if toggle.active and not toggle.locked:
455                        valueChange = -1*toggle.value
456                        toggle.active = not toggle.active
457                    elif not toggle.active and currentPuzzle.usedOnes < currentPuzzle.totalOnes:
458                        valueChange = toggle.value
459                        toggle.active = not toggle.active
460                        if currentPuzzle.mode == BBUILDER.STORY:
461                            currentPuzzle.usedOnes += 1
462                    else:
463                        valueChange = 0
464                    return valueChange
465        return 0
466
467    def processInput(self):
468        """processInput reads the necessary input for the input mode.
469            If needed, it will change self.dest in order to change the page"""
470        self.timer += 1
471        currentPage = globalVars.menuHandler.pageLibrary[globalVars.menuHandler.currentPage]
472        for event in pygame.event.get():
473            if event.type == QUIT:
474                self.exit()
475                sys.exit()
476               
477            elif event.type == MOUSEMOTION:
478                for buttonNum in range(len(currentPage.menuButtonList)):
479                    button = currentPage.menuButtonList[buttonNum]
480                    button.hover = False
481                    button.play = False
482                    if button.imageRect.collidepoint(event.pos):
483                        button.hover = True
484                        button.play = True
485                        currentPage.selectedButton = buttonNum
486           
487            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
488                for button in currentPage.menuButtonList:
489                    if button.imageRect.collidepoint(event.pos):
490#                        globalVars.soundPlayer.playSound("click.mp3")
491                        self.mouseDown = True
492                        button.active = True
493                        self.lastClicked = button
494                       
495            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
496                for button in currentPage.menuButtonList:
497                    if button == self.lastClicked:
498                        self.lastClicked.active = False
499                        if button.imageRect.collidepoint(event.pos):
500                            self.mouseDown = False
501                            button.clicked = False
502                            # Special case for empty input string
503                            if currentPage.inputStr != "" or button.dest == "page0":
504                                self.dest = button.dest
505                            else:
506                                currentPage.textList[4].text = "Please type a name"
507                self.lastClicked = None
508               
509            elif event.type == KEYDOWN:
510                key = pygame.key.name(event.key)
511                if len(key) == 1 or key == "space" or key == "backspace":
512                    caps = pygame.key.get_mods() & (KMOD_CAPS | KMOD_LSHIFT | KMOD_RSHIFT)
513                    currentPage.updateInput(key, caps)
514                elif key == "return":
515                    if currentPage.selectedButton != None:
516#                        globalVars.soundPlayer.playSound("click.mp3")
517                        button = currentPage.menuButtonList[currentPage.selectedButton]
518                        if currentPage.inputStr != "":
519                            self.dest = button.dest
520                            button.clicked = False
521                            self.mouseDown = False
522                            if self.lastClicked != None:
523                                self.lastClicked.active = False
524                        else:
525                            currentPage.textList[4].text = "Please type a name"
526                   
527    def manageTransition(self):
528        if self.transition.isInactive():
529            self.transition.setTransition(BubbleBackground(globalVars.screen, 0, 1))
530            self.transition.incrementTimer()
531            return False
532        elif not self.transition.isInactive() and self.transition.timer == 30:
533            self.transition.drawBackground()
534            if self.game == None and self.mode == BBUILDER.STORY:
535                self.game = Story(self.difficulty)
536            elif self.game == None and self.mode == BBUILDER.SURVIVAL:
537                self.game = Survival(self.difficulty)
538            self.game.draw()
539            self.transition.update(False)
540            self.transition.incrementTimer()
541            return False
542        elif not self.transition.isInactive() and self.transition.timer == 60:
543            self.transition.resetTimer()
544            self.transition.resetTransition()
545            pygame.event.clear()
546            return True
547        elif not self.transition.isInactive() and self.transition.timer != 60:
548            self.transition.drawBackground()
549            if self.game != None:
550                self.game.draw()
551            else:
552                globalVars.menuHandler.draw()
553            self.transition.update(False)   
554            self.transition.incrementTimer()
555            pygame.event.clear()
556            return False
557           
558    def manageScoresTransition(self):
559        if self.transition.isInactive():
560            self.transition.setTransition(BubbleBackground(globalVars.screen, 0, 1))
561            self.transition.incrementTimer()
562            return False
563        elif not self.transition.isInactive() and self.transition.timer == 30:
564            self.transition.drawBackground()
565            self.game.exit = True
566            self.game.draw()
567            self.transition.update(False)
568            self.transition.incrementTimer()
569            return False
570        elif not self.transition.isInactive() and self.transition.timer == 60:
571            self.transition.resetTimer()
572            self.transition.resetTransition()
573            pygame.event.clear()
574            return True
575        elif not self.transition.isInactive() and self.transition.timer != 60:
576            self.transition.drawBackground()
577            if self.transition.timer < 30:
578                self.game.draw()
579            else:
580                globalVars.menuHandler.draw()
581            self.transition.update(False)   
582            self.transition.incrementTimer()
583            pygame.event.clear()
584            return False
585       
586   
587    def exit(self):
588        """exit is called at the end to close stuff nicely"""
589        pygame.quit()
590        self.running = False
591       
Note: See TracBrowser for help on using the repository browser.