#!/usr/bin/env python  
# -*- coding: utf-8 -*-

#====================================================
# redoct.py - Juego de submarinos con  Python/Pygame
#----------------------------------------------------
# FJA - neocipres@gmail.com	    Julio de 2009
#====================================================

import sys
import os
import random
import time
import pygame
from pygame.locals import *

__uso__ = '''
    Ayuda:
        ====================================================================
        redoct.py - Un script Python para trabajar con la biblioteca Pygame.
        --------------------------------------------------------------------
        Uso: redoct [opcion]
        --------------------------------------------------------------------
        - Opciones -    
        
        -h              Mostrar ayuda
        
        - Teclas de control -
        
        a               Aumenta la potencia de los motores
        d               Disminuye la potencia de los motores
        s               Detiene las máquinas
        t, space        Dispara torpedos
        m               Dispara misiles 
        1               Lanza contramedidas de popa
        2               Lanza contramedidas de proa
        ================================================================


'''

XMAX  = 800
YMAX = 600  
DIRD = '/home/paco/prgdgnu/python/pygame/redoct/datos'
TIPO = ['b01.png',  'b02.png',  'b03.png',  'b04.png',  'b05.png',  'b06.png',  'b07.png',  'b08.png']

def cargaImagen(nombre, useColorKey = False):
    
    nomf = os.path.join(DIRD, nombre)
      
    try:
        imagen = pygame.image.load(nomf)
    except pygame.error, message:
        print "\n\tNo se puede cargar la imagen:", nomf
        raise SystemExit, message

    # To speed things up, convert the images to SDL's internal format.
    imagen = imagen.convert()

    if useColorKey is True:
        # Use the color of the pixel located at (0,0) as our colorkey
        colorkey = imagen.get_at((0,0))
        imagen.set_colorkey(colorkey, RLEACCEL)

    return imagen

def cargaSonido(nombre):

    class NoneSound:
        def play(self): pass

    if not pygame.mixer or not pygame.mixer.get_init():
        return NoneSound()

    nomf = os.path.join(DIRD, nombre)

    try:
        sonido = pygame.mixer.Sound(nomf)
        sonido.set_volume(0.5)
    except pygame.error, mensaje:
        print "No puedo cargar el fichero de sonido:", nomf
        raise SystemExit, mensaje

    return sonido
    
def asignaBuques(buqueSprites):
    buque = Buque(random.choice(TIPO))
    buqueSprites.add(buque)
    
    return buqueSprites
    
