import sys, pygame, math, random
from pygame.locals import *
pygame.init()

size = width, height = 256*2*2,256*2
white = 255, 255, 255
black = 0, 0, 0
CHARGETIME = 500

clock = pygame.time.Clock()

fullscreen = True

screen = pygame.display.set_mode(size, pygame.FULLSCREEN)

def double_size(image):
	image_object = pygame.image.load(image).convert_alpha()
	rect = image_object.get_rect()
	return pygame.transform.scale(image_object, (rect.width*2, rect.height*2))

witch = double_size("witch.png")
bugimg = double_size("fairywait.png")
bugimg2 = double_size("fairyhappy.png")
batimg = double_size("bat.png")
envelope = double_size("envelope.png")
note = double_size("note.png")
note2 = double_size("note2.png")
note3 = double_size("note3.png")
scroll = pygame.Rect((1600-800,1200-600),size)
background = double_size("bg.png")

text = pygame.font.Font("04B_25__.TTF", 24)

bg_filter = pygame.Surface(size, SRCALPHA)
bg_filtered = pygame.Surface(size)
scrollx = 0
intro = 0
channels = [ pygame.mixer.Channel(0), pygame.mixer.Channel(1), pygame.mixer.Channel(2), pygame.mixer.Channel(3), pygame.mixer.Channel(4) ]
empty = pygame.mixer.Sound("empty.wav")
for i in channels:
	i.play(pygame.mixer.Sound("music" + str(channels.index(i)) + ".wav"))
	i.set_volume(0)

class unit:
	def __init__(self):
		self.health = 10
		self.currentframe = 0
		
		if not self.totalframes:
			self.totalframes = 1
		
		if not self.rect:
			self.rect = pygame.Rect((0,0),(100,100))
		
		self.frameheight = self.image.get_rect().height / self.totalframes
	
	def move(self, a, b):
		self.rect = self.rect.move(a,b)
	
	def frame(self):
		return pygame.Rect((0,self.frameheight*math.floor(self.currentframe)),(self.rect.width,self.frameheight))
	
	def hitbox(self):
		return self.rect

class bullet:
	def __init__(self, owner):
		self.origin = owner.rect.center
		self.rect = pygame.Rect(self.origin,(16,16))
		self.speed = 10
		self.vector = self.speed, 0
	
	def move(self):
		self.rect = self.rect.move(self.vector)
	
	def draw(self):
		screen.blit(envelope, self.rect)

class player(unit):
	def __init__(self):
		self.image = witch
		self.rect = self.image.get_rect()
		self.rect.height = self.rect.height / 2
		self.rect.center = (20, size[1]/2)
		self.totalframes = 2
		self.charge = 0
		unit.__init__(self)
	
	def hitbox(self):
		newhitbox = pygame.Rect((0,0),(20,20))
		newhitbox.center = self.rect.center
		return newhitbox
	
	def move(self, a, b):
		self.rect = self.rect.move(a,b)
		if self.rect.left < 0:
			self.rect.left = 0
		if self.rect.top < 0:
			self.rect.top = 0
		if self.rect.bottom > size[1]-60:
			self.rect.bottom = size[1]-60

class bug(unit):
	def __init__(self):
		self.image = bugimg
		self.rect = self.image.get_rect()
		self.totalframes = 2
		unit.__init__(self)
		self.rect.height = self.frameheight
		self.rect.center = (size[0], 20)

class bat(unit):
	def __init__(self):
		self.image = batimg
		self.rect = self.image.get_rect()
		self.totalframes = 2
		unit.__init__(self)
		self.rect.height = self.frameheight
		self.rect.center = (size[0], 20)

def distance(a, b):
	return math.sqrt(math.pow(a[0]-b[0],2)+math.pow(a[1]-b[1],2))

def getinput():
	global intro, clock
	beat = False
	
	for event in pygame.event.get():
		if event.type is QUIT: 
			sys.exit()
		if event.type is KEYDOWN and intro is 0:
			intro = 1
			return

	keystate = pygame.key.get_pressed()
	deltax = deltay = 0
	
	if keystate[K_LEFT]:
		deltax = -5
	if keystate[K_RIGHT]:
		deltax = 5
	if keystate[K_UP]:
		deltay = -5
	if keystate[K_DOWN]:
		deltay = 5
	hero.move(deltax, deltay)
	
	if keystate[K_z]:
		hero.charge += clock.get_time()
	elif hero.charge > CHARGETIME:
		heroshots.append(bullet(hero))
		hero.charge = 0
		
		if intro is 1:
			intro = 2
	else:
		hero.charge = 0
	
	if keystate[K_ESCAPE]:
		sys.exit()
	if keystate[K_RETURN] and (keystate[K_LALT] or keystate[K_RALT]):
		global fullscreen
		if not fullscreen:
			screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
			fullscreen = True
		else:
			screen = pygame.display.set_mode(size)
			fullscreen = None
	
# Initialization
hero = player()
fairy_list = [ ]
bat_list = [ ]
heroshots = [ ]
fairy_cooldown = bat_cooldown = 0
fill = 0
old_fill = -1
points = 0
countdown = 50

