import pyxel


def en_contact(hitbox1, hitbox2):
    return ( (hitbox1.x + hitbox1.w) >= hitbox2.x and hitbox1.x <= (hitbox2.x + hitbox2.w) and (hitbox1.y + hitbox1.h) >= hitbox2.y and hitbox1.y <= (hitbox2.y + hitbox2.h) )


def gravite(entite):
    if entite.saute == False and entite.au_sol == False and entite.en_dash == False:
        if entite.chute < 2:
            entite.y = entite.y + (entite.chute**2)*0.8
            entite.chute += 0.4
        else:
            entite.y = entite.y + 2.9
    else:
        entite.chute = 0.0

def mouv_1er_plan1(entite, perso):
    if perso.vivant:
        entite.x -= perso.x - perso.x_precedent

def mouv_1er_plan(entite, perso):
    if not perso.immobile:
        if pyxel.btn(pyxel.KEY_D):
            entite.x -= 1
        if pyxel.btn(pyxel.KEY_Q):
            entite.x += 1

def mouv_2eme_plan2(entite, perso):
    if perso.vivant:
        entite.x -= (perso.x - perso.x_precedent)*0.4

def mouv_2eme_plan(entite, perso):
    if pyxel.btn(pyxel.KEY_D):
        entite.x -= 0.4
    if pyxel.btn(pyxel.KEY_Q):
        entite.x += 0.4


#*********************************************************************************

class Elem_dangereux:
    def __init__(self, x,y,w,h, type_elem = 0):
        self.x = x
        self.y = y
        self.w = w
        self.h = 8
        
        self.hitbox = Hitbox(self)
        
        self.type = type_elem #0 = piques
        self.delay_degats = 0

    def degats_perso(self, perso):
        if self.delay_degats == 0:
            if en_contact(self.hitbox, perso.hitbox):
                perso.pv -= 1
                delay_degats = 30
        else:
            self.delay_degats -= 1

    def update(self, perso):
        mouv_1er_plan(self, perso)
        self.hitbox.update(self)
        self.degats_perso(perso)

    def draw(self):
        pyxel.blt(self.x, self.y, 0, 144, 48, self.w, self.h,5)

#*********************************************************************************


class Hitbox:
    def __init__(self, entite):
        self.x = entite.x
        self.y = entite.y
        self.w = entite.w
        self.h = entite.h

    def update(self,entite, x = 0, y = 0, w = 0, h = 0):
        self.x = entite.x + x
        self.y = entite.y + y
        self.w = entite.w + w
        self.h = entite.h + h
    
    def draw(self):
        pass
        pyxel.blt(self.x, self.y, 0, 16, 224, self.w, self.h)



#*********************************************************************************


class Solide:
    def __init__(self, x,y,w,h):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.hitbox = Hitbox(self)

    def update(self, perso):
        mouv_1er_plan(self, perso)
        self.hitbox.update(self)

    def draw(self):
        pyxel.bltm(self.x, self.y, 0, 64*8, 112*8, self.w, self.h)

#*********************************************************************************

