--[[
Sprint mod for Minetest by GunshipPenguin

To the extent possible under law, the author(s)
have dedicated all copyright and related and neighboring rights
to this software to the public domain worldwide. This software is
distributed without any warranty.
]]

-- Configuration variables, these are all explained in README.md
SPRINT_SPEED = 1.4
SPRINT_STAMINA = 15

local players = {}

local function set_sprinting(player_name, sprinting) -- sets the state of a player (0=stopped/moving, 1=sprinting)
	local player = minetest.get_player_by_name(player_name)
	if players[player_name] then
		players[player_name]["sprinting"] = sprinting
		if sprinting == true then
			--[[players[player_name].fov = math.min(players[player_name].fov + 0.05, 1.2)
			player:set_fov(players[player_name].fov, true, 0.15)]]
			playerphysics.add_physics_factor(player, "speed", "sprinting", SPRINT_SPEED)
		elseif sprinting == false then
			--[[players[player_name].fov = math.max(players[player_name].fov - 0.05, 1.0)
			player:set_fov(players[player_name].fov, true, 0.15)]]
			playerphysics.remove_physics_factor(player, "speed", "sprinting")
		end
		return true
	end
	return false
end

minetest.register_on_joinplayer(function(player)
	local player_name = player:get_player_name()
	players[player_name] = {
		sprinting = false,
		stamina = SPRINT_STAMINA,
		should_sprint = false,
		fov = 1.0
	}
end)

minetest.register_on_leaveplayer(function(player)
	local player_name = player:get_player_name()
	players[player_name] = nil
end)

minetest.register_globalstep(function(dtime)
	local gametime = minetest.get_gametime()

	-- loop through all connected players
	for player_name, player_info in pairs(players) do
		local player = minetest.get_player_by_name(player_name)
		if player ~= nil then
			-- check if the player should be sprinting
			if player:get_player_control()["aux1"] and player:get_player_control()["up"] then
				players[player_name].should_sprint = true
			else
				players[player_name].should_sprint = false
			end

			-- if the player is sprinting, create particles behind them
			if player_info["sprinting"] == true and gametime % 0.1 == 0 then
				local num_particles = math.random(1, 2)
				local player_pos = player:get_pos()
				local player_node = minetest.get_node(vector.offset(player_pos, 0, -1, 0))
				local node_def = minetest.registered_nodes[player_node.name]
				if node_def and (node_def.drawtype ~= "airlike")
						and (node_def.drawtype ~= "liquid")
						and (node_def.drawtype ~= "flowingliquid") then
					for i = 1, num_particles, 1 do
						minetest.add_particle({
							pos = vector.offset(player_pos,
								math.random(-1, 1) * math.random() / 2,
								0.1,
								math.random(-1, 1) * math.random() / 2
							),
							velocity = vector.new(0, 5, 0),
							acceleration = vector.new(0, -13, 0),
							expirationtime = math.random(),
							size = math.random() + 0.4,
							collisiondetection = true,
							collision_removal = true,
							vertical = false,
							node = player_node,
						})
					end
				end
			end

			-- adjust player states
			if players[player_name]["should_sprint"] == true then --Stopped
				set_sprinting(player_name, true)
			elseif players[player_name]["should_sprint"] == false then
				set_sprinting(player_name, false)
			end

			-- lower the player's stamina by dtime if they are sprinting and set their state to 0 if stamina is zero
			if player_info["sprinting"] == true and not minetest.is_creative_enabled(player) then
				player_info["stamina"] = player_info["stamina"] - dtime
				if player_info["stamina"] <= 0 then
					player_info["stamina"] = 0
					set_sprinting(player_name, false)
				end
			-- increase player's stamina if they aren't sprinting and their stamina is less than SPRINT_STAMINA
			elseif player_info["sprinting"] == false and player_info["stamina"] < SPRINT_STAMINA then
				player_info["stamina"] = player_info["stamina"] + dtime
			end
			-- cap stamina at SPRINT_STAMINA
			if player_info["stamina"] > SPRINT_STAMINA then
				player_info["stamina"] = SPRINT_STAMINA
			end
		end
	end
end)
