-- local arcade_config = require("arcade_config")
cw = arcade_config.character_width
ch = arcade_config.character_height

require "dead"

-- abad={ x=40, y=24, 
--        flip=false,
--        frame=1,
--        wait=0,
--        respawning=0,
--        hab=10,
--        vides=3,
--        energia=40,
--        falling=0,
--        step=0, 
--        mustep=1,
--        hurting=0,
--        update=nil,
--        jumpfwd=false,
--        anim={0,1,0,2},
--        bb={x=8,y=0,w=16,h=32},
--        safe={hab=10,x=40,y=24} }

abad={}

function abad_nop()
end

function abad_init()
    abad={ name="abad",
           id="abad",
           x=40, y=24,
           w=32, h=32,
           flip=false, 
           frame=1,
           wait=0,
           respawning=0,
           hab=10,
           vides=3,
           energia=6,
           max_energia=6,
           falling=0,
           step=0,
           mustep=1,
           stairs_flip=false,
           stairs_moves=0, --contador de moviments dins de les escales
           draw=abad.draw,
           hurting=0,
           update=nil,
           save_update=nil,
           jumpfwd=false,
           step_length=1,
           vmove_space=1,
           max_jump_height=24,
           jump_height=0,
           jump_in_half_block=0,
           jump_in_half_block_used = false,
           max_shoot_cooldown=24,
           cacau_power=1,
           cacau_num_shots=1,
           cacau_type_shot=type_shot.linear,
           shoot_cooldown=25,
           anim={0,1,0,2},
           bb={x=8,y=0,w=16,h=32},
           safe={hab=10,x=40,y=24},
           move=abad.move,
           mood="normal"}
    abad.update=abad_state_normal
    abad.objects={}
end

function abad:move( x, y )
    self.x = x
    self.y = y
    local hab,xx, yy = coords.world_to_tile(x, y)
    self.hab = hab
end

function abad_add_mood(abad_x, spr_off_x, abad_y, spr_off_y, flip, mood)
    flip = flip or false
    mood = mood or "normal"
    
    if flip then
        abad_x = abad_x-15+4
    end
    
    if mood~="normal" then
        if mood=="sorpresa" then
            draw.surf(240,0,11,4,abad_x+16-spr_off_x,abad_y+5-spr_off_y,11,4,flip)
        elseif mood=="enfadat" then
            draw.surf(240,4,11,4,abad_x+16-spr_off_x,abad_y+5-spr_off_y,11,4,flip)
        elseif mood=="interessant" then
            draw.surf(240,8,11,4,abad_x+16-spr_off_x,abad_y+5-spr_off_y,11,4,flip)
        end
    end
end

function abad:draw()
    local flip = abad.flip
    local x, y = viewp:screen_coords(self.x, self.y)
    if abad.update==abad_state_stairs then
        -- flip=abad.stairs_flip
        -- -- flip=(((abad.x>>1)+(abad.y>>1))%2)==0
        if math.abs(abad.stairs_moves-(abad.x+abad.y))>12 then
            abad.stairs_moves = abad.x+abad.y
            abad.flip = not abad.flip
        end
        flip = abad.flip
        -- if ((abad.x+abad.y)%12)==0 then 
        --     abad.stairs_flip=not abad.stairs_flip 
        -- end 
        
        -- local msg = "-- "..abad.x.." "..abad.y
        -- if flip then msg = "FLIP"..abad.x.." "..abad.y end
        -- -- msg_print(0,35,msg,true)
    end
    
    if (abad.respawning==0) or (math.floor(abad.respawning/15)%2==0) then
        draw.surf(abad.frame*abad.w,0,abad.w,abad.h,x,y,abad.w,abad.h,flip)
        -- caminant, parat, disparant o saltant
        if abad.frame<=3 or abad.frame==6 then
            abad_add_mood(x,0,y,0,flip,abad.mood)
        end
    end

    if abad.respawning > 0 then 
        abad.respawning=abad.respawning-1
    end
    
    -- draw.rect(x+abad.bb.x,y+abad.bb.y,abad.bb.w,abad.bb.h,3)
end