class Personnage:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.w = 16
        self.h = 16
        
        self.x_precedent = 0
        self.y_precedent = 0
        
        self.vivant = True
        self.pv = 1
        self.hitbox = Hitbox(self)

        self.vitesse = 2
        self.vitesse_normale = 2
        self.vitesse_dash = 4
        self.en_dash = False
        self.nb_frame_dash = 20
        self.temps_dash = 0

        self.en_mouv = False
        self.sens = 1

        self.saute = False
        self.nb_frame_saut = 20
        self.temps_saute = 0
        self.au_sol = False
        self.chute = 0.0
        self.ascension = 1.6
        
        self.immobile = False
        
        self.mun_dash_max = 5
        self.mun_dash = self.mun_dash_max
        
        self.solides = [Solide(50,100,50,50)]
    
    def maj_coord_precedents(self):
        self.x_precedent = self.x
        self.y_precedent = self.y
    
    def test_collision(self):
        for solide in self.solides:
            if en_contact(self.hitbox, solide.hitbox):
                self.x = self.x_precedent
                self.y = self.y_precedent
                self.hitbox.update(self, 1, 1, -2, -2)

    def test_au_sol(self):
        self.y += 1
        self.hitbox.update(self, 3, 1, -6, -2)
        for solide in self.solides:
            if en_contact(self.hitbox, solide.hitbox):
                self.y -= 1
                self.hitbox.update(self, 1, 1, -2, -2)
                return True
        self.y -= 1
        self.hitbox.update(self, 1, 1, -2, -2)
        return False
    
    def test_saute(self):
        if self.saute:
            if self.temps_saute != 0:
                self.y = self.y - (self.ascension**2)
                self.temps_saute -= 1
                self.ascension -= 0.06
                self.au_sol = False
            else:
                self.temps_saute = self.nb_frame_saut
                self.saute = False
                self.ascension = 1.6


    #def update_solides(self):
        #for solide in self.solides:
            #solide.update(self)
   
    def draw_solides(self):
        for solide in self.solides:
            solide.draw()
    
    def test_en_dash(self):
        if self.temps_dash > 0:
            return True
        return False
    
    #def test_au_sol(self):
        #for solide in self.solides:
            #if en_contact(solide.hitbox, self.hitbox)
                

    def mouvement(self):
        #mouvements libre
        if pyxel.btn(pyxel.KEY_S):
            self.y = min(self.y + self.vitesse, 256-self.h)
            self.en_mouv = True
            #print("s")
        if pyxel.btn(pyxel.KEY_Z) and self.en_dash:
            self.y = max(self.y - (self.vitesse/2), 0)
            self.en_mouv = True
            #print("z")
        if pyxel.btn(pyxel.KEY_D):
            self.x = min(self.x + self.vitesse, 256-self.w)
            self.en_mouv = True
            self.sens = 1
            #print("d")
        if pyxel.btn(pyxel.KEY_Q):
            self.x = self.x - self.vitesse
            self.en_mouv = True
            self.sens = -1
            #print("q")

        #dashs
        if pyxel.btnp(pyxel.KEY_SPACE):
            
            if self.au_sol:
                self.saute = True
                self.temps_saute = self.nb_frame_saut
            elif self.mun_dash > 0:
                self.vitesse = self.vitesse_dash
                self.temps_dash = self.nb_frame_dash
                self.en_dash = True
                self.mun_dash -= 1
        
        if self.temps_dash > 0:
            self.temps_dash -= 1
        else:
            self.en_dash = False
            self.vitesse = self.vitesse_normale
    
    def test_vivant(self):
        if self.pv < 0:
            self.vivant = False
    
    def test_immobile(self):
        if self.x == self.x_precedent:
            self.immobile = True
        else:
            self.immobile = False
    
    def test_hors_map(self):
        if self.x < -16 or self.y > 257:
            self.vivant = False

    def recharge_dash(self):
        if self.au_sol:
            self.mun_dash = self.mun_dash_max
    
    def immo_en_dash(self):
        if self.en_dash and self.immobile:
            self.sens = 1
            self.y -= self.vitesse

    def update(self):
        self.en_mouv = not self.test_immobile

        self.maj_coord_precedents()
        self.en_dash = self.test_en_dash()
        if self.vivant:
            self.mouvement()
        self.test_saute()
        gravite(self)
        self.au_sol = self.test_au_sol()
        self.recharge_dash()
        self.immo_en_dash()
        self.hitbox.update(self, 1, 1, -2, -2)
        #self.update_solides()
        self.test_collision()
        self.test_vivant()
        self.test_immobile()
        self.test_hors_map()

    def draw(self):
        if self.en_dash == False and self.en_mouv:
            if pyxel.frame_count % 14 < 7:
                pyxel.blt(self.x, self.y, 0, 80, 8, self.w * self.sens, self.h,8)
            else:
                pyxel.blt(self.x, self.y, 0, 96, 8, self.w * self.sens, self.h,8)
                
        elif self.en_dash:
            pyxel.blt(self.x, self.y, 0, 112, 8, self.w * self.sens, self.h,8)
            if pyxel.frame_count % 10 < 5:
                pyxel.blt(self.x, self.y, 0, 128, 8, self.w * self.sens, self.h,8)
            else:
                pyxel.blt(self.x-3, self.y, 0, 144, 8, self.w * self.sens, self.h,8)

        else:
            pyxel.blt(self.x, self.y, 0, 80, 8, self.w * self.sens, self.h,8)
        
        self.draw_solides()
        #self.hitbox.draw()


