
local S = minetest.get_translator(blockbomber.modname)
local function clear_inv(player) end
local function check_for_air_under(player) end
local function get_count_in_inv(player, item) end
local function clear_inv(player) end
local function kill_player(player, cause, arena) end


local bb_powerup = {}
bb_powerup.normal_speed = .5 -- the speed players start at
bb_powerup.speed_boost = .2 -- the speed ech speed boost adds
bb_powerup.speed_snail = .25
bb_powerup.speed_super = 30


local bb_player = {}
bb_player.wear_amt = 300 -- amount of wear to add to bad powerups each globalstep




minetest.register_globalstep(function(dtime)

    for arenaID, arena in pairs(arena_lib.mods[blockbomber.modname].arenas) do
        if arena.in_game and not arena.in_loading and not arena.in_celebration then
            for p_name, stats in pairs(arena.players) do
                if not stats.dead then
                    local player = minetest.get_player_by_name(p_name)


                    -- set animations
                    local ctr = player:get_player_control()


                    if ctr.up == true or ctr.down == true or ctr.left == true or ctr.right == true then
                        if arena.players[p_name].anim ~= "walk" then
                            local visual_obj = blockbomber.get_visual_obj(player)
                            visual_obj:set_animation({x=60,y=100}, 50, 1, true)
                            arena.players[p_name].anim = "walk"
                        end
                    else
                        if arena.players[p_name].anim ~= "stand" then
                            local visual_obj = blockbomber.get_visual_obj(player)
                            visual_obj:set_animation({x=0,y=40}, 20, 1, true)
                            arena.players[p_name].anim = "stand"
                        end
                    end


                    if not player:get_hp() == 300 then
                        player:set_hp(300)
                    end


                    --%%%%%%%%%%%%%%%%%%
                    --collect nearby items
                    --%%%%%%%%%%%%%%%%%%
                    local pos = player:get_pos()
                    local inv = player:get_inventory()

                    local objs = minetest.get_objects_inside_radius(vector.add(pos,vector.new(0,.5,0)), 0.7)
                    for k,v in ipairs(objs) do
                        if v and not ( v:is_player() ) and v:get_luaentity() and v:get_luaentity().name == '__builtin:item' then
                            local stack = ItemStack(v:get_luaentity().itemstring)
                            local stack_name = stack:get_name()
                            local goodgroup = minetest.get_item_group(stack_name, "good")
                            local badgroup = minetest.get_item_group(stack_name, "bad")

                            
                            v:remove()

                            -- play sounds
                            if goodgroup == 1 then 
                                minetest.sound_play({
                                    name = "yippee",
                                    gain = 1.0,
                                }, {
                                    pos = player:get_pos(),
                                    max_hear_distance = 32,  -- default, uses an euclidean metric
                                }, true)
                            end
                            if badgroup == 1 then 
                                minetest.sound_play({
                                    name = "eew",
                                    gain = .1,
                                }, {
                                    pos = player:get_pos(),
                                    max_hear_distance = 32,  -- default, uses an euclidean metric
                                }, true)
                            end

                            -- if there is a bad powerup in the inv, remove it, whenever you get any powerup
                            local list = inv:get_list("main")
                            for l, m in ipairs(list) do
                                local stack = m
                                local i_name = stack:get_name()
                                if i_name == "bb_powerup:superfast" or
                                    i_name == "bb_powerup:slow" or
                                    i_name == "bb_powerup:weird_control" or
                                    i_name == "bb_powerup:party" or
                                    i_name == "bb_powerup:no_placebomb" then
                
                                    stack:take_item()
                                    inv:set_stack("main", l, stack)
                                end
                            end

                            -- if stack_name == "bb_powerup:resurect" then
                            --     -- resurrect all players!!!
                            --     bb_player.resurrect_all_players()                   
                            
                            if stack_name == "bb_powerup:throw" or
                                stack_name == "bb_powerup:kick" or
                                stack_name == "bb_powerup:extra_life" or
                                stack_name == "bb_powerup:multidir" then

                                    -- if the item is one of the pernament powerups then only add the item if the player doesnt already have one
                                    
                                if not(inv:contains_item("main", stack_name)) then
                                    inv:add_item("main", stack)
                                end

                            else
                                -- for everything else, we can just add the item
                                inv:add_item("main", stack)
                            end
                        end
                    end


                    
                    --%%%%%%%%%%%%%%%%%%
                    --set player speed
                    --%%%%%%%%%%%%%%%%%%

                    local snail = false
                    local superfast = false
                    local num_speed_boosts = get_count_in_inv(player,"bb_powerup:extra_speed")
                    -- determine the value of the above variables


                    if inv:contains_item("main", ItemStack("bb_powerup:slow")) then
                        snail = true
                    end
                    if inv:contains_item("main", ItemStack("bb_powerup:superfast")) then
                        superfast = true
                    end

                    -- if they have a slow modifier then set their speed to slow
                    if snail then
                        arena.players[p_name].speed = bb_powerup.speed_snail
                    -- if they have a super fast modifier then set their speed to very fast
                    elseif superfast then
                        arena.players[p_name].speed = bb_powerup.speed_super
                    -- else just set their speed based on the number of speed boosts they have collected
                    else
                        local normal_speed = bb_powerup.normal_speed --.75
                        local speed_boost = bb_powerup.speed_boost -- .5
                        local newspeed = normal_speed + num_speed_boosts * speed_boost
                        arena.players[p_name].speed = newspeed
                    end

                    player:set_physics_override({speed = arena.players[p_name].speed})




                    
                    --%%%%%%%%%%%%%%%%%%
                    --inventory sorting
                    --%%%%%%%%%%%%%%%%%%
                
                    local inv = player:get_inventory()
                    local list = inv:get_list("main")
                    
                    local bombs = nil
                    local power = nil
                    local speed = nil
                    local life = nil
                    local throw = nil
                    local kick = nil
                    local multidir = nil
                    local bad = nil
                    local new_list = {}
                    for _,stack in pairs(list) do
                        if stack:get_name() == "bb_powerup:extra_bomb" then
                            bombs = stack                
                        elseif stack:get_name() == "bb_powerup:extra_power" then
                            power = stack                
                        elseif stack:get_name() == "bb_powerup:extra_speed" then
                        speed = stack                
                        elseif stack:get_name() == "bb_powerup:extra_life" then
                            life = stack                
                        elseif stack:get_name() == "bb_powerup:throw" then
                            throw = stack                
                        elseif stack:get_name() == "bb_powerup:kick" then
                            kick = stack                 
                        elseif stack:get_name() == "bb_powerup:multidir" then
                            multidir = stack                 
                        elseif stack:get_name() ~= "" then
                            bad = stack 
                        end
                    end

                    local counter = 1

                    clear_inv(player)
                    
                    if bombs ~= nil then
                        inv:set_stack("main", counter, bombs)
                        counter = counter + 1
                    end
                    if power ~= nil then
                        inv:set_stack("main", counter, power)
                        counter = counter + 1
                    end
                    if speed ~= nil then 
                        inv:set_stack("main", counter, speed)
                        counter = counter + 1
                    end
                    if life ~= nil then
                        inv:set_stack("main", counter, life)
                        counter = counter + 1
                    end
                    if throw ~= nil then
                        inv:set_stack("main", counter, throw)
                        counter = counter + 1
                    end
                    if kick ~= nil then 
                        inv:set_stack("main", counter, kick)
                        counter = counter + 1
                    end
                    if multidir ~= nil then 
                        inv:set_stack("main", counter, multidir)
                        counter = counter + 1
                    end
                    if bad ~= nil then
                        inv:set_stack("main", counter, bad)
                        counter = counter + 1
                    end
                    local hotbar = counter - 1

                    player:hud_set_hotbar_itemcount(hotbar)
                    player:hud_set_hotbar_image("bb_player_gui_hotbar_"..hotbar..".png")
                    


                    
                    --%%%%%%%%%%%%%%%%%%
                    --add wear to time limited powerups
                    --%%%%%%%%%%%%%%%%%%

                    local inv = player:get_inventory()
                    for  v = 1 , inv:get_size("main") do
                        local stack = inv:get_stack("main", v)
                        local i_name = stack:get_name()
                        if i_name == "bb_powerup:superfast" or
                            i_name == "bb_powerup:slow" or
                            i_name == "bb_powerup:weird_control" or
                            i_name == "bb_powerup:party" or
                            i_name == "bb_powerup:no_placebomb" then

                            stack:add_wear(bb_player.wear_amt)
                            inv:set_stack("main", v, stack)
                        end

                    end

                    
                    --%%%%%%%%%%%%%%%%%%
                    --check for nearby explosions, kill players too close
                    --%%%%%%%%%%%%%%%%%%

                    -- if arena.players[p_name].alive then
                    local pos = player:get_pos()
                    local near_exp = false
                    local pos1 = vector.add(pos, vector.new(-.5,-.2,-.5))
                    local pos2 = vector.add(pos, vector.new(.5,1,.5))
                
                    local objs = minetest.get_objects_in_area(pos1, pos2)
                    local o = nil -- we will store the explosion objectref in case we need to remove it
                    for k,v in ipairs(objs) do
                        if v and not ( v:is_player() ) and v:get_luaentity() and v:get_luaentity().name == "block_bomber_mg:explosion" then
                            near_exp = true
                            o = v
                        end
                    end
                    if near_exp then
                        
                        -- if there was a nearby explosion, kill them if they dont have extra life. remove it if they do.
                        local inv = player:get_inventory()
                        if inv:contains_item("main", "bb_powerup:extra_life") == true then
                            
                            if o then -- remove the killing explosion
                                o:remove()
                            end
                            inv:remove_item("main", "bb_powerup:extra_life")
                        else
                            --update the players respawn point
                            
                            local pmeta = player:get_meta()
                            pmeta:set_string("spawn", minetest.serialize( player:get_pos() )) 

                            minetest.sound_play({
                                name = "death",
                                gain = 2.0,
                            }, 
                            {
                                pos = player:get_pos(),
                                max_hear_distance = 32,  -- default, uses an euclidean metric
                            }, true)

                            kill_player(player,"explosion", arena)

                        end
                    end

                    --%%%%%%%%%%%%%%%%%%
                    --check for air under player, move them to center of block and kill them
                    --%%%%%%%%%%%%%%%%%%

                    local pos = player:get_pos()
                    
                    if check_for_air_under(player) then
                        local p_props = player:get_properties()

                        minetest.sound_play({
                            name = "GameOver",
                            gain = 1.0,
                        }, {
                            pos = player:get_pos(),
                            gain = 1,  -- default
                            max_hear_distance = 10,  
                        }, true)

                        -- TODO: play falling sound
                        kill_player(player,"falling", arena)

                    end
                end
            end
        end
    end
end)