function abad_make_safe( force )
    force = force or false
    local hab, xx, yy = coords.world_to_tile(abad.x, abad.y)
    if abad.safe.hab~=hab or force then
        abad.safe.hab=hab
        abad.safe.x=xx
        abad.safe.y=yy
    end
end

function abad_heal(howmuch)
    abad.energia = abad.energia + howmuch
    if abad.energia>abad.max_energia then
        abad.energia = abad.max_energia
    end
end

function abad_hurt(howmuch)
    -- howmuch = 0
    if abad.hurting == 0 and abad.respawning==0 then
        sound.play(audio_abad_hit)
        abad.energia=abad.energia-howmuch
		-- abad.energia=abad.energia
        if abad.energia<=0 then
            abad.vides=abad.vides-1
            if abad.vides==0 then
                --final de la partida
                dead.start()
                music.play(audio_game_over,0)
            else
                music.play(audio_life_lost,0)
                abad.energia=abad.max_energia
                -- abad.hab=abad.safe.hab
                -- abad.x=abad.safe.x
                -- abad.y=abad.safe.y
                local abad_x, abad_y = coords.room_to_world ( abad.safe.hab, abad.safe.x, abad.safe.y )
                abad:move(abad_x, abad_y)
                abad.hurting=60
                abad.update=abad_state_normal
                abad.bb.y=0
                abad.bb.h=32
                abad.respawning=240
                surf.cls(3)
            end
        else
            surf.cls(3)
        end
    end
    if abad.respawning==0 then abad.respawning = 120 end
end

function abad_do_jump ( jumpfwd )
    jumpfwd = jumpfwd or false
    abad.jump_height = 0
    abad.update=abad_state_jumping
    abad.step=0
    abad.jumpfwd=jumpfwd
    if abad.jump then
        sound.stop(abad.jump)
        abad.jump=nil
    end
    sound.play(audio_abad_jump)
end

function abad_shot_cacau ()
    if cacau:available(abad.cacau_num_shots, abad.cacau_type_shot) then
        sound.play(audio_abad_shot)
        abad.save_update=abad.update
        abad.update=abad_state_fire
        abad.wait=0
        -- cacau.init(abad.hab,abad.x+8,abad.y+8,abad.flip)
        cacau.init(abad.x+abad.bb.w, abad.y+(abad.bb.h>>1), abad.flip, abad.cacau_power, abad.cacau_num_shots, abad.cacau_type_shot)
    end
end

function abad_jump()
    local vspace = abad.vmove_space
    -- Els dos punts de dalt de l'abad
    local x1_check = abad.x+abad.bb.x
    local x2_check = abad.x+abad.bb.x+abad.bb.w
    local y_check = abad.y-vspace
    
    -- Comprovar on està pegant
    local tile1_hit_type= arc_check_tile(x1_check, y_check )
    local tile2_hit_type= arc_check_tile(x2_check, y_check)
    local not_block_tile = tile1_hit_type ~= tiletype.block and tile2_hit_type ~= tiletype.block
    local switch_tile = tile1_hit_type == tiletype.switch or tile2_hit_type == tiletype.switch
-- print("JUMP > "..x1_check..", "..x2_check..", "..y_check)
-- print("T1= "..tile1_hit_type.." / T2= "..tile2_hit_type.." / SW= "..tiletype.switch)
-- local msg = "BLOCK TILE HITTED"
-- if not_block_tile then msg="not block" end
-- print(msg)
    -- Fer l'acció que correspon
    if not_block_tile then
        --if switch_tile then
        --    local xx= x2_check
        --    local yy= y_check
        --    -- Executar el switch
        --    if tile1_hit_type == tiletype.switch then
        --        xx= x1_check
        --    end
        --    switches.start(xx, yy)
        --else
        --    abad.y=abad.y-vspace
        --end
        if switch_tile then
            -- Si la posició actual no es dins del tile, avançar per a colisionar
            if (arc_check_tile(x1_check, abad.y)~= tiletype.switch and
                arc_check_tile(x2_check, abad.y)~= tiletype.switch)
            then
                abad.y=abad.y-vspace 
            end
        else
            abad.y=abad.y-vspace 
        end
    else
        local tile1_hit = arc_get_tile(x1_check, y_check )
        local tile2_hit = arc_get_tile(x2_check, y_check)
        local half_block1 = mapa_is_half_block_tile(map_to_editor_tile(tile1_hit))
        local half_block2 = mapa_is_half_block_tile(map_to_editor_tile(tile2_hit))
        local full_block1 = tile1_hit_type == tiletype.block and not half_block1
        local full_block2 = tile2_hit_type == tiletype.block and not half_block2
        local full_block = full_block1 and full_block2
        local half_block = half_block1 or half_block2
