2014-08-30 15:28:07 +02:00
|
|
|
#!/usr/bin/env python3
|
2014-09-06 13:01:32 +02:00
|
|
|
# -*- coding: utf-8 -*- #
|
|
|
|
|
2014-08-30 15:28:07 +02:00
|
|
|
"""
|
|
|
|
Avocados and stuff
|
|
|
|
"""
|
|
|
|
|
2014-08-30 22:42:20 +02:00
|
|
|
import os, random, sys
|
2014-08-30 15:28:07 +02:00
|
|
|
import pygame
|
2014-08-31 10:06:22 +02:00
|
|
|
import avocado, crystal, pingenerator, itext
|
2014-08-30 15:28:07 +02:00
|
|
|
from pygame.locals import *
|
2014-08-30 16:28:56 +02:00
|
|
|
from support.colors import *
|
2014-08-30 15:52:27 +02:00
|
|
|
from interface import hud
|
2014-08-30 15:28:07 +02:00
|
|
|
|
2014-08-30 22:02:17 +02:00
|
|
|
|
2014-08-30 22:16:41 +02:00
|
|
|
class TheGame:
|
|
|
|
|
|
|
|
def __init__(self):
|
2014-08-31 00:15:36 +02:00
|
|
|
""" Initialize the game """
|
|
|
|
pygame.init()
|
|
|
|
pygame.display.set_caption('Pin Avo, the Cado!')
|
2014-08-31 10:06:22 +02:00
|
|
|
self.clock = pygame.time.Clock()
|
|
|
|
self.initializeScreen()
|
2014-08-31 01:15:03 +02:00
|
|
|
|
2014-08-30 23:57:31 +02:00
|
|
|
# initialize the game canvas
|
2014-08-31 10:06:22 +02:00
|
|
|
self.timeout = 30
|
|
|
|
self.level = 1
|
2014-09-02 09:39:30 +02:00
|
|
|
self.psychomode = 2
|
2014-08-31 10:06:22 +02:00
|
|
|
self.targetScore = 400
|
2014-08-31 10:29:04 +02:00
|
|
|
##############################
|
|
|
|
# Never set below 4, else we have a high
|
|
|
|
# probability of losing the game due to a missing color
|
|
|
|
# Alternatively, you could edit chooseRandomColor()
|
|
|
|
# to only work on the first multiplier colors
|
|
|
|
self.desired_fps = 60
|
2014-08-31 10:06:22 +02:00
|
|
|
self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
|
2014-08-31 12:04:45 +02:00
|
|
|
self.colors = [RED, GREEN, BLUE, YELLOW, PINK]
|
2014-08-31 12:46:07 +02:00
|
|
|
self.multiplier = len(self.colors)
|
2014-08-31 00:47:36 +02:00
|
|
|
self.bg = pygame.image.load(os.path.join('img', 'lawyerCrystalBall.png'))
|
2014-08-31 10:44:46 +02:00
|
|
|
self.bg.set_colorkey((255,255,255))
|
|
|
|
self.bg.set_alpha(75)
|
2014-08-31 11:49:02 +02:00
|
|
|
self.last_colors = []
|
2014-08-31 00:15:36 +02:00
|
|
|
|
|
|
|
# fonts
|
2014-08-31 00:47:36 +02:00
|
|
|
self.bigFont = pygame.font.Font(None, 90)
|
2014-08-31 00:15:36 +02:00
|
|
|
|
2014-08-31 02:36:21 +02:00
|
|
|
# Set splashscreen
|
2014-08-31 12:04:45 +02:00
|
|
|
splashScreen = pygame.image.load(os.path.join('img', 'splashScreen.png'))
|
2014-08-31 10:06:22 +02:00
|
|
|
self.screen.blit(
|
|
|
|
pygame.transform.scale(
|
|
|
|
splashScreen, (self.WIDTH, self.HEIGHT)
|
|
|
|
),
|
|
|
|
(0, 0)
|
|
|
|
)
|
|
|
|
|
2014-08-31 00:54:33 +02:00
|
|
|
pygame.display.flip()
|
|
|
|
pygame.time.wait(3000)
|
|
|
|
|
2014-08-30 23:03:14 +02:00
|
|
|
try:
|
|
|
|
pygame.mixer.init()
|
|
|
|
pygame.mixer.music.set_volume(0.5)
|
2014-08-31 00:15:36 +02:00
|
|
|
sound = True
|
2014-08-30 23:03:14 +02:00
|
|
|
except:
|
|
|
|
print("Y U NO sound? :(")
|
2014-08-31 00:15:36 +02:00
|
|
|
sound = False
|
2014-08-30 22:16:41 +02:00
|
|
|
|
|
|
|
|
2014-08-31 10:06:22 +02:00
|
|
|
def initializeScreen(self):
|
|
|
|
# displayInfo = pygame.display.Info()
|
|
|
|
# self.resize = 1.3
|
|
|
|
|
|
|
|
# self.WIDTH = int(displayInfo.current_w / self.resize)
|
|
|
|
# self.HEIGHT = int(displayInfo.current_h / self.resize)
|
|
|
|
|
|
|
|
# Look at the cleverness ;)
|
|
|
|
self.WIDTH, self.HEIGHT = 800, 600
|
|
|
|
|
|
|
|
|
2014-08-31 00:02:36 +02:00
|
|
|
def mute(self,mute=False, sound=True):
|
2014-08-30 22:59:38 +02:00
|
|
|
if not sound:
|
|
|
|
return
|
|
|
|
if mute:
|
|
|
|
pygame.mixer.music.set_volume(0.0)
|
|
|
|
else:
|
|
|
|
pygame.mixer.music.set_volume(0.5)
|
|
|
|
|
|
|
|
|
|
|
|
def playLevel(self,lvl=1,sound=True):
|
|
|
|
if not sound:
|
|
|
|
return
|
|
|
|
if lvl == 1:
|
|
|
|
pygame.mixer.music.load("""audio/level1.wav""")
|
|
|
|
elif lvl == 2:
|
|
|
|
pygame.mixer.music.load("""audio/level2.wav""")
|
2014-08-30 23:15:35 +02:00
|
|
|
elif lvl >= 3:
|
2014-08-30 22:59:38 +02:00
|
|
|
pygame.mixer.music.load("""audio/level3.wav""")
|
|
|
|
pygame.mixer.music.play()
|
|
|
|
|
2014-09-02 09:39:30 +02:00
|
|
|
def toggle_fullscreen(self):
|
|
|
|
global fullS
|
|
|
|
fullS = True
|
|
|
|
self.screen = pygame.display.get_surface()
|
|
|
|
self.tmp = self.screen.convert()
|
|
|
|
self.caption = pygame.display.get_caption()
|
|
|
|
self.cursor = pygame.mouse.get_cursor() # Duoas 16-04-2007
|
|
|
|
|
|
|
|
self.w,self.h = self.screen.get_width(),self.screen.get_height()
|
|
|
|
self.flags = self.screen.get_flags()
|
|
|
|
self.bits = self.screen.get_bitsize()
|
|
|
|
|
|
|
|
pygame.display.quit()
|
|
|
|
pygame.display.init()
|
|
|
|
|
|
|
|
self.screen = pygame.display.set_mode((self.w,self.h),self.flags^FULLSCREEN,self.bits)
|
|
|
|
self.screen.blit(self.tmp,(0,0))
|
|
|
|
pygame.display.set_caption(*self.caption)
|
|
|
|
|
|
|
|
pygame.key.set_mods(0) #HACK: work-a-round for a SDL bug??
|
|
|
|
|
|
|
|
pygame.mouse.set_cursor( *self.cursor ) # Duoas 16-04-2007
|
|
|
|
|
|
|
|
return self.screen
|
|
|
|
|
2014-08-30 22:59:38 +02:00
|
|
|
|
2014-08-31 01:07:12 +02:00
|
|
|
def fadeSound(self, sound=True):
|
2014-08-30 22:59:38 +02:00
|
|
|
if not sound:
|
|
|
|
return
|
|
|
|
pygame.mixer.music.fadeout(3000)
|
|
|
|
|
2014-08-31 12:08:00 +02:00
|
|
|
|
2014-08-31 01:07:12 +02:00
|
|
|
def chooseRandomColor(self):
|
2014-08-31 12:46:07 +02:00
|
|
|
selected = random.randint(0, len(self.colors) - 1)
|
2014-08-31 11:49:02 +02:00
|
|
|
if len(self.last_colors) > 5:
|
|
|
|
self.last_colors.pop(0)
|
|
|
|
for i in range(0, 5):
|
|
|
|
if selected in self.last_colors:
|
|
|
|
selected = random.randint(0, 3)
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
self.last_colors.append(selected)
|
2014-08-31 01:07:12 +02:00
|
|
|
return self.colors[selected]
|
2014-08-30 22:16:41 +02:00
|
|
|
|
2014-08-30 23:57:31 +02:00
|
|
|
def gameOver(self):
|
2014-08-31 10:25:37 +02:00
|
|
|
screen_width, screen_height = self.screen.get_size()
|
2014-08-31 12:04:45 +02:00
|
|
|
gameOverImage = pygame.image.load(os.path.join('img', 'gameOver.png'))
|
2014-08-31 12:46:07 +02:00
|
|
|
gameOverText = self.bigFont.render('GAME OVER', False, YELLOW)
|
2014-08-31 00:47:36 +02:00
|
|
|
gameOverImage.blit(gameOverText, (screen_width/8, screen_height/7))
|
2014-08-31 10:25:37 +02:00
|
|
|
self.screen.blit(pygame.transform.scale(gameOverImage,
|
|
|
|
self.screen.get_size()), (0, 0))
|
2014-08-30 23:27:24 +02:00
|
|
|
pygame.display.flip()
|
2014-08-31 01:07:12 +02:00
|
|
|
self.fadeSound()
|
2014-08-30 23:27:24 +02:00
|
|
|
pygame.time.wait(3000)
|
2014-08-30 23:57:31 +02:00
|
|
|
pygame.quit()
|
2014-08-31 00:15:36 +02:00
|
|
|
sys.exit()
|
2014-08-30 23:57:31 +02:00
|
|
|
|
2014-08-30 23:27:24 +02:00
|
|
|
|
2014-08-30 23:34:15 +02:00
|
|
|
def keepPinned(self, avocado):
|
|
|
|
self.pinned.append(avocado)
|
2014-08-30 22:16:41 +02:00
|
|
|
|
2014-08-30 23:57:31 +02:00
|
|
|
|
2014-08-31 00:47:36 +02:00
|
|
|
def drawBackground(self):
|
|
|
|
if type(self.bg) is tuple:
|
|
|
|
self.screen.fill(self.bg)
|
|
|
|
else:
|
2014-08-31 10:06:22 +02:00
|
|
|
self.screen.blit(
|
|
|
|
pygame.transform.scale(
|
|
|
|
self.bg, self.screen.get_size()
|
|
|
|
),
|
|
|
|
(0, 0)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def resetLevel(self):
|
|
|
|
self.pinnedAvocados = []
|
|
|
|
self.movingAvocados = []
|
|
|
|
self.thrownPins = []
|
|
|
|
self.timeleft = self.timeout
|
2014-08-31 00:47:36 +02:00
|
|
|
|
|
|
|
|
2014-08-30 22:16:41 +02:00
|
|
|
def main(self):
|
2014-08-31 01:07:12 +02:00
|
|
|
score = 0
|
2014-08-31 11:48:20 +02:00
|
|
|
boundaries = []
|
2014-08-31 03:39:02 +02:00
|
|
|
|
|
|
|
# We could use this list for redrawing only this part
|
2014-08-31 10:29:04 +02:00
|
|
|
# of the screen instead of all of it
|
2014-08-31 10:06:22 +02:00
|
|
|
self.resetLevel()
|
2014-08-30 22:16:41 +02:00
|
|
|
|
|
|
|
# initialize the HUD class and the lawyer
|
2014-08-30 23:57:31 +02:00
|
|
|
the_hud = hud.Hud(self.screen)
|
2014-08-31 12:46:07 +02:00
|
|
|
crystalBall = crystal.Crystal(self.screen, self.level, self.bigFont, self.psychomode)
|
2014-08-31 11:48:20 +02:00
|
|
|
boundaries.append(crystalBall.getBoundaries())
|
2014-08-30 22:16:41 +02:00
|
|
|
|
2014-08-31 00:15:36 +02:00
|
|
|
# Initial color indication
|
2014-08-30 22:16:41 +02:00
|
|
|
color = self.chooseRandomColor()
|
2014-08-31 01:38:26 +02:00
|
|
|
crystalBall.setColor(color)
|
2014-08-30 22:16:41 +02:00
|
|
|
|
2014-08-31 10:06:22 +02:00
|
|
|
texts = []
|
|
|
|
container = {'font': self.bigFont, 'screen': self.screen, 'clock': self.clock}
|
|
|
|
|
2014-08-30 22:33:10 +02:00
|
|
|
running = True
|
2014-08-31 00:15:36 +02:00
|
|
|
while running:
|
2014-08-31 10:29:04 +02:00
|
|
|
time_passed = self.clock.tick(self.desired_fps)
|
2014-08-31 10:06:22 +02:00
|
|
|
fps = self.clock.get_fps()
|
|
|
|
screen_width, screen_height = self.screen.get_size()
|
2014-08-30 22:48:49 +02:00
|
|
|
|
|
|
|
# Next level?
|
2014-08-31 10:06:22 +02:00
|
|
|
if score >= (self.targetScore * self.level):
|
|
|
|
self.level += 1
|
|
|
|
levelText = itext.Text(
|
|
|
|
container,
|
|
|
|
'Level ' + str(self.level),
|
|
|
|
(screen_width / 3, screen_height /2),
|
|
|
|
2000
|
|
|
|
)
|
|
|
|
texts.append(levelText)
|
|
|
|
self.playLevel(self.level)
|
|
|
|
self.resetLevel()
|
|
|
|
|
|
|
|
|
|
|
|
self.timeleft -= time_passed / 1000
|
|
|
|
self.timeleft = round(self.timeleft, 2)
|
|
|
|
if self.timeleft <= 0:
|
2014-08-30 23:57:31 +02:00
|
|
|
self.gameOver()
|
2014-08-30 22:16:41 +02:00
|
|
|
else:
|
2014-08-31 10:06:22 +02:00
|
|
|
displaytime = self.timeleft
|
|
|
|
|
|
|
|
|
2014-08-31 10:29:04 +02:00
|
|
|
# Redraw the background and put our lawyer back on top
|
|
|
|
self.drawBackground()
|
|
|
|
crystalBall.blitme()
|
|
|
|
|
2014-08-31 10:06:22 +02:00
|
|
|
# Check if there's any text that wants to get displayed
|
|
|
|
for text in texts:
|
|
|
|
text.blitme()
|
|
|
|
texts[:] = [text for text in texts if not text.hasExpired() ]
|
|
|
|
|
2014-08-30 22:16:41 +02:00
|
|
|
# Redraw the HUD
|
|
|
|
the_hud.draw_hud(score, displaytime, round(fps, 2))
|
|
|
|
|
2014-08-31 10:06:22 +02:00
|
|
|
# Initialize a number of avocados, depending on the level
|
|
|
|
avocadosInGame = len(self.movingAvocados)
|
2014-08-31 10:29:04 +02:00
|
|
|
avocadosWanted = self.level * self.multiplier
|
2014-08-31 10:06:22 +02:00
|
|
|
|
|
|
|
if avocadosInGame < avocadosWanted:
|
|
|
|
probability = int(1.0/(avocadosWanted - avocadosInGame) * 100)
|
|
|
|
if random.randint(0, probability) < 3:
|
2014-08-31 11:48:20 +02:00
|
|
|
properties = {'color': self.chooseRandomColor(), 'size': (50,50)}
|
2014-08-31 10:06:22 +02:00
|
|
|
# Spawn a new avocado
|
2014-08-31 10:29:04 +02:00
|
|
|
a = avocado.Avocado(
|
|
|
|
self.screen,
|
2014-08-31 11:48:20 +02:00
|
|
|
boundaries,
|
|
|
|
properties,
|
2014-08-31 10:29:04 +02:00
|
|
|
color,
|
|
|
|
self.level
|
|
|
|
)
|
2014-08-31 10:06:22 +02:00
|
|
|
self.movingAvocados.append(a)
|
|
|
|
|
|
|
|
# Remove avocados from the list of moving avocados if they no longer move
|
|
|
|
# Or add them to the list of pinned avocados if they're been hit
|
|
|
|
self.pinnedAvocados += [avo for avo in self.movingAvocados if avo.isPinned() ]
|
|
|
|
self.movingAvocados[:] = [ avo for avo in self.movingAvocados if avo.isFalling() ]
|
|
|
|
|
|
|
|
##############################
|
|
|
|
#
|
|
|
|
# Late-Night-Comments:
|
|
|
|
#
|
|
|
|
# Can we maybe handle the pinned avocados the same way I handle "stuck"
|
|
|
|
# pins? It seems to be easier.. well, the pins don't fall out of the screen
|
|
|
|
# though…
|
|
|
|
#
|
|
|
|
##############################
|
|
|
|
|
|
|
|
# Now redraw our avocados
|
|
|
|
for a in self.movingAvocados:
|
|
|
|
a.setTargetColor(color)
|
|
|
|
a.move()
|
|
|
|
a.blitme()
|
|
|
|
|
|
|
|
for a in self.pinnedAvocados:
|
|
|
|
a.blitme()
|
|
|
|
|
|
|
|
# And finally check if we need to redraw any pins
|
|
|
|
for activePin in self.thrownPins:
|
|
|
|
activePin.blitme()
|
|
|
|
if not activePin.isStuck():
|
|
|
|
activePin.moveTowardsTarget()
|
2014-08-31 03:39:02 +02:00
|
|
|
|
2014-08-30 22:16:41 +02:00
|
|
|
# Catch events
|
|
|
|
for event in pygame.event.get():
|
|
|
|
# Collision detection
|
|
|
|
if event.type == MOUSEBUTTONDOWN:
|
2014-08-31 01:07:12 +02:00
|
|
|
mousepos = pygame.mouse.get_pos()
|
2014-08-31 03:39:02 +02:00
|
|
|
|
2014-08-31 10:06:22 +02:00
|
|
|
# Throwing a new pin
|
2014-08-31 03:39:02 +02:00
|
|
|
newPin = pingenerator.Generate(self.screen)
|
|
|
|
newPin.throwAt(mousepos)
|
2014-08-31 10:06:22 +02:00
|
|
|
self.thrownPins.append(newPin)
|
2014-08-31 03:39:02 +02:00
|
|
|
|
|
|
|
# Check if any avocados have been hit
|
2014-08-31 10:25:37 +02:00
|
|
|
for avo in self.movingAvocados:
|
2014-08-31 10:15:28 +02:00
|
|
|
hit, center = avo.isHit(mousepos)
|
2014-08-31 10:45:06 +02:00
|
|
|
if hit is None:
|
|
|
|
continue
|
2014-08-30 22:16:41 +02:00
|
|
|
if hit:
|
|
|
|
score += 100
|
2014-08-31 10:15:28 +02:00
|
|
|
newPin.throwAt(center)
|
2014-08-30 22:33:10 +02:00
|
|
|
color = self.chooseRandomColor()
|
2014-08-31 01:03:39 +02:00
|
|
|
crystalBall.setColor(color)
|
2014-08-31 10:45:06 +02:00
|
|
|
else:
|
2014-08-30 22:16:41 +02:00
|
|
|
score -= 50
|
|
|
|
|
2014-08-31 10:44:46 +02:00
|
|
|
|
2014-08-30 22:16:41 +02:00
|
|
|
# Had enough of this?
|
|
|
|
if event.type == pygame.QUIT:
|
|
|
|
running = False
|
2014-08-31 01:32:07 +02:00
|
|
|
game.gameOver()
|
2014-08-30 22:42:20 +02:00
|
|
|
pygame.quit()
|
|
|
|
sys.exit()
|
2014-08-31 10:44:46 +02:00
|
|
|
elif event.type == pygame.KEYDOWN:
|
|
|
|
if pygame.key.get_pressed()[pygame.K_f] != 0:
|
|
|
|
print("Toggling full screen, in the Future")
|
2014-09-02 09:39:30 +02:00
|
|
|
#game.toggle_fullscreen()
|
2014-08-31 10:44:46 +02:00
|
|
|
elif (pygame.key.get_pressed()[pygame.K_q] != 0) or (pygame.key.get_pressed()[pygame.K_ESCAPE] != 0):
|
|
|
|
running = False
|
|
|
|
game.gameOver()
|
|
|
|
pygame.quit()
|
|
|
|
sys.exit()
|
2014-08-30 22:16:41 +02:00
|
|
|
|
2014-08-30 21:11:10 +02:00
|
|
|
pygame.display.flip()
|
2014-08-30 22:16:41 +02:00
|
|
|
|
|
|
|
|
2014-08-30 15:28:07 +02:00
|
|
|
if __name__ == '__main__':
|
2014-08-30 22:16:41 +02:00
|
|
|
game = TheGame()
|
2014-08-30 23:03:14 +02:00
|
|
|
game.playLevel()
|
2014-08-30 22:16:41 +02:00
|
|
|
game.main()
|