# -*- coding: utf-8 -*-
__author__ = 'Carlos'

from PPlay.window import *
from PPlay.sprite import *
import random
import math
random.seed()

# INICIALIZAÇÃO DO JOGO

# Cria a janela do programa.
janela = Window(600, 600)
janela.set_title("Protótipo - Colisão")

# Temos 8 sprites. 4 do personagem andando e 4 parados. No game loop vamos desenhar apenas um deles,
# mas os sprites serão pré-carregados apenas uma vez, antes do game loop.
lista_sprites_heroi = []
#Sprites de 0 a 3: personagem parado.
for contador in range(4):
    sprite = Sprite("hero" + str(contador) + "_1.png", 1)
    sprite.set_total_duration(500)
    lista_sprites_heroi.append(sprite)
# Sprites de 4 a 7: personagem andando.
for contador in range(4):
    sprite = Sprite("hero" + str(contador) + ".png", 4)
    sprite.set_total_duration(500)
    lista_sprites_heroi.append(sprite)

# Pré-carrega sprites de tiles
lista_sprites_terreno = []
sprite = Sprite("cave.png", 1)
lista_sprites_terreno.append(sprite)
TERRENO_TILE_PAREDE_0 = 0
sprite = Sprite("cave2.png", 1)
lista_sprites_terreno.append(sprite)
TERRENO_TILE_PAREDE_1 = 1
sprite = Sprite("cave_floor.png", 1)
lista_sprites_terreno.append(sprite)
TERRENO_TILE_CHAO_0 = 2
sprite = Sprite("cave_floor2.png", 1)
lista_sprites_terreno.append(sprite)
TERRENO_TILE_CHAO_1 = 3
sprite = Sprite("buraco.png", 1)
lista_sprites_terreno.append(sprite)
TERRENO_TILE_SAIDA = 4


# Propriedades iniciais do personagem.
heroi_velocidade_x = 8
heroi_velocidade_y = 8
heroi_direcao = 0
heroi_movimento = 0
heroi_colidiu = 0
# variuável utilizada para otimizar a instância do sprite atual em lista_sprites_heroi.
sprite_atual = 0

# Associar uma variável à instância de teclado contida em Window
teclado = Window.get_keyboard()  # Função da CLASSE e não da instância! W maiúsculo!

# Constantes de mapa e renderização
tamanho_tile_x = 54
tamanho_tile_y = 42

# GERADOR DE MAPAS ALEATÓRIOS
#
# Parte longa do código. Se quiser pular para a lógica do jogo, procure por GAME_LOOP.

# Inicialização do terreno. Todas as tiles são inicialmente o chão padrão.
tamanho_do_mapa = 60
terreno = [[TERRENO_TILE_CHAO_0 for x in range(tamanho_do_mapa)] for y in range(tamanho_do_mapa)]
terreno_preenchido = [[0 for x in range(tamanho_do_mapa)] for y in range(tamanho_do_mapa)]
#Insere o monstrão central (ele fica parado gerando monstrinhos que andam na direção do herói)
metade_mapa = int(tamanho_do_mapa / 2)
terreno[metade_mapa][metade_mapa] = TERRENO_TILE_CHAO_1
terreno_preenchido[metade_mapa][metade_mapa] = 1
terreno_preenchido[metade_mapa+1][metade_mapa] = 1
terreno_preenchido[metade_mapa][metade_mapa+1] = 1
terreno_preenchido[metade_mapa+1][metade_mapa+1] = 1
# Damos um espaço em volta desse monstrão para que os monstrimhos possam ser gerados sem obstáculos
i = metade_mapa - 3
while i < (metade_mapa + 3):
    terreno_preenchido[i][metade_mapa - 3] = 1
    terreno_preenchido[i][metade_mapa - 2] = 1
    terreno_preenchido[i][metade_mapa + 2] = 1
    terreno_preenchido[i][metade_mapa + 3] = 1
    i += 1