-- print("BLOCK TILE")
-- msg = tile1_hit.." "..tile2_hit.." >> "
-- if half_block1 then msg= msg.."half_block1 " end
-- if half_block2 then msg= msg.."half_block2 " end
-- if full_block1 then msg= msg.."full_block1 " end
-- if full_block2 then msg= msg.."full_block2 " end
-- if full_block  then msg= msg.."full_block " end
-- if half_block  then msg= msg.."half_block " end
-- if abad.jump_in_half_block_used then msg= msg.."jump_in_half_block_used " end
-- print(msg)
        -- Si ninguno dels tiles tocats es un block complet
        -- i almenys un dels tiles tocats es mig tile
        -- permetre continuar en el salt
        if not full_block and half_block then
            if abad.jump_in_half_block==0 and not abad.jump_in_half_block_used then
                abad.jump_in_half_block = arcade_config.tiles_height / 2
-- print(abad.jump_in_half_block)
            end
            if abad.jump_in_half_block>0 then
                abad.y=abad.y-vspace
                abad.jump_in_half_block = abad.jump_in_half_block-1
                abad.jump_in_half_block_used = true
            end
        end
    end
    abad.jump_height = abad.jump_height+1
end

function abad_land ()
    -- Els dos punts de baix de l'abad
    local x1_check = abad.x+abad.bb.x
    local x2_check = abad.x+abad.bb.x+abad.bb.w
    local y_check = abad.y+abad.bb.h
    
    -- Comprovar on està aterrant
    local tile1_hit= arc_check_tile(x1_check, y_check )
    local tile2_hit= arc_check_tile(x2_check, y_check)
    local floor_tile = tile1_hit>=tiletype.half or tile2_hit>=tiletype.half
    
    -- Encara que siga un tile de piso s'ha de comprovar que 
    -- la y es un múltiple de l'alt dels tiles
    local over_tile = (y_check & 0xF) == 0 
    
    local can_land = floor_tile and over_tile
    
    if can_land then
        abad.jump_in_half_block_used = false
        abad.jump_height = 0
    end
    
    return can_land
end

function abad_in_stairs(next_x, next_y)
    next_x = next_x or 0
    next_y = next_y or 0
    local result = false
    
    -- local x1_check = abad.x+abad.bb.x+next_x
    -- local x2_check = abad.x+abad.bb.x+abad.bb.w+next_x
    -- local y1_check = abad.y+next_y
    -- local y2_check = abad.y+abad.bb.h+next_y
    -- 
    -- if arc_check_tile(x1_check, y1_check)==tiletype.stair or
    --    arc_check_tile(x2_check, y1_check)==tiletype.stair or
    --    arc_check_tile(x1_check, y2_check)==tiletype.stair or
    --    arc_check_tile(x2_check, y2_check)==tiletype.stair
    -- then
    --     return true
    -- end
    
    local x1_check = abad.x+(abad.w/2)+next_x
    local y1_check = abad.y+next_y
    local y2_check = abad.y+abad.bb.h+next_y
    
    if arc_check_tile(x1_check, y1_check)==tiletype.stair or
       arc_check_tile(x1_check, y2_check)==tiletype.stair
    then
        result = true
    end    
    
    return result
end

function abad_in_floor(next_x, next_y)
    local x1_check = abad.x+abad.bb.x+next_x
    local x2_check = abad.x+abad.bb.x+abad.bb.w+next_x
    local y2_check = abad.y+abad.bb.h+next_y
    if arc_check_tile(x1_check, y2_check)==tiletype.block or
       arc_check_tile(x2_check, y2_check)==tiletype.block 
    then
        return true
    end
    
    return false
end

