minetest.log("action", "sbz base: init")

local modname = minetest.get_current_modname()
local sbzapi = rawget(_G, modname) or {}
rawset(_G, modname, sbzapi)

local modpath = minetest.get_modpath("sbz_base")
local storage = minetest.get_mod_storage()


-- generate an empty world with only the core block
minetest.log("action", "sbz base: register mapgen")
minetest.register_on_generated(function(minp, maxp, seed)
    if minp.x <= 0 and maxp.x >= 0 and minp.y <= 0 and maxp.y >= 0 and minp.z <= 0 and maxp.z >= 0 then
        local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
        local data = vm:get_data()

        local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
        local c_air = minetest.get_content_id("air")
        local c_stone = minetest.get_content_id("sbz_resources:the_core")

        for z = minp.z, maxp.z do
            for y = minp.y, maxp.y do
                for x = minp.x, maxp.x do
                    local vi = area:index(x, y, z)
                    data[vi] = c_air
                end
            end
        end

        -- place the core
        if minp.x <= 0 and maxp.x >= 0 and minp.y <= 0 and maxp.y >= 0 and minp.z <= 0 and maxp.z >= 0 then
            local vi = area:index(0, 0, 0)
            data[vi] = c_stone
        end

        vm:set_data(data)
        vm:write_to_map()
    end
end)

-- new players always spawn on the core
minetest.log("action", "sbz base: register new player")
minetest.register_on_newplayer(function(player)
    player:set_pos({x = 0, y = 1, z = 0})
end)

-- also allow /core
minetest.register_chatcommand("core", {
    description = "Go back to the core, if you fell off.",
    privs = {},
    func = function(name, param)
        minetest.get_player_by_name(name):set_pos({x = 0, y = 1, z = 0})
        displayDialougeLine(name, "Beamed you back to the Core.")
    end,
})

-- bgm stuffs
local bgm_sounds = {
    "bgm1",
    "bgm2",
    "bgm3",
    "bgm4",
    "bgm5",
}
local bgm_lengths = {
    280,
    207,
    143,
    121,
    151,
}
local function playRandomBGM(player_name)
    local random_index = math.random(1, #bgm_sounds)
    local sound_name = bgm_sounds[random_index]
    local sound_length = bgm_lengths[random_index]
    minetest.sound_play(sound_name, {
        to_player = player_name,
        gain = 1.0,
    })
    minetest.after(sound_length + 1, function() -- i introduce one second of complete silence here, just because
        playRandomBGM(player_name)
    end)
end



-- WHY LUA, WHY
local function table_length(tbl)
    local count = 0
    for _ in pairs(tbl) do
        count = count + 1
    end
    return count
end

minetest.log("action", "sbz base: register join player")
minetest.register_on_joinplayer(function(player)

    -- send welcome messages
    minetest.chat_send_player(player:get_player_name(), "SkyBlock: Zero")
    minetest.chat_send_player(player:get_player_name(), "          by Zander (@zanderdev)")
    
    local num_nodes = table_length(minetest.registered_nodes)
    local num_items = table_length(minetest.registered_craftitems)
    minetest.chat_send_player(player:get_player_name(), "✔ Loaded "..num_nodes.." Nodes and "..num_items.." Items.")
    minetest.chat_send_player(player:get_player_name(), "✔ Current Power Available: " ..power_get().. " Global Power.")
    
    minetest.chat_send_player(player:get_player_name(), "‼ reminder: If you fall off, use /core to teleport back to the core.")

    if not is_achievement_unlocked(player:get_player_name(), "noprogression") then 
        minetest.chat_send_player(player:get_player_name(), "‼ tip: This game follows a semi-linear progression. Type /noprogression to disable the progression-line.")
    end -- 

    -- play bgm
    playRandomBGM(player:get_player_name())

    -- disable the sun, moon, clouds, stars and sky
    player:set_sky({
        base_color = "#000000",
        type = "plain",
        sky_color = {
            day_sky = "#000000",
            day_horizon = "#000000",
            dawn_sky = "#000000",
            dawn_horizon = "#000000",
            night_sky = "#000000",
            night_horizon = "#000000",
            indoors = "#000000",
        },
    }, "plain", {})

    player:set_sun({
        visible = false,
        sunrise_visible = false,
    })

    player:set_moon({
        visible = false,
    })

    player:set_clouds({
        density = 0,
        color = "#00000000",
        ambient = "#00000000",
    })

    player:set_stars({
        visible = false,
    })

    -- set hotbar
    -- player:hud_set_hotbar_itemcount(32) -- nerds only

    -- space gravity yeeeah
    player:set_physics_override({
        gravity = 0.5,
    })
end)

-- for the immersion
minetest.register_on_chat_message(function(name, message)
    local players = minetest.get_connected_players()
    if #players == 1 then
        displayDialougeLine(name, "You talk. But there is no one to listen.")
        return true
    end
    return false
end)

-- everything pitch dark always
minetest.register_globalstep(function(dtime)
    minetest.set_timeofday(0)
end)


-- powermanagement
function power_off()
    return power_get() < 0
end
function power_get()
    return storage:get_int("power")
end
function power_add(power)
    new_power = storage:get_int("power") + power
    storage:set_int("power", new_power)
    displayGlobalDialougeLine("Added some power. The island now has " ..new_power.. " Global Power available.")
end
function power_remove(power)
    new_power = storage:get_int("power") - power
    storage:set_int("power", new_power)

    displayGlobalDialougeLine("Something seems to have lost power. The island now has " ..new_power.. " Global Power available.")

    if new_power < 0 then
        displayGlobalDialougeLine("The grid could not handle this much power draw. All machines have stopped working.")
        minetest.sound_play("power_shutdown", {
            gain = 1.0,
        })
    end
end

-- inter-mod utils
function is_node_within_radius(pos, itemstring, radius)
    for dx = -radius, radius do
        for dy = -radius, radius do
            for dz = -radius, radius do
                local current_pos = {
                    x = pos.x + dx,
                    y = pos.y + dy,
                    z = pos.z + dz
                }
                local node = minetest.get_node(current_pos)
                if node.name == itemstring then
                    return true
                end
            end
        end
    end
    return false
end
function count_nodes_within_radius(pos, itemstring, radius)
    local count = 0
    for dx = -radius, radius do
        for dy = -radius, radius do
            for dz = -radius, radius do
                local current_pos = {
                    x = pos.x + dx,
                    y = pos.y + dy,
                    z = pos.z + dz
                }
                local node = minetest.get_node(current_pos)
                if node.name == itemstring then
                    count = count + 1
                end
            end
        end
    end
    return count
end