function check_for_air_under(player)
    --return true if the player should fall out and lose the game
    local pos = player:get_pos()
    -- checkdistance to check for solid nodes under player in. it defines the distance players may step off a ledge without falling.
    local cdist = .2
    local check_for_floor = 30 -- distance to detect if player can fall to floor below instead of falling out.
    --player pos is at the floor of the player's hitbox, where they are standing, in the center of the x,z
    -- u_pos is the pos under that
    local u_pos = vector.add(pos, vector.new(0,-.7,0))
    --iff all checkpoints have air, then the player has stepped off

    if minetest.get_node(vector.add(u_pos,vector.new(-cdist,0,-cdist))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(-cdist,0,0))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(-cdist,0,cdist))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(0,0,-cdist))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(0,0,0))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(0,0,cdist))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(cdist,0,-cdist))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(cdist,0,0))).name == "air" and
        minetest.get_node(vector.add(u_pos,vector.new(cdist,0,cdist))).name == "air" then

            local floor_found = false
            for i = 0,check_for_floor do
                if minetest.get_node(vector.add(u_pos,vector.new(0,-i,0))).name ~= "air" then 
                    floor_found = true
                end
            end

            if floor_found then
                return false
            else
                return true
            end
    else
        return false
    end
end












function clear_inv(player)
    local inv = player:get_inventory()
    local list = inv:get_list("main")
    for k, v in pairs(list) do
        inv:remove_item("main", v)
    end
