source: src/eventhandler.py @ 267

Last change on this file since 267 was 267, checked in by andefodahl, 3 years ago

Hopefully revamped hover system

File size: 26.9 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                    if button.imageRect.collidepoint(event.pos):
183                        currentPage.changeButton(buttonNum)
184                       
185            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
186                for button in visibleButtons:
187                    if button.imageRect.collidepoint(event.pos):
188#                        globalVars.soundPlayer.playSound("click.mp3")
189                        self.mouseDown = True
190                        button.active = True
191                        self.lastClicked = button
192                for clickableObject in currentPage.clickableObjects:
193                    if clickableObject.imageRect.collidepoint(event.pos):
194                        self.mouseDown = True
195                        self.lastClicked = clickableObject
196                       
197            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
198                for button in visibleButtons:
199                    if button == self.lastClicked:
200                        self.lastClicked.active = False
201                        if button.imageRect.collidepoint(event.pos):
202                            self.mouseDown = False
203                            button.clicked = False
204                            if globalVars.menuHandler.transition.isInactive():
205                                self.dest = button.dest
206                for clickableObject in currentPage.clickableObjects:
207                    if clickableObject == self.lastClicked:
208                        if clickableObject.imageRect.collidepoint(event.pos):
209                            clickableObject.clicked()
210                            self.mouseDown = False
211                self.lastClicked = None
212               
213            elif event.type == KEYDOWN:
214                key = pygame.key.name(event.key)
215                if key == "up" or key == "left":
216                    currentPage.selectButton(BBUILDER.BUTTON_PREV)
217                elif key == "down" or key == "right":
218                    currentPage.selectButton(BBUILDER.BUTTON_NEXT)
219                elif (key == "space" or key == "return") and currentPage.selectedButton != None:
220#                    globalVars.soundPlayer.playSound("click.mp3")
221                    self.dest = currentPage.selectedButton.dest
222
223    def processGameEvents(self):
224        """processGameEvents calls the appropriate processing function
225            based on the state of the game. Returns the change in value
226            from toggling blocks"""
227        #Sets currentPuzzles based on mode
228        if self.mode == BBUILDER.STORY:
229            currentPuzzle = self.game.levelDict[
230                self.game.currentLevel].currentPuzzle
231        elif self.mode == BBUILDER.SURVIVAL or self.mode == BBUILDER.BONUS:
232            currentPuzzle = self.game.currentPuzzle
233
234        curState = currentPuzzle.puzzleState
235           
236        if curState == BBUILDER.PUZZLE:
237            return self.processToggleEvents(currentPuzzle)
238        if curState == BBUILDER.INTRO or  curState == BBUILDER.END or curState == BBUILDER.VICTORY:
239            return self.processGameMenuEvents(currentPuzzle)
240        elif curState == BBUILDER.BONUS:
241            return self.processBonusEvents(currentPuzzle)
242        elif curState == BBUILDER.BONUS_INTRO:
243            return self.processGameMenuEvents(self.game.levelDict[
244                self.game.currentLevel])
245           
246
247    def processGameMenuEvents(self, currentPuzzle):
248        """event reader for game menus (if mode is not Puzzle)
249            returns 'Continue' if button is clicked, else 'No'"""
250        if currentPuzzle.puzzleState == BBUILDER.INTRO or currentPuzzle.puzzleState == BBUILDER.BONUS_INTRO:
251            buttonList = currentPuzzle.introButtons
252        elif currentPuzzle.puzzleState == BBUILDER.VICTORY:
253            buttonList = currentPuzzle.victoryButtons
254        else:
255            buttonList = currentPuzzle.endButtons
256
257        for event in pygame.event.get():
258            if event.type == QUIT:
259                self.exit()
260                sys.exit()
261            if event.type == MOUSEMOTION:
262                for button in buttonList:
263                    button.hover = False
264                    button.play = False
265                    if button.imageRect.collidepoint(event.pos):
266                        button.hover = True
267                        button.play = True
268                       
269            if event.type == MOUSEBUTTONDOWN and event.button == 1:
270                for button in buttonList:
271                    if button.imageRect.collidepoint(event.pos):
272#                        globalVars.soundPlayer.playSound("click.mp3")
273                        self.mouseDown = True
274                        button.active = True
275                        self.lastClicked = button
276                if currentPuzzle.puzzleState == BBUILDER.VICTORY and currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
277#                    globalVars.soundPlayer.playSound("click.mp3")
278                    self.mouseDown = True
279                    self.lastClicked = currentPuzzle.exitButton
280                       
281            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
282                for button in buttonList:
283                    if button == self.lastClicked:
284                        self.lastClicked.active = False
285                        self.lastClicked = None
286                        if button.imageRect.collidepoint(event.pos):
287                            self.mouseDown = False
288                            button.clicked = False
289                            return "Continue"
290                if currentPuzzle.puzzleState == BBUILDER.VICTORY and currentPuzzle.exitButton == self.lastClicked:
291                    if currentPuzzle.exitButton.imageRect.collidepoint(
292                        event.pos):
293                        self.mouseDown = False
294                        self.transitioning = True
295                        self.manageScoresTransition()
296                self.lastClicked = None
297
298            elif event.type == KEYDOWN:
299                key = pygame.key.name(event.key)
300                if key == "space" or key == "return":
301#                    globalVars.soundPlayer.playSound("click.mp3")
302                    return "Continue"
303
304        return "No"
305       
306    def processBonusEvents(self, currentPuzzle):
307        for event in pygame.event.get():
308            if event.type == QUIT:
309                self.exit()
310                sys.exit()
311            if event.type == MOUSEMOTION:
312                for toggleNum in range(len(currentPuzzle.choiceList)):
313                    toggle = currentPuzzle.choiceList[toggleNum]
314                    for rect in toggle.rectList:
315                        if rect.collidepoint(event.pos):
316                            currentPuzzle.selectedToggle = toggleNum
317                           
318            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
319                for toggle in currentPuzzle.choiceList:
320                    if not toggle.locked:
321                        for rect in toggle.rectList:
322                            if rect.collidepoint(event.pos):
323                                self.mouseDown = True
324                                self.lastClicked = toggle
325                if currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
326                    self.mouseDown = True
327                    self.lastClicked = currentPuzzle.exitButton
328                       
329            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
330                for toggle in currentPuzzle.choiceList:
331                    if toggle != self.lastClicked:
332                        if toggle.active:
333                            toggle.active = not toggle.active
334                    else:
335                        for rect in toggle.rectList : 
336                            if rect.collidepoint(event.pos):
337                                self.mouseDown = False
338                                if toggle.active:
339                                    valueChange = -1*toggle.value
340                                else: 
341                                    valueChange = toggle.value
342                                    toggle.active = not toggle.active
343                                return valueChange
344                if currentPuzzle.exitButton == self.lastClicked:
345                    if currentPuzzle.exitButton.imageRect.collidepoint(
346                        event.pos):
347                        self.mouseDown = False
348                        self.transitioning = True
349                        self.manageScoresTransition()
350                self.lastClicked = None
351           
352            elif event.type == KEYDOWN:
353                key = pygame.key.name(event.key)
354                if key == "right":
355                    currentPuzzle.selectToggleNext()
356                elif key == "down" or key == "up":
357                    currentPuzzle.selectToggleNext()
358                    currentPuzzle.selectToggleNext()
359                elif key == "left":
360                    currentPuzzle.selectTogglePrev()
361                elif (key == "space" or key == "return") and currentPuzzle.selectedToggle != None:
362#                    globalVars.soundPlayer.playSound("click.mp3")
363                    toggle = currentPuzzle.choiceList[
364                        currentPuzzle.selectedToggle]
365                    if toggle.active:
366                        valueChange = -1*toggle.value
367                    else: valueChange = toggle.value
368                    toggle.active = not toggle.active
369                    return valueChange
370                       
371
372    def processToggleEvents(self, currentPuzzle):
373        """event reader for actually playing the game (mode is Puzzle)
374            returns change in currentcount, else 0"""
375        for event in pygame.event.get():
376            if event.type == QUIT:
377                self.exit()
378                sys.exit()
379            if event.type == MOUSEMOTION:
380                for toggleNum in range(len(currentPuzzle.toggleList)):
381                    toggle = currentPuzzle.toggleList[toggleNum]
382                    for rect in toggle.rectList : 
383                        if rect.collidepoint(event.pos):
384                            currentPuzzle.selectedToggle = toggleNum
385                exitButton = currentPuzzle.exitButton
386                exitButton.hover = False
387                exitButton.play = False
388                if exitButton.imageRect.collidepoint(event.pos):
389                    exitButton.hover = True
390                    exitButton.play = True
391                           
392               
393
394            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
395                for toggle in currentPuzzle.toggleList:
396                    for rect in toggle.rectList : 
397                        if rect.collidepoint(event.pos):
398    #                        globalVars.soundPlayer.playSound("click.mp3")
399                            self.mouseDown = True
400                            self.lastClicked = toggle
401                if currentPuzzle.exitButton.imageRect.collidepoint(event.pos):
402#                    globalVars.soundPlayer.playSound("click.mp3")
403                    self.mouseDown = True
404                    self.lastClicked = currentPuzzle.exitButton
405                       
406            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
407                for toggle in currentPuzzle.toggleList:
408                    if toggle == self.lastClicked:
409                        for rect in toggle.rectList : 
410                            if rect.collidepoint(event.pos):
411                                self.mouseDown = False
412                                if toggle.active and not toggle.locked:
413                                    valueChange = -1*toggle.value
414                                    toggle.active = not toggle.active
415                                elif not toggle.active and currentPuzzle.usedOnes < currentPuzzle.totalOnes:
416                                    valueChange = toggle.value
417                                    toggle.active = not toggle.active
418                                    if currentPuzzle.mode == BBUILDER.STORY:
419                                        currentPuzzle.usedOnes += 1
420                                else:
421                                    valueChange = 0
422                               
423                                return valueChange
424                if currentPuzzle.exitButton == self.lastClicked:
425                    if currentPuzzle.exitButton.imageRect.collidepoint(
426                        event.pos):
427                        self.mouseDown = False
428                        self.transitioning = True
429                        self.manageScoresTransition()
430                self.lastClicked = None
431               
432            elif event.type == KEYDOWN:
433                key = pygame.key.name(event.key)
434                if key == "up" or key == "left":
435                    currentPuzzle.selectToggleNext()
436                elif key == "down" or key == "right":
437                    currentPuzzle.selectTogglePrev()
438                elif (key == "space" or key == "return") and currentPuzzle.selectedToggle != None:
439#                    globalVars.soundPlayer.playSound("click.mp3")
440                    toggle = currentPuzzle.toggleList[
441                        currentPuzzle.selectedToggle]
442                    if toggle.active and not toggle.locked:
443                        valueChange = -1*toggle.value
444                        toggle.active = not toggle.active
445                    elif not toggle.active and currentPuzzle.usedOnes < currentPuzzle.totalOnes:
446                        valueChange = toggle.value
447                        toggle.active = not toggle.active
448                        if currentPuzzle.mode == BBUILDER.STORY:
449                            currentPuzzle.usedOnes += 1
450                    else:
451                        valueChange = 0
452                    return valueChange
453        return 0
454
455    def processInput(self):
456        """processInput reads the necessary input for the input mode.
457            If needed, it will change self.dest in order to change the page"""
458        self.timer += 1
459        currentPage = globalVars.menuHandler.pageLibrary[globalVars.menuHandler.currentPage]
460        for event in pygame.event.get():
461            if event.type == QUIT:
462                self.exit()
463                sys.exit()
464               
465            if event.type == MOUSEMOTION:
466                for buttonNum in range(len(currentPage.menuButtonList)):
467                    button = currentPage.menuButtonList[buttonNum]
468                    if button.imageRect.collidepoint(event.pos):
469                        currentPage.changeButton(buttonNum)
470           
471            elif event.type == MOUSEBUTTONDOWN and event.button == 1:
472                for button in currentPage.menuButtonList:
473                    if button.imageRect.collidepoint(event.pos):
474#                        globalVars.soundPlayer.playSound("click.mp3")
475                        self.mouseDown = True
476                        button.active = True
477                        self.lastClicked = button
478                       
479            elif event.type == MOUSEBUTTONUP and self.mouseDown == True:
480                for button in currentPage.menuButtonList:
481                    if button == self.lastClicked:
482                        self.lastClicked.active = False
483                        if button.imageRect.collidepoint(event.pos):
484                            self.mouseDown = False
485                            button.clicked = False
486                            # Special case for empty input string
487                            if currentPage.inputStr != "" or button.dest == "page0":
488                                self.dest = button.dest
489                            else:
490                                currentPage.textList[4].text = "Please type a name"
491                self.lastClicked = None
492               
493            elif event.type == KEYDOWN:
494                key = pygame.key.name(event.key)
495                if len(key) == 1 or key == "space" or key == "backspace":
496                    caps = pygame.key.get_mods() & (KMOD_CAPS | KMOD_LSHIFT | KMOD_RSHIFT)
497                    currentPage.updateInput(key, caps)
498                elif key == "return":
499                    if currentPage.selectedButton != None:
500#                        globalVars.soundPlayer.playSound("click.mp3")
501                        button = currentPage.menuButtonList[currentPage.selectedButton]
502                        if currentPage.inputStr != "":
503                            self.dest = button.dest
504                            button.clicked = False
505                            self.mouseDown = False
506                            if self.lastClicked != None:
507                                self.lastClicked.active = False
508                        else:
509                            currentPage.textList[4].text = "Please type a name"
510                   
511    def manageTransition(self):
512        if self.transition.isInactive():
513            self.transition.setTransition(BubbleBackground(globalVars.screen, 0, 1))
514            self.transition.incrementTimer()
515            return False
516        elif not self.transition.isInactive() and self.transition.timer == 30:
517            self.transition.drawBackground()
518            if self.game == None and self.mode == BBUILDER.STORY:
519                self.game = Story(self.difficulty)
520            elif self.game == None and self.mode == BBUILDER.SURVIVAL:
521                self.game = Survival(self.difficulty)
522            self.game.draw()
523            self.transition.update(False)
524            self.transition.incrementTimer()
525            return False
526        elif not self.transition.isInactive() and self.transition.timer == 60:
527            self.transition.resetTimer()
528            self.transition.resetTransition()
529            pygame.event.clear()
530            return True
531        elif not self.transition.isInactive() and self.transition.timer != 60:
532            self.transition.drawBackground()
533            if self.game != None:
534                self.game.draw()
535            else:
536                globalVars.menuHandler.draw()
537            self.transition.update(False)   
538            self.transition.incrementTimer()
539            pygame.event.clear()
540            return False
541           
542    def manageScoresTransition(self):
543        if self.transition.isInactive():
544            self.transition.setTransition(BubbleBackground(globalVars.screen, 0, 1))
545            self.transition.incrementTimer()
546            return False
547        elif not self.transition.isInactive() and self.transition.timer == 30:
548            self.transition.drawBackground()
549            self.game.exit = True
550            self.game.draw()
551            self.transition.update(False)
552            self.transition.incrementTimer()
553            return False
554        elif not self.transition.isInactive() and self.transition.timer == 60:
555            self.transition.resetTimer()
556            self.transition.resetTransition()
557            pygame.event.clear()
558            return True
559        elif not self.transition.isInactive() and self.transition.timer != 60:
560            self.transition.drawBackground()
561            if self.transition.timer < 30:
562                self.game.draw()
563            else:
564                globalVars.menuHandler.draw()
565            self.transition.update(False)   
566            self.transition.incrementTimer()
567            pygame.event.clear()
568            return False
569       
570   
571    def exit(self):
572        """exit is called at the end to close stuff nicely"""
573        pygame.quit()
574        self.running = False
575       
Note: See TracBrowser for help on using the repository browser.