i = metade_mapa - 1
while i < (metade_mapa + 1):
    terreno_preenchido[metade_mapa - 3][i] = 1
    terreno_preenchido[metade_mapa - 2][i] = 1
    terreno_preenchido[metade_mapa + 2][i] = 1
    terreno_preenchido[metade_mapa + 3][i] = 1
    i += 1
# Em seguida, faremos barreiras das quatro bordas do terreno. Nessas 4 bordas, a gente preenche cada uma com
# um polígono em que duas faces do canto do mapa são retas e a outra é uma espécie de curva.
#
# Borda Noroeste
borda_esquerda = 0
borda_direita = int(tamanho_do_mapa * 0.25)
borda_cima = 0
borda_baixo = int(tamanho_do_mapa * 0.25)
x = borda_esquerda
y = borda_baixo
while x <= borda_direita:
    preenchimento_y = y
    while preenchimento_y >= borda_cima:
        if terreno_preenchido[x][preenchimento_y] == 0:
            terreno[x][preenchimento_y] = TERRENO_TILE_PAREDE_0
            terreno_preenchido[x][preenchimento_y] = 1
        preenchimento_y -= 1
    fator_de_curva = random.randint(0,3)
    if (y < (borda_cima + fator_de_curva)):
        y = borda_cima
    else:
        y -= fator_de_curva
    x += 1
# Borda Nordeste
borda_esquerda = int(tamanho_do_mapa * 0.75)
borda_direita = tamanho_do_mapa - 1
borda_cima = 0
borda_baixo = int(tamanho_do_mapa * 0.25)
x = borda_esquerda
y = borda_cima
while x <= borda_direita:
    preenchimento_y = y
    while preenchimento_y >= borda_cima:
        if terreno_preenchido[x][preenchimento_y] == 0:
            terreno[x][preenchimento_y] = TERRENO_TILE_PAREDE_0
            terreno_preenchido[x][preenchimento_y] = 1
        preenchimento_y -= 1
    fator_de_curva = random.randint(0,3)
    if (y > (borda_baixo - fator_de_curva)):
        y = borda_baixo
    else:
        y += fator_de_curva
    x += 1
# Borda Sudoeste
borda_esquerda = 0
borda_direita = int(tamanho_do_mapa * 0.25)
borda_cima = int(tamanho_do_mapa * 0.75)
borda_baixo = tamanho_do_mapa - 1
x = borda_esquerda
y = borda_cima
while x <= borda_direita:
    preenchimento_y = y
    while preenchimento_y <= borda_baixo:
        if terreno_preenchido[x][preenchimento_y] == 0:
            terreno[x][preenchimento_y] = TERRENO_TILE_PAREDE_0
            terreno_preenchido[x][preenchimento_y] = 1
        preenchimento_y += 1
    fator_de_curva = random.randint(0,3)
    if (y > (borda_baixo - fator_de_curva)):
        y = borda_baixo
    else:
        y += fator_de_curva
    x += 1
# Borda Sudeste
borda_esquerda = int(tamanho_do_mapa * 0.75)
borda_direita = tamanho_do_mapa - 1
borda_cima = int(tamanho_do_mapa * 0.75)
borda_baixo = tamanho_do_mapa - 1
x = borda_esquerda
y = borda_baixo
while x <= borda_direita:
    preenchimento_y = y
    while preenchimento_y <= borda_baixo:
        if terreno_preenchido[x][preenchimento_y] == 0:
            terreno[x][preenchimento_y] = TERRENO_TILE_PAREDE_0
            terreno_preenchido[x][preenchimento_y] = 1
        preenchimento_y += 1
    fator_de_curva = random.randint(0,3)
    if (y < (borda_cima + fator_de_curva)):
        y = borda_cima
    else:
        y -= fator_de_curva
    x += 1
