--[[
Damage mod. This mod introduces a custom "damage" mechanic for players.
It is completely separate from Luanti's built-in health system,
which is ignored in this game.

Players can have 0 to lzr_damage.MAX_DAMAGE. Damage in this mod is
just a visual effect on the screen but has no gameplay effect on its own.
But it can be queried when the player has reached a certain damage.
Damage is never lethal.
Players may also receive damage of the type "scorched",
which will change the player model and wieldhand texture and wieldhand
to a scorched version until player_damage is reduced to 0.

The player damage can be added to, or reset to 0. When the player has
damage, it will slowly be reduced to 0 again.

Damage is mostly useful as an effect to simulate the player being
"hurt" without
]]

lzr_damage = {}

-- Note this game does NOT use regular damage and health, as defined
-- by Luanti, it's disabled. The "damage" here applies only to this mod!
lzr_damage.MAX_DAMAGE = 4

-- Reduce damage when player didn't take damage every HEAL_TIME
-- seconds.
local HEAL_TIME = 3.0

-- Player damage increases roughly every second the player is in danger,
-- and decreases while out of danger
local player_damage = 0

-- If true, player is using the scorched texture
local player_is_scorched = false

-- Count the time for how many consecutive seconds the player did
-- not take damage yet.
local safe_timer = 0

local damage_screen

local update_damage_screen = function(player)
	if player_damage == 0 then
		if damage_screen then
			player:hud_remove(damage_screen)
			damage_screen = nil
		end
	else
		local texture = "lzr_damage_screen_"..player_damage..".png"
		if not damage_screen then
			damage_screen = player:hud_add({
				type = "image",
				scale = { x = -100, y = -100 },
				text = texture,
				alignment = { x = 1, y = 1 },
				position = { x = 0, y = 0 },
				z_index = -400,
			})
		else
			player:hud_change(damage_screen, "text", texture)
		end
	end
end

local update_player_skin = function(player)
	if player_is_scorched then
		local state = lzr_gamestate.get_state()
		if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
			lzr_hand.set_hand(player, "scorched")
			player_api.set_textures(player, {"character_scorched.png"})
		end
	else
		lzr_hand.set_hand(player, "normal")
		player_api.set_textures(player, {"character.png"})
	end
end

lzr_damage.reset_player_damage = function(player)
	local player_was_scorched = player_is_scorched
	local player_was_damaged = player_damage > 0
	player_damage = 0
	player_is_scorched = false
	if player_was_scorched then
		update_player_skin(player)
	end
	if player_was_damaged then
		update_damage_screen(player)
	end
end

lzr_damage.damage_player = function(player, damage, damage_type)
	safe_timer = 0
	player_damage = player_damage + (damage or 1)
	if player_damage > lzr_damage.MAX_DAMAGE then
		player_damage = lzr_damage.MAX_DAMAGE
	end
	local gain
	if player_damage >= 3 then
		gain = 1
	elseif player_damage >= 2 then
		gain = 0.7
	else
		gain = 0.4
	end
	local texture = "lzr_damage_screen_"..player_damage..".png"
	if player_damage >= 1 and damage_type == "scorch" then
		player_is_scorched = true
		update_player_skin(player)
	end
	update_damage_screen(player)
	minetest.sound_play({name="lzr_damage_damage", gain=gain}, {to_player=player:get_player_name()}, true)
end

local undamage_player = function(player)
	player_damage = math.max(0, player_damage - 1)
	if player_damage == 0 and player_is_scorched then
		player_is_scorched = false
		update_player_skin(player)
	end
	update_damage_screen(player)
end

lzr_damage.get_player_damage = function(player)
	return player_damage
end

-- Slowly reduce damage to 0 when player hasn’t been
-- damaged for a while.
minetest.register_globalstep(function(dtime)
	safe_timer = safe_timer + dtime
	if safe_timer < HEAL_TIME then
		return
	end
	safe_timer = 0

	local players = minetest.get_connected_players()
	local state = lzr_gamestate.get_state()
	if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE and state ~= lzr_gamestate.LEVEL_TEST then
		return
	end
	for p=1, #players do
		local player = players[p]
		undamage_player(player)
	end
end)

-- Reset player damage when entering any state but the level states
lzr_gamestate.register_on_enter_state(function(new_state)
	if new_state ~= lzr_gamestate.LEVEL and new_state ~= lzr_gamestate.LEVEL_COMPLETE and new_state ~= lzr_gamestate.LEVEL_TEST then
		local player = minetest.get_player_by_name("singleplayer")
		if player then
			lzr_damage.reset_player_damage(player)
		end
	end
end)