function abad_advance()
    local step_length=abad.step_length; --lo que avança l'abad cada pas
    local limit=tiletype.block
    
    if abad.update~=abad_state_walking then 
        limit=tiletype.half 
    end

    local x_check = abad.x+abad.bb.x+abad.bb.w+step_length
    if abad.flip then 
        step_length = -step_length 
        x_check = abad.x+abad.bb.x+step_length
    end
    -- local y_check = abad.y+abad.bb.h-4
    local y_check = abad.y+abad.bb.h-1
    
    if arc_check_tile(x_check, y_check)<limit then
        abad.x=abad.x+step_length
    end
    
    -- if arc_check_tile(x_check,y_check)==tiletype.stair then
    --     print("STAIRS "..math.random(50))
    --     if abad.update~=abad_state_stairs and controller:check("up") 
    --     then
    --     print("UPDATE STAIRS")
    --         abad.update=abad_state_stairs
    --     end
    -- elseif abad.update==abad_state_stairs then
    --     abad.update=abad_state_normal
    --     abad.frame=0
    -- end
    
    if not abad_in_stairs() and 
       abad.update==abad_state_stairs 
    then
        abad.update=abad_state_normal
        abad.frame=0
    end
    
    local hab,xx, yy = coords.world_to_tile(abad.x, abad.y)
    abad.hab = hab
end

function abad_move_down()
    if abad_in_stairs(0,1) and not abad_in_floor(0,0) then
        abad.update=abad_state_stairs
    else
        abad.update=abad_state_crouch
    end
end

-- Controlador principal de l'abad
function abad_state_normal()
    abad.frame=0
    abad.wait=0
    abad.step=0
    if abad.shoot_cooldown<abad.max_shoot_cooldown then abad.shoot_cooldown = abad.shoot_cooldown + 1 end
    abad.jumpfwd=false
    abad.jump_height = 0
    if abad.hurting > 0 then 
        abad.hurting=abad.hurting-1
        return
    end

    if abad.falling>0 then
        local altura_piso = (mapa_room_rows*arcade_config.tiles_height)
        local pisos_caiguts = math.floor(abad.falling/altura_piso)
        local damage = pisos_caiguts*2
        if damage>0 then
            if damage>abad.energia then damage=abad.energia end
            abad_hurt(damage)
        end
        abad.falling=0
    end
    
    abad_make_safe()

    if controller:check("up") and abad_in_stairs() then
        abad.update=abad_state_stairs
    elseif controller:check("down") then
        abad_move_down()
    elseif controller:check("right") then
        abad.update=abad_state_walking
        abad.flip=false
    elseif controller:check("left") then
        abad.update=abad_state_walking
        abad.flip=true
    elseif controller:check("jump") then
        abad_do_jump()
    --elseif btn(KEY_Z) then
    --    abad.respawning=240
    elseif controller:check("shoot") then
        abad_shot_cacau()
    end
end

function abad_state_crouch()
    abad.bb.y=8
    abad.bb.h=24
    abad.frame=5
    abad.wait=0
    abad.step=0
    abad.jumpfwd=false
    abad.jump_height=0
    if not controller:check("down") then
        abad.update=abad_state_normal
        abad.bb.y=0
        abad.bb.h=32
    end
    
end

function abad_state_fire()
    abad.frame=6
    abad.wait=abad.wait+1

    if abad.wait==6 then
        abad.wait=0
        if abad.save_update==nil then
            abad.update=abad_state_normal
        else
            abad.update=abad.save_update
            abad.save_update=nil
        end
    end
    
    if abad.save_update~=nil and abad.save_update~=abad_state_normal then abad_advance() end
end