# Agora que terminamos as bordas, adicionamos a saída
y = tamanho_do_mapa - 1
x = int(tamanho_do_mapa * 0.3) + random.randint(0,int(tamanho_do_mapa * 0.4))
terreno[x][y] = TERRENO_TILE_SAIDA
terreno_preenchido[x][y] = 1
# Em seguida, adicionamos a bomba ao lado da saída
y = y - 1
terreno[x][y] = TERRENO_TILE_PAREDE_0
terreno_preenchido[x][y] = 1
# O personagem inicia ao lado da bomba. O terreno é um chão padrão, por isso, não muda.
x = x - 1
heroi_posicao_mapa_x = x + 0.5
heroi_posicao_mapa_y = y + 0.5
terreno_preenchido[x][y] = 1
# Adicionamos algumas barreiras para proteger o personagem
y -= 2
xFill = (x - 2)
while xFill < (x + 3):
    if terreno_preenchido[xFill][y] == 0:
        terreno[xFill][y] = TERRENO_TILE_PAREDE_0
        terreno_preenchido[xFill][y] = 1
    xFill += 1
# Preenchemos o resto das bordas com barreiras. Isso ajuda a impedir o personagem e os monstros de saírem
# do mapa
y = 0
while y < tamanho_do_mapa:
    if terreno_preenchido[0][y] == 0:
        terreno[0][y] = TERRENO_TILE_PAREDE_0
        terreno_preenchido[0][y] = 1
    if terreno_preenchido[tamanho_do_mapa - 1][y] == 0:
        terreno[tamanho_do_mapa - 1][y] = TERRENO_TILE_PAREDE_0
        terreno_preenchido[tamanho_do_mapa - 1][y] = 1
    y += 1
x = 0
while x < tamanho_do_mapa:
    if terreno_preenchido[x][0] == 0:
        terreno[x][0] = TERRENO_TILE_PAREDE_0
        terreno_preenchido[x][0] = 1
    if terreno_preenchido[x][tamanho_do_mapa - 1] == 0:
        terreno[x][tamanho_do_mapa - 1] = TERRENO_TILE_PAREDE_0
        terreno_preenchido[x][tamanho_do_mapa - 1] = 1
    x += 1





