import pyxel
import random

class Vent: 
    def __init__(self):
        self.x=random.randint(20, pyxel.width-20)
        self.y=random.randint(0, pyxel.height)
        self.vitesse = random.randint(4,6)
    
    def update(self):
        if self.y > -11:
            self.y -= self.vitesse
        else:
            self.x = random.randint(0, pyxel.width)
            self.y = pyxel.height
            self.vitesse = random.randint(4,6)
    
    def draw(self):
        pyxel.blt(self.x, self.y, 0, 0, 8, 7, 7, colkey = 1)

class Cinematic:
    def __init__(self, n):
        self.x = 136
        self.y = 10
        self.vent = list()
        for i in range(n):
            self.vent.append(Vent())
            
    def update(self):
        for e in self.vent:
            e.update()
        
    def draw(self):
        for e in self.vent:
            e.draw()
        
        if pyxel.frame_count % 64 >= 32:
            pyxel.blt(172, 90 + (pyxel.frame_count%32//4), 0, 24, 0, 8, 8, colkey = 0, scale = 16)
            pyxel.rect(- 32 + pyxel.frame_count%32 , 0, 64, pyxel.height, 5)
            pyxel.rect(320 + pyxel.frame_count%32, 0, 64, pyxel.height, 5)
        else:
            pyxel.blt(172, 98 - (pyxel.frame_count%32//4), 0, 24, 0, 8, 8, colkey = 0, scale = 16)
            pyxel.rect(0 - pyxel.frame_count%32, 0, 64, pyxel.height, 5)
            pyxel.rect(352 - pyxel.frame_count%32, 0, 64, pyxel.height, 5)

class Cinematique_fin:
    def __init__(self, frame_nb, death_nb, starting_timer):
        if (frame_nb - starting_timer)  < 126000 :
            if ((frame_nb - starting_timer)//35) % 60 < 10 :
                self.time = str((frame_nb - starting_timer)//(35*60)) + ": 0" + str(((frame_nb - starting_timer)//35)%60)
            else:
                self.time = str((frame_nb - starting_timer)//(35*60)) + ":" + str(((frame_nb - starting_timer)//35)%60)
        else:
            if ((frame_nb - starting_timer)//35) % 60 < 10 :
                self.time = str((frame_nb - starting_timer)//(35*60*60)) + str((frame_nb - starting_timer)//(35*60)) + ": 0" + str(((frame_nb - starting_timer)//35)%60)
            else:
                self.time = str((frame_nb - starting_timer)//(35*60*60)) + ":" + str(((frame_nb - starting_timer)//(35*60))%60) + ":" + str(((frame_nb - starting_timer)//35)%60)
        self.death_nb = str(death_nb)
        self.joueur = [368, 191]
        self.anim_phase = 1
        self.impulsion = 10
        self.ecran_fin = False
        
        self.show_credit = False
        self.show_credit_two = False
        self.show_death = False
        self.show_time = False
        self.show_checkpoint = False
        
    def update(self):
        if self.anim_phase == 1:
            self.joueur[1] -= self.impulsion
            self.impulsion -= 1
            if self.impulsion <= 0:
                self.anim_phase = 1.1
                
        elif self.anim_phase == 1.1:
            self.joueur[0] -= 2
            self.joueur[1] -= self.impulsion
            self.impulsion -= 1
            if self.joueur[1] >= 168:
                self.joueur[1] = 168
                self.anim_phase = 1.2
                self.wait = 20
                
        elif self.anim_phase == 1.2:
            self.wait -= 1
            if self.wait <= 0:
                self.anim_phase = 2
                
        elif self.anim_phase == 2:
            self.joueur[0] -= 2
            if self.joueur[0] <= 88:
                self.anim_phase = 3
                self.wait = 100
                
        elif self.anim_phase == 3:
            self.wait -= 1
            if self.wait <= 0:
                self.anim_phase = 4
                self.impulsion = 8
                
        elif self.anim_phase == 4:
            self.joueur[0] -= 3
            self.joueur[1] -= self.impulsion
            self.impulsion -= 1
            if self.joueur[1] >= 220:
                self.ecran_fin = True
                self.anim_phase = 5
                self.wait = 200
                
        elif self.anim_phase == 5:
            self.wait -= 1
            if self.wait <= 100:
                self.show_credit = True
            if self.wait <= 80:
                self.show_credit_two = True
            if self.wait <= 0:
                self.show_death = True
            if self.wait <= -20:
                self.show_time = True
            if self.wait <= -40:
                self.show_checkpoint = True
                
    def draw(self):
        pyxel.blt(self.joueur[0], self.joueur[1], 0, 0, 0, -8, 8, colkey = 0)
        
class Joueur:
    def __init__(self):
        self.sprite = 3
        self.x = 56
        self.y = -7
        self.height = 8
        self.width = 8
        self.vitesse = 2
        self.direction_facing = 1

        self.up_movement = 0
        
        self.dash_ability = False
        self.dash_remaining = 1
        self.dash_lenght = 0
        
        self.double_jump = False
        self.aerial_jump = 0
        
        self.big_saut = False
        self.big_saut_lenght = 0
        self.up_dash = 0
        
        self.spawn_point = [56, 120]
        self.accessibilty_settings = False
        self.checkpoint_available = True
        self.nb_checkpoint = 0
        self.death_anim = 0
        self.ground_color = self.get_color_under()
    
    def update(self, Jeu): 
        if self.big_saut_lenght > 0:
            self.big_saut_lenght -= 1
        
        if self.death_anim > 0:
            self.death_anim -= 1
            if self.death_anim == 1:
                self.x, self.y = self.spawn_point
                self.sprite = 0
                Jeu.death_counter += 1
                self.up_movement = 0
                self.dash_lenght = 0
                self.big_saut_lenght = 0
                self.up_dash = 0
            if self.death_anim <= 4:
                self.sprite = 7
            else:
                self.sprite = 5
        
        else:
            
            if self.up_movement == 0:
                self.sprite = 0
            elif self.up_movement < 0:
                self.sprite = 2
            else:
                self.sprite = 3
            
            
            if self.dash_lenght > 0:
                self.dash()
                self.sprite = 4
                """elif pyxel.btn(pyxel.KEY_V):
                self.x += 20 * self.direction_facing
                self.sprite = 4"""
                
            else:
                if self.up_dash > 0:
                    self.up_dash_apply()
                self.ground_color = self.get_color_under()
                self.deplacement_verticale(Jeu)
                
                if pyxel.btn(pyxel.KEY_D) or pyxel.btn(pyxel.KEY_RIGHT):
                    self.direction_facing = 1
                    if pyxel.pget(self.x + self.vitesse + self.width - 1, self.y + self.height - 1) == 0 and pyxel.pget(self.x + self.vitesse + self.width - 1, self.y) == 0:
                        self.x += self.vitesse
                    elif pyxel.pget(self.x + self.vitesse + self.width - 1, self.y + self.height - 1) == 8 or pyxel.pget(self.x + self.vitesse + self.width - 1, self.y) == 8:
                        self.x += self.vitesse
                        self.death_anim = 35
                        self.up_movement = 0
                    else:
                        while pyxel.pget(self.x + self.width, self.y + self.height - 1) == 0 and pyxel.pget(self.x + self.width, self.y) == 0 :
                            self.x += 1 * self.direction_facing
                
                if pyxel.btn(pyxel.KEY_Q) or pyxel.btn(pyxel.KEY_LEFT):
                    self.direction_facing = -1
                    if pyxel.pget(self.x - self.vitesse, self.y + self.height - 1) == 0 and pyxel.pget(self.x - self.vitesse, self.y) == 0:
                        self.x -= self.vitesse
                    elif pyxel.pget(self.x - self.vitesse, self.y + self.height - 1) == 8 or pyxel.pget(self.x - self.vitesse, self.y) == 8:
                        self.x -= self.vitesse
                        self.death_anim = 35
                        self.up_movement = 0
                    else :
                        while pyxel.pget(self.x - 1, self.y + self.height - 1) == 0 and pyxel.pget(self.x - 1, self.y) == 0 :
                            self.x += 1 * self.direction_facing
                
                if pyxel.btn(pyxel.KEY_S) or pyxel.btn(pyxel.KEY_DOWN):
                    if self.ground_color == 4:
                        self.y += 3
                        self.up_movement = 3
                
                if pyxel.btnp(pyxel.KEY_SPACE) and (self.ground_color != 0 or (self.double_jump and self.aerial_jump == 0 )): 
                    if not(self.ground_color != 0):
                        self.aerial_jump += 1
                    self.vitesse = 3
                    self.up_movement = -9
                
                elif pyxel.btnp(pyxel.KEY_SPACE, 45, 1) and self.big_saut: 
                    self.sprite  = 6
                    self.big_saut_lenght = 2
                    
                elif pyxel.btnr(pyxel.KEY_SPACE) and self.big_saut_lenght > 0 and self.ground_color != 0:
                    self.up_dash = 32
                
                if (pyxel.btnp(pyxel.KEY_C) or pyxel.btn(pyxel.KEY_A) or pyxel.btn(pyxel.KEY_TAB))and self.dash_ability and self.dash_remaining > 0 :
                    self.dash_lenght = 10
                    self.up_movement = 0
                    self.dash_remaining -= 1
                
                if pyxel.btnp(pyxel.KEY_P):
                    self.accessibilty_settings = True
                    
                if pyxel.btnp(pyxel.KEY_X) and (self.ground_color == 5 or self.ground_color == 4) and self.checkpoint_available and self.accessibilty_settings :
                    self.spawn_point = [self.x, self.y]
                    self.checkpoint_available = False
                    self.nb_checkpoint += 1
    
    def dash(self):
        self.up_dash = 0
        if self.direction_facing == 1 :
            if pyxel.pget(self.x + self.width + 7, self.y + self.height - 1) == 0 and pyxel.pget(self.x + self.width + 7, self.y) == 0:
                self.x += 7 * self.direction_facing
                self.dash_lenght -= 1
            elif pyxel.pget(self.x + self.width + 7, self.y + self.height - 1) == 8 and pyxel.pget(self.x + self.width + 7, self.y) == 8:
                self.x += 7 * self.direction_facing
                self.dash_lenght -= 1
                self.death_anim = 35
                self.dash_lenght = 0
            else:
                self.dash_lenght = 0
                i = 0
                while pyxel.pget(self.x + self.width + i, self.y + self.height- 1) == 0 and pyxel.pget(self.x + self.width + i, self.y) == 0:
                    i += 1
                self.x += i * self.direction_facing
        elif self.direction_facing == -1 :
            if pyxel.pget(self.x - 7, self.y + self.height - 1) == 0 and pyxel.pget(self.x - 7, self.y) == 0:
                self.x += 7 * self.direction_facing
                self.dash_lenght -= 1
            elif pyxel.pget(self.x - 7, self.y + self.height - 1) == 8 and pyxel.pget(self.x - 7, self.y) == 8:
                self.x += 7 * self.direction_facing
                self.dash_lenght -= 1
                self.death_anim = 35
                self.dash_lenght = 0
            else:
                self.dash_lenght = 0
                i = 0
                while pyxel.pget(self.x - 1 - i, self.y + self.height - 1) == 0 and pyxel.pget(self.x - i - 1, self.y) == 0:
                    i += 1
                self.x += i * self.direction_facing
    
    def up_dash_apply(self):
        for i in range(self.up_dash):
            if pyxel.pget(self.x, self.y - i - 1) != 0 or pyxel.pget(self.x + self.width - 1, self.y - i - 1) != 0 :
                if pyxel.pget(self.x, self.y - 1) == 8 and pyxel.pget(self.x + self.width - 1, self.y - 1) == 8:
                    self.death_anim = 35
                self.y -= i
                self.up_dash = 0
                self.up_movement = -2
                return None
            else:
                self.up_movement = -2
        self.y -= self.up_dash
        self.up_dash = round(self.up_dash * (3/4)) - 1
    
    def deplacement_verticale(self, Jeu): 
        #Check si sous lui c'est le sol
        if self.ground_color != 0 :
            
            self.vitesse = 2
            self.dash_remaining = 1
            self.aerial_jump = 0
            
            if self.up_movement >= 0:
                self.up_movement = 0
                
            #si touche du vert, fait rebondir
            if self.ground_color == 11 :
                self.up_movement = -10
                
            #meurt s'il touchhe du rouge
            if self.ground_color == 8 :
                self.death_anim = 35    
                
            #fais remonter s'il se met a descendre à travers le sol    
            while (pyxel.pget(self.x, self.y + self.height - 1) == 5 or pyxel.pget(self.x + self.width - 1, self.y + self.height - 1) == 5)\
            or (pyxel.pget(self.x, self.y + self.height - 1) == 7 or pyxel.pget(self.x + self.width - 1, self.y + self.height - 1) == 7):
                self.y -= 1
                
            if self.ground_color == 15 :
                self.spawn_point = self.x, self.y
            
            #gagne une habilité en touchant du jaune
            if self.ground_color == 10 :
                if self.dash_ability:
                    if self.big_saut:
                        self.double_jump = True
                    self.big_saut = True
                self.dash_ability = True
                Jeu.change_de_map[0] += 1
                Jeu.change_de_map[1] = 0
                self.spawn_point = [self.x, self.y]
            
            
        else:
            if self.up_movement < 8:
                self.up_movement += 1
            self.au_sol = False
            self.vitesse = 3
        
        if self.up_movement <= 0:
            #Check si au dessus de lui c'est du vide
            if (pyxel.pget(self.x, self.y + self.up_movement) == 0 or pyxel.pget(self.x, self.y + self.up_movement) == 4) and \
            (pyxel.pget(self.x + self.width - 1, self.y + self.up_movement) == 0 or pyxel.pget(self.x + self.width - 1, self.y + self.up_movement) == 4):
                self.y += self.up_movement 
            elif pyxel.pget(self.x, self.y + self.up_movement) == 8 or pyxel.pget(self.x + self.width - 1, self.y + self.up_movement) == 8 :
                self.y += self.up_movement
                self.death_anim = 35
                self.up_movement = 0
            else:
                self.up_movement = 0
                while pyxel.pget(self.x, self.y - 1) == 0 and pyxel.pget(self.x + self.width - 1, self.y - 1) == 0:
                    self.y -= 1
            
        elif self.up_movement >= 0:
            if pyxel.pget(self.x, self.y + self.height + self.up_movement) == 0 and pyxel.pget(self.x, self.y + self.height + self.up_movement) == 0:
                self.y += self.up_movement 
            else:
                while pyxel.pget(self.x, self.y + self.height) == 0 and pyxel.pget(self.x + self.width - 1, self.y + self.height) == 0:
                    self.y += 1
                    self.up_movement = 0
    
    def get_color_under(self):
        x1 = pyxel.pget(self.x, self.y + self.height)
        x2 = pyxel.pget(self.x + self.width//2, self.y + self.height)
        x3 = pyxel.pget(self.x + self.width - 1, self.y + self.height)
        for e in [11, 15, 5, 7, 4, 8, 10, 0]:
            if e == x2:
                return x2
            if e == x1:
                return x1
            if e == x3:
                return x3
    
    def draw(self):
        
        pyxel.blt(self.x, self.y, 0, self.sprite*8, 0, 8*self.direction_facing, 8, colkey = 0)
        
        if self.double_jump:
            if self.aerial_jump == 0:
                pyxel.circ(self.x + 4 -10*self.direction_facing, self.y - 5, 1, 6)
            else:
                pyxel.circ(self.x + 4 -10*self.direction_facing, self.y - 5, 1, 1)
        
        if pyxel.btn(pyxel.MOUSE_BUTTON_LEFT):
            pyxel.rectb(self.x + 70*self.direction_facing, self.y, 8, 8, 7)

class Jeu:
    def __init__(self):
        
        pyxel.init(384, 192, title="Chat-Verne", fps=35)
        self.change_de_map = [0,0]
        self.j = Joueur()
        self.cinematic = Cinematic(10)
        self.start = False
        self.end = False
        self.death_counter = 00
        self.tuto_checkpoint = False
        pyxel.load("res2.pyxres") 
        pyxel.run(self.update, self.draw)
    
    def update(self):
        
        if not self.start:
            self.cinematic.update()
            if pyxel.btnp(pyxel.KEY_SPACE):
                self.start = True
                self.starting_timer = pyxel.frame_count
            if pyxel.btnp(pyxel.KEY_E):
                if not self.tuto_checkpoint:
                    self.tuto_checkpoint = True
                else:
                    self.tuto_checkpoint = False
                    
        elif self.end:
            self.cinematique_fin.update()
            
        else:
            #self.perso.update(self.j)
            self.j.update(self)
            
            if self.j.x + self.j.width <= 0:
                self.j.checkpoint_available = True
                if self.change_de_map[1] == 0:
                    self.change_de_map[1] = 4
                    self.change_de_map[0] -= 1
                else: 
                    self.change_de_map[1] -= 1
                self.j.x = 384 - 1
                self.j.spawn_point = [self.j.x - 20, self.j.y]
            
            elif self.j.x >= 384:
                self.j.checkpoint_available = True
                if self.change_de_map[1] == 4:
                    self.change_de_map[1] = 0
                    self.change_de_map[0] += 1
                else:
                    self.change_de_map[1] += 1
                self.j.x = 0 - self.j.width + 1
                self.j.spawn_point = [self.j.x + 20, self.j.y]
                
            elif self.j.y + self.j.height <= 0:
                self.j.checkpoint_available = True
                self.change_de_map[0] += 1
                self.j.y = 192 - 1
                self.j.up_movement += -3
                if self.change_de_map[0] == 10 :
                    self.end = True
                    self.cinematique_fin = Cinematique_fin(pyxel.frame_count, self.death_counter, self.starting_timer)
                
            elif self.j.y >= 192:
                self.j.checkpoint_available = True
                self.change_de_map[0] -= 1
                self.j.y = 0 + 1
                self.j.spawn_point = self.j.x, self.j.y + 20
    
    def draw(self):
        pyxel.cls(0)   
        if self.start:
            pyxel.bltm(0, 0, 0, 384*self.change_de_map[1], 192*self.change_de_map[0], 384, 192)
            if self.change_de_map[0] < 6:
                pyxel.text(10, 2, str(self.death_counter), 0)
            
            self.j.draw()
        else:
            self.cinematic.draw()
            pyxel.text(155, 10, "LA CHAT-VERNE", 7)
            pyxel.text(130, 20, "press SPACE to start the game", 13)
            pyxel.text(65, 160, "if you want to see the friendlier settings to the game, press E", 13)
            if self.tuto_checkpoint :
                pyxel.rect(35, 50, 314, 92, 1)
                pyxel.rectb(35, 50, 314, 92, 12)
                pyxel.text(45, 60, "An option is available in order to make the game easier :", 7)
                pyxel.text(50, 68, "The manual Checkpoint", 7)
                pyxel.text(43, 78, "It allows you to place bonus checkpoints when you find a jump too difficult", 7)
                pyxel.text(43, 92, "You only have one manual checkpoint per room, it reset when you exit a room", 7)
                pyxel.text(43, 102, "Keep in mind the game was not intended this way, so you may stuck yourself", 7)
                pyxel.text(43, 116, "To activate this option, press -P- in the game", 7)
                pyxel.text(43, 126, "You can then place a checkpoint by pressing -X- while on the ground", 7)
        if self.end:
            pyxel.bltm(0, 0, 1, 0, 0, 384, 192)
            self.cinematique_fin.draw()
            if self.cinematique_fin.ecran_fin :
                pyxel.bltm(0, 0, 1, 384, 0, 384, 192)
                if self.cinematique_fin.show_credit:
                    pyxel.text(250, 90, "A Game made by Victor Andrieu", 13)
                if self.cinematique_fin.show_credit_two:
                    pyxel.text(250, 98, "With the participation of Keylan", 13)
                if self.cinematique_fin.show_death:
                    pyxel.text(150, 100, "number of death :", 7)
                    pyxel.text(220, 100, self.cinematique_fin.death_nb, 7)
                if self.cinematique_fin.show_time:
                    pyxel.text(160, 120, "time :", 7)
                    pyxel.text(190, 120, self.cinematique_fin.time, 7)
                if self.cinematique_fin.show_checkpoint and self.j.accessibilty_settings:
                    pyxel.text(135, 140, "number of checkpoint used :", 7)
                    pyxel.text(245, 140, str(self.j.nb_checkpoint), 7)

Jeu()