function abad_state_walking()
    -- Limitar la velocitat de moviment
    abad.wait=abad.wait+1

    -- representació del moviment
    if abad.wait==6 then
        abad.wait=0
        abad.step=(abad.step+1)%2
        if abad.step==0 then
            sound.play(audio_abad_step[abad.mustep],32)
            abad.mustep = abad.mustep + 1
            if abad.mustep == 5 then abad.mustep=1 end
        end
        abad.frame=abad.anim[abad.step+1]        
    end
    -- Comprovar dos punts de contacte de l'abad en el piso a vore si cau
    local x1_check = abad.x+abad.bb.x
    local x2_check = x1_check+abad.bb.w
    local y_check = abad.y+abad.bb.h; -- base de l'abad
    local tile1 = arc_check_tile(x1_check,y_check)
    local tile2 = arc_check_tile(x2_check,y_check)
    if tile1==tiletype.void and tile2==tiletype.void then
        abad.update=abad_state_falling
        return
    end
    
    abad_advance()

    -- guardar punt segur
    abad_make_safe()

    -- Gestionar accions mentre es camina
    if controller:check("jump") then
        abad_do_jump(true); -- jumping forward
        return
    elseif controller:check("down") then
        abad_move_down()
    elseif controller:check("shoot") then
        abad_shot_cacau()
    end

    -- "Flipar" a l'Abad
    if controller:check("right") then
        abad.flip=false
    elseif controller:check("left") then
        abad.flip=true
    elseif abad.wait==0 then
        abad.update=abad_state_normal
    end

end

function abad_state_jumping()
    local step_length = abad.step_length
    abad.frame=3
    abad.wait=abad.wait+1

    abad.wait=0

    if abad.jump_height<abad.max_jump_height then
        abad_jump()
    else
        -- Canviar a mode caure
        abad.update=abad_state_falling
        abad.jump=sound.play(audio_abad_fall)
    end
    abad.step=abad.step+1

    if abad.jumpfwd then abad_advance() end
    
    if abad.objects.llibre and controller:check("shoot") then
        abad_shot_cacau()
    end

end

function abad_state_falling()
    abad.frame=3
    abad.wait=abad.wait+1

    if abad.wait==6 then
        abad.wait=0

        -- if abad.y<32 then
        --     if (abad.y+16)&7==0 and 
        --        (arc_check_tile(abad.x+4,abad.y+16)>=tiletype.half or 
        --         ((abad.x+4)&7~=0 and 
        --           arc_check_tile(abad.x+12,abad.y+16)>=tiletype.half)
        --         ) then
        --         abad.update=abad_state_normal
        --         return
        --     end
        --     abad.y=abad.y+2
        --     abad.falling=abad.falling+1
        -- else
        --     abad.hab=abad.hab+10
        --     -- imp.reset()
        --     abad.y=0
        -- end
    end
    
    if abad_land() then
        abad.update=abad_state_normal
        return
    end    
    
    abad.y=abad.y+1
    abad.jump_height = abad.jump_height-1
    abad.falling=abad.falling+1
    if abad.jumpfwd then abad_advance() end
    
    if abad.objects.llibre and controller:check("shoot") then
        abad_shot_cacau()
    end
end

function abad_state_stairs()
    abad.frame=4
    abad.wait=abad.wait+1
    local moved = false

    --local x1_check = abad.x+abad.bb.x
    --local x2_check = abad.x+abad.bb.x+abad.bb.w-1
    --local y_check = abad.y+abad.bb.h
    
    if controller:check("right") then
        abad.flip=false
        abad_advance()
        moved = true
    elseif controller:check("left") then
        abad.flip=true
        abad_advance()
        moved = true
    elseif controller:check("up") then
        --y_check = y_check - 1
        --if arc_check_tile(x1_check,y_check)==tiletype.stair and 
        --   arc_check_tile(x2_check,y_check)==tiletype.stair then
        --    abad.y=abad.y-1
        --    if abad.wait==6 then sound.play(audio_low) end
        --end
        if abad_in_stairs(0,-1) then
            abad.y=abad.y-1
            moved = true
        end
    elseif controller:check("down") then
        -- y_check = y_check + 1
        -- if arc_check_tile(x1_check,y_check)==tiletype.stair and 
        --    arc_check_tile(x2_check,y_check)==tiletype.stair then
        --     abad.y=abad.y+1
        --     if abad.wait==6 then sound.play(audio_low) end
        -- end
        if abad_in_stairs(0,1) and not abad_in_floor(0,0) then
            abad.y=abad.y+1
            moved = true
        else
            --abad.update=abad_state_normal
        end
    end
    if moved and abad.wait==6 then sound.play(audio_low) end
    
    if abad.wait==6 then abad.wait=0 end
end