#!/usr/bin/python

import pygame, os, random, math
from pygame.locals import *

def load_image(name, colourkey=None):
	"""function to load images
		if colourkey is supplied will use that
		as transparent, otherwise will use
		top left colour
		unless -1 is passed, in which case no
		transparent colour will be used"""
	fullname = os.path.join('data', name)
	try:
		image = pygame.image.load(fullname)
	except pygame.error, message:
		print 'Cannot load image:', fullname
		raise SystemExit, message
	image = image.convert()
	if colourkey is None:
		colourkey = image.get_at((0,0))
	if colourkey is not -1:
		image.set_colorkey(colourkey)
	return image, image.get_rect()

def load_sound(name):
	class No_Sound:
		def play(self): pass
	if not pygame.mixer or not pygame.mixer.get_init():
		return No_Sound()
	fullname = os.path.join('data', name)
	if os.path.exists(fullname) == True:
		sound = pygame.mixer.Sound(fullname)
	else:
		print 'File does not exist:', fullname
		return No_Sound
	return sound

def draw_background():
	arena.fill(background_colour)
	for i in range(lines_per_side):
		startpos = (0, random.randint(5, 295))
		endpos = (random.randint(5, 295), 300)
		pygame.draw.line(arena, line_colour, startpos, endpos, 2)
	for i in range(lines_per_side):
		startpos = (300, random.randint(5, 295))
		endpos = (random.randint(5, 295), 300)
		pygame.draw.line(arena, line_colour, startpos, endpos, 2)
	for i in range(lines_per_side):
		startpos = (random.randint(5, 295), 0)
		endpos = (300, random.randint(5, 295))
		pygame.draw.line(arena, line_colour, startpos, endpos, 2)
	for i in range(lines_per_side):
		startpos = (0, random.randint(5, 295))
		endpos = (random.randint(5, 295), 0)
		pygame.draw.line(arena, line_colour, startpos, endpos, 2)
	screen.blit(arena, (50, 50))

def welcome_screen():
	#display welcome text on the screen
	draw_background()
	text = main_title_font.render('Welcome to pyBalloon', 1, welcome_text_colour)
	screen.blit(text, (73, 125))
	text = title_font.render("An entry in ludumdare.com's Oct 04", 1, welcome_text_colour)
	screen.blit(text, (65, 180))
	text = title_font.render('48hr game programming competition', 1, welcome_text_colour)
	screen.blit(text, (61, 200))
	text = status_font.render('Space to Start', 1, (0, 0, 0))
	screen.blit(text, (234, 52))
	text = status_font.render('esc or q to quit', 1, (0, 0, 0))
	screen.blit(text, (234, 62))
	text = status_font.render('use your arrow keys in the game', 1, (0, 0, 0))
	screen.blit(text, (198, 72))
	pygame.display.flip()
	while True:
		pygame.time.wait(250)
		for event in pygame.event.get():
			if event.type == QUIT:
				return (False, True)
			elif event.type == KEYDOWN:
				if event.key == K_ESCAPE or event.key == K_q:
					return (False, True)
				elif event.key == K_SPACE:
					return (True, False)