end





function get_count_in_inv(player, item)
    local count = 0
    local inv = player:get_inventory()
    local lists = inv:get_lists()
    for listname,itemstacklist in pairs(lists) do
        for _,stack in pairs( itemstacklist ) do
            if stack:get_name() == item then
                count = count + stack:get_count()
            end
        end
    end
    return count

end







function kill_player(player, cause, arena)
    local p_name = player:get_player_name()
    local death_pos = player:get_pos()
    local death_dir = player:get_look_horizontal()
    cause = cause or "unknown"

    clear_inv(player)

    -- add a fake player object for the death animation
    local look_dir = player:get_look_horizontal()
    local p_props = player:get_properties()

    local static_data = minetest.write_json({
        _falling = cause == "falling",
        _arena_name = arena.name,
        _match_id = arena.match_id
    })
    local obj = minetest.add_entity(vector.add(vector.round(death_pos), vector.new(0,-.5,0)) ,"block_bomber_mg:dead_player", static_data)

    -- arena.players[p_name].dead_marker = obj
    p_props.physical = false
    obj:set_properties(p_props)
    obj:set_yaw(look_dir)
    -- set animation
    if cause == "falling" then
        obj:set_animation({x=110,y=150}, 20, 2, false)
    else
        obj:set_animation({x=170,y=210}, 90, 2, false)
    end

    arena.players[p_name].dead = true
    arena.players[p_name].cause = cause


end


function clear_inv(player)
    local inv = player:get_inventory()
    local list = inv:get_list("main")
    for k, v in pairs(list) do
        inv:remove_item("main", v)
    end
end