while 1:
	clock.tick(60)
	
	if points < 0:
		points = 0
	
	if fairy_cooldown:
		fairy_cooldown -= 1
	else:
		for i in range(6+points/10):
			if random.randint(0,10) < 3:
				newenemy = bug()
				newenemy.rect = newenemy.rect.move(random.randint(20,100)*2,min(i*((size[1]-80)/2/(6+points/10))+random.randint(0,25),230)*2)
				fairy_list.append(newenemy)
				fairy_cooldown = random.randint(80,200)
	
	if bat_cooldown:
		bat_cooldown -= 1
		if bat_cooldown < 0 and points < 40:
			bat_cooldown = 0
	elif len(bat_list) < 70:
		for i in range(points):
			if random.randint(0,10) < 3:
				newenemy = bat()
				newenemy.rect = newenemy.rect.move(random.randint(0,200)*2,min(i*((size[1])/points)+random.randint(0,25),230)*2)
				bat_list.append(newenemy)
				if points < 45:
					bat_cooldown = 45
				else:
					bat_cooldown = -1
	
	if hero.health < 0:
		sys.exit()
	
	for i in channels:
		if not i.get_queue():
			i.queue(pygame.mixer.Sound("music" + str(channels.index(i)) + "l.wav"))
		i.set_volume(min(0.5, max(points-((channels.index(i)-1)*10.0),0)/50))
	
	getinput()
	
	if scrollx < size[0]:
		scrollx += 1
	else:
		scrollx = 0
	screen.blit(background, (-scrollx,0))
	screen.blit(background, (-scrollx+size[0],0))
	
	if fill < points*5:
		fill = points*5
	if fill >= 255:
		countdown -= 1
		fill = 255
		bat_cooldown = 1
		
	if fill is not old_fill:
		bg_filter.fill((0,0,0,fill), None)
		bg_filtered.blit(background, (0,0))
		bg_filtered.blit(bg_filter, (0,0))
		
		old_fill = fill
	screen.blit(bg_filtered, (-scrollx,0))
	screen.blit(bg_filtered, (-scrollx+size[0],0))
	
	if hero.charge > CHARGETIME:
		screen.blit(text.render("!", True, white), (hero.rect.right, hero.rect.top))
	
	if hero.currentframe < hero.totalframes-0.1 and points:
		hero.currentframe += clock.get_time()/(CHARGETIME*1.0)
	else:
		hero.currentframe = 0
	
	for i in fairy_list:
		if i.currentframe < i.totalframes-0.1:
			i.currentframe += 0.1
		else:
			i.currentframe = 0
		screen.blit(i.image, i.rect, i.frame())
		
		if i.health <= 0:
			i.move(-1,-4)
		else:
			i.move(-1,0)
		
		if i.rect.center[0] < -100:
			fairy_list.remove(i)
		
	for i in bat_list:
		if i.currentframe < i.totalframes-0.1:
			i.currentframe += 0.1
		else:
			i.currentframe = 0
		screen.blit(i.image, i.rect, i.frame())
		
		i.move(-random.randint(4,6),0)
		
		if i.hitbox().colliderect(hero.hitbox()):
			points -= 5
			
			bat_list.remove(i)
		
		if i.rect.center[0] < -100:
			bat_list.remove(i)
	
	if intro is 0:
		screen.blit(text.render("My name is Melody. I'm the letter carrier for the fairies! :)", True, white, black), (20,size[1]-50))
	elif intro < 50:
		if intro > 1:
			intro += 1
		screen.blit(text.render("By holding Z, I can get a letter ready... and release it to throw!", True, white, black), (20,size[1]-50))
	elif intro < 800:
		screen.blit(text.render("I absolutely hate bats! x_x If they get tangled in my hair, I lose my rhythm!", True, white, black), (20,size[1]-50))
		intro += 1
	elif intro < 1000:
		screen.blit(text.render("I've got a busy night ahead of me! ;)", True, white, black), (20,size[1]-50))
		intro += 1
	
	for i in heroshots:
		i.move()
		i.draw()
		
		for j in fairy_list:
			if i.rect.colliderect(j.hitbox()):
				if j.health:
					j.health = 0
					j.image = bugimg2
					heroshots.remove(i)
					points += 1
					break
				else:
					i.vector = (0, i.speed)
					break
		
		if not i.rect.colliderect(screen.get_rect()) and i in heroshots:
			heroshots.remove(i)
		
	screen.blit(hero.image, hero.rect, hero.frame())
	for i in range(points):
		if i <= 10:
			screen.blit(note, ((23*4)*i+23*0, 10+1))
		elif i <= 21:
			screen.blit(note2, ((23*4)*(i-11)+23*1, 10-2))
		elif i <= 32:
			screen.blit(note3, ((23*4)*(i-22)+23*2, 10))
		elif i <= 43:
			screen.blit(note, ((23*4)*(i-33)+23*3, 10+3))
	
	seconds = pygame.time.get_ticks()/1000
	faded = False
	while countdown is 0:
		if not faded:
			for i in channels:
				i.queue(empty)
				i.fadeout(3000)
			faded = True
	
		s = seconds - int(math.floor(seconds/60))*60
		if s < 10:
			s = "0" + str(s)
		else:
			s = str(s)
		screen.fill(black, None)
		screen.blit(text.render("Time: " + str(int(math.floor(seconds/60))) + ":" + s, True, white), (size[0]/2-50, size[1]/2))
		getinput()
		pygame.display.flip()
	
	pygame.display.flip()