#*********************************************************************************


class Background:
    def __init__(self, x,y):
        self.x = x
        self.y = y
        self.w = 128
    
    def recentre_x(self):
        self.x = self.x % self.w

    def update(self, perso):
        mouv_1er_plan(self, perso)
        self.recentre_x()

    def draw(self):
        k = 0
        while 128 - (k*128) > -200:
            pyxel.bltm(self.x - (k*128), self.y, 0, 0, 200*8, 128, 256)
            k += 1
        k = 1
        while 128 + (k*128) < 500:
            pyxel.bltm(self.x + (k*128), self.y, 0, 0, 200*8, 128, 256)
            k += 1




#*********************************************************************************

class Ath:
    def __init__(self, perso):
        self.vivant = perso.vivant
        self.mun_dash = perso.mun_dash
        self.score = 0
    
    def update(self, perso):
        self.vivant = perso.vivant
        self.mun_dash = perso.mun_dash
        if self.vivant:
            self.score = pyxel.frame_count

    
    def draw(self):
        if not self.vivant:
            pyxel.cls(0)
            pyxel.text(110,110,"Loser !",pyxel.frame_count%16)
        else:
            pyxel.text(50,10,"dashs : " + str(self.mun_dash),7)
        pyxel.text(150,10,"score : " + str(self.score),7)




#*********************************************************************************


class App:
    
    def __init__(self):
        pyxel.init(256,256,quit_key = pyxel.KEY_DELETE, fps = 60)
        pyxel.load("4.pyxres")
        
        self.perso = Personnage(50, 10)
        self.elems_dangereux = []
        self.background = Background(0,0)
        
        self.nb_frame_solide_spawn = 200
        self.solide_spawn_ready = 0
        
        self.vitesse = 0.4
        
        self.ath = Ath(self.perso)
        
        pyxel.run(self.update, self.draw)
    
    def update_elems_dangereux(self):
        for elem in self.elems_dangereux:
            elem.update(self.perso)
    
    def update_solides(self):
        for elem in self.perso.solides:
            elem.update(self.perso)
    
    def draw_elems_dangereux(self):
        for elem in self.elems_dangereux:
            elem.draw()
    
#     def decalage_ecran(self):
#         decalage = 110
#         if self.perso.x > decalage:
#             self.perso.x -= self.perso.x-decalage
#             for elem in self.perso.solides:
#                 elem.x -= self.perso.x-decalage
#             for solide in self.perso.solides:
#                 solide.x -= self.perso.x-decalage
#             for elem in self.elems_dangereux:
#                 elem.x -= self.perso.x-decalage
#             self.background.x = self.background.x - (self.perso.x-decalage)

    def vitesse_decor(self):
        for elem in self.perso.solides:
            elem.x -= self.vitesse
        for elem in self.elems_dangereux:
            elem.x -= self.vitesse
        self.background.x -= self.vitesse
        if self.perso.au_sol:
            self.perso.x -= self.vitesse
        self.vitesse += 0.001

    def spawn_aléatoire(self): #tous les n pixels parcourus, nouveau spawn
        if self.solide_spawn_ready == 0:
            y = pyxel.rndi(50,258-32)
            w = pyxel.rndi(40,100)
            h = pyxel.rndi(20,40)
            self.perso.solides.append(Solide(260,y,w,h))

            x2 = pyxel.rndi(260, 260+w-8)
            w2 = pyxel.rndi(8,(260+w)-(x2))
            h2 = 0 #sert à rien mais pas le temps là
            self.solide_spawn_ready = self.nb_frame_solide_spawn
            self.elems_dangereux.append(Elem_dangereux(x2,y-7,w2,h2))
        else:
            self.solide_spawn_ready -= 1

    def update(self):
        self.spawn_aléatoire()
        self.perso.update()
        self.vitesse_decor()
        self.background.update(self.perso)
        self.update_solides()
        self.update_elems_dangereux()
        #self.decalage_ecran()
        self.ath.update(self.perso)

    def draw(self):
        pyxel.cls(5)
        self.background.draw()
        self.draw_elems_dangereux()
        self.perso.draw()
        self.ath.draw()


App()