class Hand(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_image('hand.png')
		self.up = False
		self.down = False
		self.left = False
		self.right = False
		self.keyinc = 4
	
	def setup(self):
		self.up = False
		self.down = False
		self.left = False
		self.right = False
		self.rect.center = (150, 150)
	
	def update(self):
		if self.up and self.rect.top >= 1:
			self.rect.top -= self.keyinc
		if self.down and self.rect.bottom <= 298:
			self.rect.bottom += self.keyinc
		if self.left and self.rect.left >= 1:
			self.rect.left -= self.keyinc
		if self.right and self.rect.right <= 298:
			self.rect.right += self.keyinc
		

class Balloon(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_image('balloon.png')
		self.rect.top = 300
		self.rect.centerx = random.randint(20, 280)
		self.speed_up = 3
	
	def update(self):
		self.rect.bottom -= self.speed_up
		

class Pin(pygame.sprite.Sprite):
	def __init__(self, start_speed):
		pygame.sprite.Sprite.__init__(self)
		self.pin_image, self.rect = load_image('pin.png', -1)
		self.rect.center = (random.randint(20, 280), random.randint(20, 280))
		self.move_vertically = random.randint(-1 * start_speed, start_speed)
		self.move_horizontally = random.randint(-1 * start_speed, start_speed)
		self.angle = random.randint(1, 360)
		self.dangle = random.randint(-8, 8)
		self.image = pygame.transform.rotate(self.pin_image, self.angle)
		self.image.set_colorkey((255, 255, 255))
	
	def update(self):
		self.rect.centerx += self.move_horizontally
		self.rect.centery += self.move_vertically
		if self.rect.left < 1:
			self.move_horizontally *= -1
			self.rect.left = 0
		elif  self.rect.right > 298:
			self.move_horizontally *= -1
			self.rect.right = 299
		if self.rect.top < 1:
			self.move_vertically *= -1
			self.rect.top = 0
		elif self.rect.bottom > 298:
			self.move_vertically *= -1
			self.rect.bottom = 299
		self.angle += self.dangle
		if self.angle > 180:
			self.angle -= 360
		elif self.angle <= -180:
			self.angle += 360
		self.image = pygame.transform.rotate(self.pin_image, self.angle) # * math.pi) / 180)
		self.image.set_colorkey((255, 255, 255))

class Star(pygame.sprite.Sprite):
	def __init__(self, start_speed):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_image('star.png')
		self.rect.center = (random.randint(20, 280), random.randint(20, 280))
		self.move_vertically = random.randint(-1 * start_speed, start_speed)
		self.move_horizontally = random.randint(-1 * start_speed, start_speed)
	
	def update(self):
		self.rect.centerx += self.move_horizontally
		self.rect.centery += self.move_vertically
		if self.rect.left < 1:
			self.move_horizontally *= -1
			self.rect.left = 0
		elif  self.rect.right > 298:
			self.move_horizontally *= -1
			self.rect.right = 299
		if self.rect.top < 1:
			self.move_vertically *= -1
			self.rect.top = 0
		elif self.rect.bottom > 298:
			self.move_vertically *= -1
			self.rect.bottom = 299

def play_balloon():
	draw_background()
	background.blit(arena, (0, 0))
	hand.setup()
	caught = 0
	misses = 10
	speed = 1
	speed_count = 0
	balloon_frequency = 40
	pin_frequency = 180
	star_frequency = 600
	pin_start_speed = 5
	star_start_speed = 5
	while True:
		clock.tick(25)
		speed_count += 1
		if speed_count >= 250:
			speed += 1
			speed_count = 0
			if balloon_frequency > 26:
				balloon_frequency -= 7
			elif balloon_frequency > 15:
				balloon_frequency -= 6
			elif balloon_frequency > 9:
				balloon_frequency -= 4
			if pin_frequency > 61:
				pin_frequency -= 15
			if star_frequency > 150:
				star_frequency -= 60
			pin_start_speed += 1
			star_start_speed += 1
		for event in pygame.event.get():
			if event.type == QUIT:
				return True
			elif event.type == KEYDOWN:
				if event.key == K_ESCAPE:
					return False
				elif event.key == K_RIGHT:
					hand.right = True
					hand.left = False
				elif event.key == K_LEFT:
					hand.left = True
					hand.right = False
				elif event.key == K_UP:
					hand.up = True
					hand.down = False
				elif event.key == K_DOWN:
					hand.down = True
					hand.up = False
			elif event.type == KEYUP:
				if event.key == K_RIGHT:
					hand.right = False
				elif event.key == K_LEFT:
					hand.left = False
				elif event.key == K_UP:
					hand.up = False
				elif event.key == K_DOWN:
					hand.down = False
		hand_sprite.clear(arena, background)
		balloon_sprites.clear(arena, background)
		pin_sprites.clear(arena, background)
		star_sprites.clear(arena, background)
		
		hand_sprite.update()
		balloon_sprites.update()
		pin_sprites.update()
		star_sprites.update()
		
		for bln in balloon_sprites.sprites():
			if bln.rect.bottom < 0:	
				bln.kill()
				misses -= 1
		for pin in pin_sprites.sprites():
			for bln in pygame.sprite.spritecollide(pin, balloon_sprites, 0):
				if math.sqrt(math.pow((pin.rect.centerx - bln.rect.centerx), 2) + math.pow((pin.rect.centery - (15 * math.sin(pin.angle * math.pi / 180)) - bln.rect.centery), 2)) > math.pow((pin.rect.centerx - (15 * math.cos(pin.angle * math.pi / 180)) - bln.rect.centerx), 2):
					bln.kill()
					pop.play()
					misses -= 1
				else:
					pin.move_vertically *= -1
					pin.move_horizontally *= -1
		for hit in pygame.sprite.groupcollide(star_sprites, balloon_sprites, 0, 1):
			pop.play()
			misses -= 1
		
		#Randomly add balloons
		if random.randint(1, balloon_frequency) == 1:
			balloon_sprites.add(Balloon())
		#Randomly add pins
		if random.randint(1, pin_frequency) == 1 and len(pin_sprites.sprites()) < 10:
			pin_sprites.add(Pin(pin_start_speed))
		#Randomly add stars
		if random.randint(1, star_frequency) == 1 and len(star_sprites.sprites()) < 8:
			star_sprites.add(Star(star_start_speed))
		
		hand_sprite.draw(arena)
		balloon_sprites.draw(arena)
		pin_sprites.draw(arena)
		star_sprites.draw(arena)
		
		draw_current_stats(caught, misses, speed)
		screen.blit(arena, (50, 50))
		pygame.display.flip()
		
		if misses <= 0:
			return False
		
		#Check for collisions
		for hit in pygame.sprite.groupcollide(hand_sprite, balloon_sprites, 0, 1):
			caught += 1
			yippee.play()
		for hit in pygame.sprite.groupcollide(hand_sprite, pin_sprites, 0, 1):
			ouch.play()
		for hit in pygame.sprite.groupcollide(hand_sprite, star_sprites, 0, 1):
			ouch.play()
			

def draw_current_stats(caught, misses, speed):
	screen.fill((0, 0, 0), (0, 195, 49, 35))
	text = main_title_font.render(str(caught), 1, (248, 50, 237))
	screen.blit(text, (5, 196))
	screen.fill((0, 0, 0), (0, 113, 49, 35))
	text = main_title_font.render(str(misses), 1, (248, 50, 237))
	screen.blit(text, (15, 114))
	screen.fill((0, 0, 0), (0, 261, 49, 35))
	text = main_title_font.render(str(speed), 1, (248, 50, 237))
	screen.blit(text, (15, 262))

def draw_game_text():
	screen.fill((0, 0, 0))
	text = status_font.render('Misses', 1, (255, 255, 255))
	screen.blit(text, (3, 82))
	text = status_font.render('Left', 1, (255, 255, 255))
	screen.blit(text, (3, 98))
	text = status_font.render('Balloons', 1, (255, 255, 255))
	screen.blit(text, (3, 164))
	text = status_font.render('Caught', 1, (255, 255, 255))
	screen.blit(text, (3, 180))
	text = status_font.render('Speed', 1, (255, 255, 255))
	screen.blit(text, (3, 246))
	text = title_font.render('Catch', 1, (255, 255, 255))
	screen.blit(text, (5, 12))
	image, rect = load_image('balloon.png')
	screen.blit(image, (55, 7))
	text = title_font.render('s    before', 1, (255, 255, 255))
	screen.blit(text, (80, 12))
	image, rect = load_image('pin.png')
	screen.blit(image, (157, 12))
	text = title_font.render('s   and', 1, (255, 255, 255))
	screen.blit(text, (190, 12))
	image, rect = load_image('star.png')
	screen.blit(image, (252, 7))
	text = title_font.render('s   pop', 1, (255, 255, 255))
	screen.blit(text, (290, 12))
	text = title_font.render('them   and  before  they  leave  the  screen', 1, (255, 255, 255))
	screen.blit(text, (21, 30))

pygame.init()
screen = pygame.display.set_mode((355, 355))
pygame.display.set_caption('pyBalloon')
arena = pygame.Surface((300, 300))
background = pygame.Surface((300, 300))
main_title_font = pygame.font.Font(None, 36)
title_font = pygame.font.Font(None, 24)
status_font = pygame.font.Font(None, 14)
line_colour = (205, 205, 205)
background_colour = (221, 221, 221)
welcome_text_colour = (0, 0, 0)
lines_per_side = 12
clock = pygame.time.Clock()
hand = Hand()
hand_sprite = pygame.sprite.RenderClear(hand)
balloon_sprites = pygame.sprite.RenderClear()
pin_sprites = pygame.sprite.RenderClear()
star_sprites = pygame.sprite.RenderClear()
global pop
global yippee
global ouch
pop = load_sound('pop.wav')
yippee = load_sound('yippee.wav')
ouch = load_sound('ouch.wav')

draw_game_text()

game_on = False
quit = False

while not quit:
	game_on, quit = welcome_screen()
	if game_on == True:
		quit = play_balloon()
		for bln in balloon_sprites.sprites():
			bln.kill()
		for pin in pin_sprites.sprites():
			pin.kill()
		for star in star_sprites.sprites():
			star.kill()
