#!/usr/bin/python
__doc__ = '''A minimal structure for a real-time game featuring a saucer. 
Version 4 adds missiles which can be fired by the player saucer, as well as counters for scoring.'''

import pygame
import pygame.event
from pygame.locals import *

from random import randint

X, Y = 500, 500 # Controls the screen size
FPS = 30 # Controls the timing, one frame every FPS milliseconds
S = 20 # Controls the step size in pixels
F = 10 # Controls the frequency of enemies. One enemy appears every 1/F T time units

def rand_color():
	return randint(0,255),randint(0,255), randint(0,255)

class Saucer(object):
	'''Description of a saucer, characterized by position (x,y), radius r, and color (r,g,b)'''
	def __init__(self, size=None, color=None, pos=None):
		if not size : size=randint(10,40)
		if not color : color=rand_color()
		if not pos : pos=(randint(0,X),0)
		self.radius=size
		self.color=color
		self.pos=pos

	def collide(self, other):
		from math import sqrt
		x1, y1 = self.pos
		x2, y2 = other.pos
		dist=sqrt((x1-x2)**2+(y1-y2)**2)
		if dist<self.radius+other.radius :
			return True
		return False

class Missile(Saucer):
	'''Missile objects are similar to Saucers, but simpler'''
	def __init__(self, pos):
		self.radius=5
		self.pos=pos
		self.color=(250,100,100)
		

class GameBoard(object):
	'''Description of the game board and all the related functionalities'''
	def __init__(self, X,Y):
		self.X=X
		self.Y=Y
		pygame.init()
		# Display and other intializations
		self.srect=Rect(0,0,self.X, self.Y)
		self.screen=pygame.display.set_mode(self.srect.size,0)
		self.bg = pygame.Surface(self.srect.size)
		self.clock=pygame.time.Clock()
		pygame.display.set_caption('Saucers')
		pygame.key.set_repeat(FPS,FPS)
		# Game actors
		self.player=Saucer(30, (0,120,255), (self.X/2, self.Y/2))
		self.objects=[]
		self.missiles=[]
		# Score
		self.kills=0
		self.fired=0
		self.objs=0

	def blitAll(self):
		# Draw black screen
		self.screen.fill((0,0,0))
		for o in self.objects:
			pygame.draw.circle(self.screen, o.color, o.pos, o.radius)
		for o in self.missiles:
			pygame.draw.circle(self.screen, o.color, o.pos, o.radius)
		pygame.draw.circle(self.screen, self.player.color, self.player.pos, self.player.radius)
		pygame.display.update()

	def random_gen(self, freq=F):
		if randint(1,freq)==1:
			self.objs+=1
			self.objects.append(Saucer())

	def move_all(self):
		for o in self.objects :
			x, y = o.pos
			o.pos = x, y+S
		self.objects = [ o for o in self.objects if o.pos[1]<self.Y and o.pos[0]<self.X ]
		for o in self.missiles :
			x, y = o.pos
			o.pos = x, y-(3*S/2)
		self.missiles = [ o for o in self.missiles if o.pos[1]<self.Y and o.pos[0]<self.X and o.pos[1]>0 and o.pos[0]>0 ]

	def collision(self):
		for o in self.objects :
			if self.player.collide(o):
				print "Collision!!"
				for r in range(0,255,10):
					pygame.draw.circle(self.screen, (r,0,0), self.player.pos, r)
					self.clock.tick(FPS)
					pygame.display.update()
				self.quit()

	def object_collision(self):
		self.objects = [ o for o in self.objects if not sum([ o.collide(p) for p in self.missiles]) ]
		self.kills += len([ o for o in self.objects if sum([ o.collide(p) for p in self.missiles]) ])

	def quit(self):
				print 'Enemies', self.objs
				print 'Kills', self.kills
				print 'Fired', self.fired
				exit(1)

	def constrain_pos(self):
		'''limit position to 0-X, 0-Y'''
		x, y = self.player.pos
		x = self.X if x > self.X else x
		x = 0 if x < 0 else x
		y = self.Y if y>self.Y else y
		y = 0 if y < 0 else y
		self.player.pos = x, y
		
	def run(self):
		while True :
			self.random_gen()
			for e in pygame.event.get():
				print e
				if e.type==QUIT : self.quit()
				if e.type==KEYDOWN :
					cmd=pygame.key.get_pressed()
					x, y = self.player.pos
					if cmd[K_q] : self.quit()
					if cmd[K_SPACE] or cmd[K_f] : 
						self.fired+=1
						self.missiles.append(Missile(self.player.pos))
					if cmd[K_a] or cmd[K_LEFT] : self.player.pos = x-S, y
					if cmd[K_d] or cmd[K_RIGHT] : self.player.pos = x+S, y
					if cmd[K_s] or cmd[K_DOWN] : self.player.pos = x, y+S
					if cmd[K_w] or cmd[K_UP] : self.player.pos = x, y-S
					self.constrain_pos()
			self.blitAll()
			self.object_collision()
			self.collision()
			self.clock.tick(FPS)
			self.move_all()

if __name__ == "__main__" :
	game=GameBoard(X,Y)
	game.run()