# GAME_LOOP
while(True):

    # ENTRADA DE DADOS

    # Consideramos por padrão que o personagem está parado
    heroi_movimento = 0
    # Tratamento de eventos de teclado relacionados ao movimento do personagem.
    if(teclado.key_pressed("UP")):
        heroi_direcao = 0
        heroi_movimento = 4
    if(teclado.key_pressed("RIGHT")):
        heroi_direcao = 1
        heroi_movimento = 4
    if(teclado.key_pressed("DOWN")):
        heroi_direcao = 2
        heroi_movimento = 4
    if(teclado.key_pressed("LEFT")):
        heroi_direcao = 3
        heroi_movimento = 4
    # Verifica se "Esc" foi pressionado para fechar o jogo
    if(teclado.key_pressed("esc")):
        janela.close()

    # FÍSICA

    # Move o sprite atual do personagem para a posição do personagem.
    sprite_atual = heroi_direcao + heroi_movimento
    lista_sprites_heroi[sprite_atual].set_position(heroi_posicao_mapa_x, heroi_posicao_mapa_y)

    # move o sprite atual de acordo com o input do teclado
    lista_sprites_heroi[sprite_atual].move_key_x(heroi_velocidade_x * janela.delta_time())
    lista_sprites_heroi[sprite_atual].move_key_y(heroi_velocidade_y * janela.delta_time())

    # PS: Prezados fãs do PPlay, me perdoem. Mas dispensei o seu método padrão de colisão, pois
    # ele não é adequado ao tipo de sprite que estou lidando no meu jogo. Além disso, a verificação
    # a seguir já obtém resultados adequados
    #
    # Verifica colisão com o terreno ao redor do personagem para validar o movimento.
    min_x = math.floor(lista_sprites_heroi[sprite_atual].x)
    min_y = math.floor(lista_sprites_heroi[sprite_atual].y)
    heroi_colidiu = 0
    if abs(lista_sprites_heroi[sprite_atual].x - min_x - 0.5) <= 0.25:
        max_x = min_x
    elif (lista_sprites_heroi[sprite_atual].x - min_x) > 0.75:
        max_x = min_x + 1
    else:
        max_x = min_x
        min_x -= 1
    if abs(lista_sprites_heroi[sprite_atual].y - min_y - 0.5) <= 0.25:
        max_y = min_y
    elif (lista_sprites_heroi[sprite_atual].y - min_y) > 0.75:
        max_y = min_y + 1
    else:
        max_y = min_y
        min_y -= 1
    if min_x < 0:
        min_x = 0
    if min_y < 0:
        min_y = 0
    if min_x >= tamanho_do_mapa:
        min_x = tamanho_do_mapa - 1
    if min_y >= tamanho_do_mapa:
        min_y = tamanho_do_mapa - 1
    if max_x >= tamanho_do_mapa:
        max_x = tamanho_do_mapa - 1
    if max_y >= tamanho_do_mapa:
        max_y = tamanho_do_mapa - 1
    x = min_x
    while x <= max_x:
        y = min_y
        while y <= max_y:
            if (terreno[x][y] == TERRENO_TILE_PAREDE_0) or (terreno[x][y] == TERRENO_TILE_PAREDE_1):
                heroi_colidiu = 1
            y += 1
        x += 1

    # Atualiza a posição do personagem para a posição do sprite atual.
    if heroi_colidiu == 0:
        heroi_posicao_mapa_x = lista_sprites_heroi[sprite_atual].x
        heroi_posicao_mapa_y = lista_sprites_heroi[sprite_atual].y

    # RENDERIZAÇÃO

    # Desenha o fundo. É fundamental para apagar o que estava na tela anterior.
    janela.set_background_color((0,0,0))

    # Desenha o terreno em volta do personagem. O personagem ficará sempre no centro da janela. O mapa é que
    # será movimentado nesse processo.
    #
    # As variáveis min_posicao_y, posicao_x e posicao_y estão no sistema de coordenadas da tela.
    # As variáveis heroi_posicao_mapa_x, heroi_posicao_mapa_y, x, y, min_x, min_y, max_x e max_y estão no sistema de
    # coordenadas do mapa.
    min_x = math.floor(heroi_posicao_mapa_x - (janela.width / (2 * tamanho_tile_x))) - 1
    min_y = math.floor(heroi_posicao_mapa_y - (janela.height / (2 * tamanho_tile_y))) - 1
    max_x = math.ceil(heroi_posicao_mapa_x + (janela.width / (2 * tamanho_tile_x))) + 1
    max_y = math.ceil(heroi_posicao_mapa_y + (janela.height / (2 * tamanho_tile_y))) + 1
    if min_x < 0:
        min_x = 0
    posicao_x = (janela.width / 2) - ((heroi_posicao_mapa_x - min_x) * tamanho_tile_x)
    if min_y < 0:
        min_y = 0
    min_posicao_y = (janela.height / 2) + tamanho_tile_y - ((heroi_posicao_mapa_y - min_y) * tamanho_tile_y)
    if max_x > tamanho_do_mapa:
        max_x = tamanho_do_mapa
    if max_y > tamanho_do_mapa:
        max_y = tamanho_do_mapa
    x = min_x
    while x < max_x:
        posicao_y = min_posicao_y
        y = min_y
        while y < max_y:
            lista_sprites_terreno[terreno[x][y]].set_position(posicao_x, posicao_y - (lista_sprites_terreno[terreno[x][y]].height - tamanho_tile_y))
            lista_sprites_terreno[terreno[x][y]].draw()
            posicao_y += tamanho_tile_y
            y += 1
        posicao_x += tamanho_tile_x
        x += 1

    # Desenha apenas o sprite do movimento que está sendo feito (direção + andando/parado)
    # O sprite é centralizado horizontalmente na tela. Verticalmente, tentamos centralizar o pé do personagem.
    lista_sprites_heroi[sprite_atual].set_position((janela.width / 2) - (lista_sprites_heroi[sprite_atual].width / 2), (janela.height / 2) - (lista_sprites_heroi[sprite_atual].height / 2))
    lista_sprites_heroi[heroi_direcao + heroi_movimento].draw()

    # Muda o frame da animação
    lista_sprites_heroi[heroi_direcao + heroi_movimento].update()

    # Atualiza janela.
    janela.update()