class ORed(pygame.sprite.Sprite):

    def __init__(self):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("sub.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (XMAX/2,YMAX-50)
        self.vx = 0
        self.vy = 0
        
    def update(self):
        self.rect.move_ip((self.vx, self.vy))
        
        if self.rect.right< 0:
            self.rect.right = XMAX
        elif self.rect.left > XMAX:
            self.rect.right = 0

        if self.rect.bottom <= (YMAX/2):
            self.rect.bottom = YMAX/2 
               
        elif self.rect.bottom >= YMAX:
            self.rect.bottom = YMAX
            
            
class Torpedo(pygame.sprite.Sprite):
    
    def __init__(self, x0,  y0):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("torpedo.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)

    def update(self):
        if self.rect.bottom <= YMAX/2 + 20:
            self.kill()
        else:
            self.rect.move_ip((0, -3))
            
class Misil(pygame.sprite.Sprite):
    
    def __init__(self, x0,  y0):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("misil.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)

    def update(self):
        if self.rect.bottom < 0:
            self.kill()
        else:
            self.rect.move_ip((0, -5))         
            
class CargaP(pygame.sprite.Sprite):
    
    def __init__(self, x0,  y0,  vc):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("cargap.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)
        self.vc = vc

    def update(self):
        if self.rect.bottom > YMAX - 10:
            self.kill()
        else:
            self.rect.move_ip((0, self.vc))
            
class Contramedida(pygame.sprite.Sprite):
    
    def __init__(self, x0,  y0):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("contramedida.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)
        self.t0 = time.time()
        
    def update(self):
        if int(time.time() - self.t0) > 3: 
            self.kill()
         
class MisilVA(pygame.sprite.Sprite):
    
    def __init__(self, x0,  y0, vc):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("misilva.png", True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)
        self.vc = vc
    def update(self):
        if self.rect.bottom > YMAX - 10:
            self.kill()
        else:
            self.rect.move_ip((0, self.vc))     
            
class MisilHA(pygame.sprite.Sprite):
    
    def __init__(self, tipo, x0,  y0, vc):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen(tipo, True)
        self.rect = self.image.get_rect()
        self.rect.center = (x0, y0)
        self.vc = vc
    def update(self):
        if self.rect.right < 0 and self.vc < 0:
            self.kill()
        elif self.rect.left > XMAX and self.vc > 0:
            self.kill()
        else:
            self.rect.move_ip((self.vc,  0))
            
class Mina(pygame.sprite.Sprite):
    
    def __init__(self):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("mina.png", True)
        self.rect = self.image.get_rect()
        x0 = random.randrange(30, XMAX - 30)
        y0 = random.randrange(YMAX/2 + 150, YMAX -  30)
        self.rect.center = (x0, y0)
        
        
        
class Buque(pygame.sprite.Sprite):
    
    def __init__(self,  tipo):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen(tipo, True)
        self.rect = self.image.get_rect()
        self.nomb = tipo
        if tipo in TIPO[5:]:
            s = -1
            x0 = XMAX
        else:
            s = 1
            x0 = 0
        self.sentido = s
        self.rect.center = (x0,YMAX/2 - 30)
        if tipo in TIPO[2:]:
            bc = 1
        else: 
            bc = 0
        self.combate = bc
        
    def update(self):
        self.rect.move_ip((2*self.sentido, 0))          
         
        if self.rect.right< 0:
            self.rect.left = XMAX
        elif self.rect.left > XMAX:
            self.rect.right = 0

class Explosion(pygame.sprite.Sprite):
    
    def __init__(self, nombre, pos):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen(nombre, True)
        self.rect = self.image.get_rect()
        self.rect.center = pos
            
    def update(self):
        self.kill()
         
         
class Avion(pygame.sprite.Sprite):
    
    def __init__(self):
        # Intialize Sprite, which is our base class
        pygame.sprite.Sprite.__init__(self)
        self.image = cargaImagen("avion.png", True)
        self.rect = self.image.get_rect()
        x0 = XMAX + 80
        y0 = random.randrange(50, YMAX/2 -  60)
        self.rect.center = (x0, y0)

    def update(self):
        if self.rect.right < 0:
            self.kill()
        else:
            self.rect.move_ip((-3, 0))
                 
def main():
    try:
        random.seed()
        pygame.mixer.pre_init(44100,-16, 2, 1024)
        pygame.mixer.init()
        pygame.init()
        pygame.font.init()
        fuente = pygame.font.Font(None, 25)
        screen = pygame.display.set_mode((XMAX, YMAX))
        pygame.display.set_caption(' Octubre Rojo ')
        
        imagen_fondo = cargaImagen("fondo.png")
        fondo_rect = imagen_fondo.get_rect()
        screen.blit(imagen_fondo, (0,0))
        
        # Se crean los contenedores de los Sprites
        subSprite = pygame.sprite.RenderClear()
        sub = ORed()
        subSprite.add(sub)
        subTorpedoSprites = pygame.sprite.RenderClear()
        buqueSprites = pygame.sprite.RenderClear()
        buqueSprites = asignaBuques(buqueSprites)
        explosionSprites = pygame.sprite.RenderClear()
        cargaPSprites = pygame.sprite.RenderClear()
        minaSprites = pygame.sprite.RenderClear()
        avionSprites = pygame.sprite.RenderClear()
        misilVASprites = pygame.sprite.RenderClear()
        misilHASprites = pygame.sprite.RenderClear()
        subMisilSprites = pygame.sprite.RenderClear()
        contramedidaSprites = pygame.sprite.RenderClear()
        
        # Carga los sonidos
        torpedoFX = cargaSonido('torpedo.wav')
        explosion1FX = cargaSonido('explo01.wav')
        explosion2FX = cargaSonido('explo02.wav')
        sosFX = cargaSonido('sos.wav')
        cargapFX = cargaSonido('cargap.wav')
        subFX = cargaSonido('sub.wav')
        
        run = True    
        vx = 0
        vy = 0
        m = 6
        fin = False
        activo = True
        clock = pygame.time.Clock()
        t0 = time.time()
        puntos = 0
        estado = 100
        rango = range(30,  1000,  50)
        vcargas = 1
        torpedos = 100
        misiles = 100
        contramedidas = 50
        
        while run:
            clock.tick(3*m)
            t = int(time.time() - t0)
            eventos = pygame.event.get( )
            for e in eventos:
                if (e.type == QUIT):
                    run = False
                    break
                
                elif e.type == KEYDOWN:
                    if e.key == K_ESCAPE or e.key == K_F10:
                        run = False
                        break
                    elif e.key == K_LEFT:
                        vx = - 1
                    elif e.key == K_RIGHT:
                        vx = 1
                    elif e.key == K_UP:
                        vy = - 1
                    elif e.key == K_DOWN:
                        vy = 1
                    elif e.key == K_a:
                        if  m < 10: m = m + 1 
                    elif e.key == K_d:
                        if m > 1 : m = m - 1 
                    elif e.key == K_s:
                        vx = 0
                        vy = 0
                        subFX.play()
                    elif e.key == K_t or e.key == K_SPACE:
                        if torpedos > 0:
                            subTorpedoSprites.add(Torpedo(sub.rect.left+100, sub.rect.top))
                            torpedoFX.play()
                            torpedos -= 1
                    elif e.key == K_m:
                        if misiles > 0:
                            subMisilSprites.add(Misil(sub.rect.left + 25, sub.rect.top))
                            torpedoFX.play()
                            misiles -= 1
                    elif e.key == K_1:
                        if contramedidas > 0:
                            contramedidaSprites.add(Contramedida(sub.rect.centerx - 80,  sub.rect.centery + 7))
                            contramedidas -= 1
                    elif e.key == K_2:
                        if contramedidas > 0:
                            contramedidaSprites.add(Contramedida(sub.rect.centerx + 90,  sub.rect.centery + 7))
                            contramedidas -= 1
                    elif e.key == K_f :
                        pygame.display.toggle_fullscreen()
                            
            if m > 9: m = 9
            if m < 1: m = 1
            if m > 3 and vx == -1: m = 3 
             
            if activo:
                sub.vx = vx
                sub.vy = vy
                
            # Actualiza todos los Sprites
            subSprite.update()
            subTorpedoSprites.update()
            buqueSprites.update()
            explosionSprites.update()
            cargaPSprites.update()
            avionSprites.update()
            misilVASprites.update()
            misilHASprites.update()
            subMisilSprites.update()
            contramedidaSprites.update()
            
            # Detecta las colisiones entre Sprites: buques - torpedo
            for colision in pygame.sprite.groupcollide(buqueSprites, subTorpedoSprites, 1, 1):
                explosionSprites.add(Explosion('explo02.png',  colision.rect.center))
                explosion2FX.play()
                puntos += 10
                if len(buqueSprites) < 5: buqueSprites = asignaBuques(buqueSprites)
            
            # Detecta las colisiones entre Sprites: avión - misil
            for colision in pygame.sprite.groupcollide(avionSprites, subMisilSprites, 1, 1):
                explosionSprites.add(Explosion('explo01.png',  colision.rect.center))
                explosion1FX.play()
                puntos += 30
                
            # Lanzamiento de cargas de profundidad
            for b in buqueSprites.sprites():
                if b.combate == 1 and  abs(sub.rect.centerx - b.rect.centerx ) == sub.rect.width -  30:
                    #sub.rect.centerx in [b.rect.centerx  -  30, b.rect.centerx + 30] :
                    cargapFX.play()
                    if b.sentido == -1:
                        cargaPSprites.add(CargaP(b.rect.right + 5, b.rect.top + 10,  vcargas))
                        if b.nomb in ['b03.png',  'b06.png']: cargaPSprites.add(CargaP(b.rect.left - 5, b.rect.top + 10,  vcargas))
                    
                    if b.sentido == 1: 
                        cargaPSprites.add(CargaP(b.rect.left - 5, b.rect.top + 10,  vcargas))
                        if b.nomb in ['b03.png',  'b06.png']: cargaPSprites.add(CargaP(b.rect.right + 5, b.rect.top + 10,  vcargas))
                    
                    
            # Lanzamiento de las cargas de profundidad  por el avión
            for a in avionSprites.sprites():
                if  n == 103 : misilVASprites.add(MisilVA(a.rect.centerx, a.rect.bottom +15,  vcargas + 1))
                    
            # Explosión de las cargas de profundidad
            for c in cargaPSprites.sprites():
                if c.rect.centery in [sub.rect.centery - 5, sub.rect.centery + 5]:
                    explosionSprites.add(Explosion('explo01.png',  c.rect.center))
                    c.kill()
                    explosion1FX.play()
                    if abs(c.rect.centerx - sub.rect.centerx) < 100: estado -= 20
                    elif abs(c.rect.centerx - sub.rect.centerx) < 150: estado -= 10
                        
            # Localización y seguimiento de las cargas de profundidad del avión al submarino
            for misil in misilVASprites.sprites():
                if misil.rect.centery in [sub.rect.centery - 5, sub.rect.centery + 5]:
                    x = misil.rect.centerx
                    y = misil.rect.centery
                    misil.kill()
                    if x > sub.rect.centerx:
                        misilHASprites.add(MisilHA('misilhi.png',  x,  y + 7, -(vcargas + 2)))
                    else: misilHASprites.add(MisilHA('misilhd.png',  x,  y + 7, vcargas + 2))
                
            # Detecta las colisiones entre Sprites: submarino - cargas
            for colision in pygame.sprite.groupcollide(cargaPSprites, subSprite, 1, 1):
                explosionSprites.add(Explosion('explo02.png',  colision.rect.center))
                explosion2FX.play()
                fin = True
                tf = time.time()
            
            # Detecta las colisiones entre Sprites: submarino - minas
            for colision in pygame.sprite.groupcollide(minaSprites, subSprite, 1, 1):
                explosionSprites.add(Explosion('explo02.png',  colision.rect.center))
                explosion2FX.play()
                fin = True
                tf = time.time()
             
            # Detecta las colisiones entre Sprites: submarino - misilha
            for colision in pygame.sprite.groupcollide(misilHASprites, subSprite, 1, 1):
                explosionSprites.add(Explosion('explo02.png',  colision.rect.center))
                explosion2FX.play()
                fin = True
                tf = time.time()   
            
            # Detecta las colisiones entre Sprites: cargas - minas
            for colision in pygame.sprite.groupcollide(minaSprites, cargaPSprites, 1, 1):
                explosionSprites.add(Explosion('explo01.png',  colision.rect.center))
                explosion1FX.play()
                
            # Detecta las colisiones entre Sprites: contramedidas - misilha
            for colision in pygame.sprite.groupcollide(misilHASprites, contramedidaSprites, 1, 1):
                explosionSprites.add(Explosion('explo01.png',  colision.rect.center))
                explosion1FX.play()   
            
            # Limpia la pantalla y dibuja de nuevo 
            subSprite.clear(screen, imagen_fondo)
            subSprite.draw(screen)
            subTorpedoSprites.clear(screen, imagen_fondo)
            subTorpedoSprites.draw(screen)
            buqueSprites.clear(screen, imagen_fondo)
            buqueSprites.draw(screen)
            explosionSprites.clear(screen, imagen_fondo)
            explosionSprites.draw(screen)
            cargaPSprites.clear(screen, imagen_fondo)
            cargaPSprites.draw(screen)
            minaSprites.clear(screen, imagen_fondo)
            minaSprites.draw(screen)
            avionSprites.clear(screen, imagen_fondo)
            avionSprites.draw(screen)
            misilVASprites.clear(screen, imagen_fondo)
            misilVASprites.draw(screen)
            misilHASprites.clear(screen, imagen_fondo)
            misilHASprites.draw(screen)
            subMisilSprites.clear(screen, imagen_fondo)
            subMisilSprites.draw(screen)
            contramedidaSprites.clear(screen, imagen_fondo)
            contramedidaSprites.draw(screen)
            
            # Nivel de dificultad
            n = random.randrange(0,  299)
            if n == 101: avionSprites.add(Avion())
            if puntos in rango:
                buqueSprites = asignaBuques(buqueSprites)
                for i in range(puntos/100): minaSprites.add(Mina())
                rango = rango[1:]
            if puntos > 300: vcargas = 2
            elif puntos > 700: vcargas = 3 
            
                
            # Información en pantalla 
            datos1 =  ' P = ' + str(m) + '   Vx = ' + str(sub.vx) + '   Vy = ' + str(sub.vy)  + '  tiempo:  ' + str(t) 
            datos2 =  '  Puntos: ' + str(puntos)  + '   E: ' + str(estado) + '   h = ' + str(sub.rect.bottom - 300)  
            datos3 =  '  T = ' + str(torpedos) + '  M = ' + str(misiles) + '  C = ' + str(contramedidas) +'   '
            texto = fuente.render(datos1 + '  ' + datos2 + '  ' + datos3, 1, (255, 0, 255),  (0, 0, 255))
            screen.blit(texto, (3, 3))
            if estado < 0: 
                sub.vx = 0
                sub.vy = 3
                if (t % 30) == 0: sosFX.play()
                activo = False
                
            if fin:
                texto = fuente.render(' - Octubre Rojo cazado ... Game Over !!! - ', 1, (255, 0, 0),  (233, 233, 233))
                screen.blit(texto, (XMAX/2 - 180, YMAX/2 - 100))
                if time.time() - tf > 10: run = False
        
            
            pygame.display.flip()
            
        
    except pygame.error,  mensaje:
        print "\n\t Error:",  mensaje, "\n"
    except:
       print "\n\t Error: ", sys.exc_info()[0], "\n"

	
if __name__ == '__main__':
    if len(sys.argv) == 1:
        main()
    elif len(sys.argv) == 2:
        if sys.argv[1] == '-h':
            print __uso__