Skip to content
Snippets Groups Projects
Select Git revision
  • 24df8af363013eb8c6667b17d23cdd8eb9d58d6d
  • main default protected
  • 1-kalenderimport
  • 1.2
  • 1.1
  • 1.0
6 results

taxonomy.html

Blame
  • Forked from FS Info TU Dortmund / Öffentlichkeit / anubis
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    death.lua 8.13 KiB
    
    -- adapted from https://github.com/pandorabox-io/pandorabox_custom/blob/master/death.lua
    local WAYPOINT_EXPIRES_SECONDS = tonumber(minetest.settings:get("kif_custom.death.waypoint_expires_seconds")) or 60 * 60
    local WAYPOINT_EXPIRES_SECONDS_CREATIVE = tonumber(minetest.settings:get("kif_custom.death.waypoint_expires_seconds_creative")) or 5 * 60
    
    local UPDATE_INTERVAL = tonumber(minetest.settings:get("kif_custom.death.update_interval")) or 5
    local WAYPOINT_SATURATION = tonumber(minetest.settings:get("kif_custom.death.waypoint_saturation")) or 1
    
    local MARKERS_FILE = minetest.get_worldpath().."/death_markers.json"
    
    
    -- table for deaths indexed by player name and pos
    local death_markers = {}
    local dirty = false
    local WRITEBACK_INTERVAL_SEC = 10
    
    -- table to remember which hud elements we know and manage (per player and pos)
    local managed_hud_ids = {}
    
    -- color calculation got a bit crazy, so let's cache these...
    local color_cache = {}
    
    
    local read_json_file = function(path)
    	local file = io.open(path, "r")
    	local content = {}
    	if file then
    		local json = file:read("*a")
    		content = minetest.parse_json(json or "[]") or {}
    		file:close()
    	end
    	return content
    end
    
    local write_json_file = function(path, content)
    	local file = io.open(path,"w")
    	local json = minetest.write_json(content)
    	if file and file:write(json) and file:close() then
    		return true
    	else
    		return false
    	end
    end
    
    death_markers = read_json_file(MARKERS_FILE)
    
    local mark_dirty_and_schedule_writeback = function()
    	if not dirty then
    		dirty = true
    		minetest.after(WRITEBACK_INTERVAL_SEC, function()
    			if dirty then
    				write_json_file(MARKERS_FILE, death_markers)
    				dirty = false
    			end
    		end)
    	end
    end
    
    
    -- add something to the bones on_punch to remove markers when the bones are picked up
    
    local bones_def = minetest.registered_items["bones:bones"]
    assert(bones_def)
    
    local bones_on_punch = bones_def.on_punch
    assert(bones_on_punch)
    assert(type(bones_on_punch) == "function")
    
    minetest.override_item("bones:bones", {
    	on_punch = function(pos, node, player)
    		-- call original function
    		bones_on_punch(pos, node, player)
    
    		local player_name = player:get_player_name()
    		local pos_string = minetest.pos_to_string(pos)
    
    		if death_markers[player_name] ~= nil and death_markers[player_name][pos_string] ~= nil then
    			minetest.after(1, function()
    				if minetest.get_node(pos).name ~= "bones:bones" then
    					death_markers[player_name][pos_string] = nil
    					update_hud_markers(player_name)
    				end
    			end)
    		end
    	end
    })
    
    
    minetest.register_on_shutdown(function()
    	if dirty then
    		write_json_file(MARKERS_FILE, death_markers)
    		dirty = false
    	end
    
    	-- clean up markers (not sure if this makes sense, but I got weird results before, so...)
    	for player_name, hud_ids in pairs(managed_hud_ids) do
    		local player = minetest.get_player_by_name(player_name)
    
    		if player ~= nil then
    			for pos_string, marker in pairs(hud_ids) do
    				player:hud_remove(hud_id)
    			end
    		end
    		managed_hud_ids[player_name] = nil
    	end
    end)
    
    
    local interpolate = function(a, b, t)
    	return t*(b-a) + a
    end
    
    local calculate_color = function(t)
    	-- clamp t between 0 and 1, in steps of 0.01
    	t = math.max(0, math.min(1, math.floor(t * 100 + 0.5) / 100))
    
    	if color_cache[t] == nil then
    		-- helper variables
    		local t2 = t^2	-- t squared
    		local it = 1 - t	-- inverse t
    		local it2 = it^2	-- inverse t squared
    
    		local r = t2
    		local g = 2*t * it
    		local b = it2
    		local avg = math.sqrt(r^2 + g^2 + b^2)
    
    		r = interpolate(avg, r, WAYPOINT_SATURATION)
    		g = interpolate(avg, g, WAYPOINT_SATURATION)
    		b = interpolate(avg, b, WAYPOINT_SATURATION)
    
    		local white_start = it2^2
    		local dimming = 1 - t^8
    
    		r = (r * (1-white_start) + white_start) * dimming
    		g = (g * (1-white_start) + white_start) * dimming
    		b = (b * (1-white_start) + white_start) * dimming
    
    		-- we have 255 steps per subpixel
    		local base = 0xFF
    
    		-- clamp values, discard fractions
    		r = math.floor(base * math.max(0, math.min(1, r)))
    		g = math.floor(base * math.max(0, math.min(1, g)))
    		b = math.floor(base * math.max(0, math.min(1, b)))
    
    		-- pack it into one number representing the RGB values
    		color_cache[t] = r*2^16 + g*2^8 + b
    	end
    
    	return color_cache[t]
    end
    
    local update_hud_markers = function(player_name)
    	if death_markers[player_name] ~= nil then
    		local player = minetest.get_player_by_name(player_name)
    		local now = os.time()
    		local valid_hud_ids = {}
    
    		for pos_string, marker in pairs(death_markers[player_name]) do
    			local t = now - marker.timestamp
    			if marker.is_creative then
    				t = t / WAYPOINT_EXPIRES_SECONDS_CREATIVE
    			else
    				t = t / WAYPOINT_EXPIRES_SECONDS
    			end
    
    			if managed_hud_ids[player_name] ~= nil and managed_hud_ids[player_name][pos_string] ~= nil then
    				local hud_id = managed_hud_ids[player_name][pos_string]
    				valid_hud_ids[hud_id] = hud_id
    
    				if t > 1 then
    					death_markers[player_name][pos_string] = nil
    					mark_dirty_and_schedule_writeback()
    
    					if player ~= nil then
    						player:hud_remove(hud_id)
    						managed_hud_ids[player_name][pos_string] = nil
    					end
    				else
    					if player ~= nil then
    						player:hud_change(hud_id, "name", marker.text)--.." (t = "..tostring(math.floor(t * 100 + 0.5) / 100)..")")
    						player:hud_change(hud_id, "number", calculate_color(t))
    					end
    				end
    			else
    				if player ~= nil and t < 1 then
    					if managed_hud_ids[player_name] == nil then
    						managed_hud_ids[player_name] = {}
    					end
    
    					local pos = minetest.string_to_pos(pos_string)
    
    					local hud_id = player:hud_add({
    						hud_elem_type = "waypoint",
    						name = marker.text,--.." (add | t = "..tostring(math.floor(t * 100 + 0.5) / 100)..")",
    						text = "m",
    						number = calculate_color(t),
    						world_pos = pos
    					})
    					managed_hud_ids[player_name][pos_string] = hud_id
    					valid_hud_ids[hud_id] = hud_id
    				end
    			end
    		end
    
    		if player ~= nil and managed_hud_ids[player_name] ~= nil then
    			-- everything that remains should be removed
    			for pos_string, hud_id in pairs(managed_hud_ids[player_name]) do
    				if valid_hud_ids[hud_id] == nil then
    					player:hud_remove(hud_id)
    					managed_hud_ids[player_name][pos_string] = nil
    				end
    			end
    		end
    	end
    end
    
    minetest.register_on_dieplayer(function(player)
    	local player_name = player:get_player_name()
    	local is_creative = creative and creative.is_enabled_for(player_name)
    
    	local pos = player:get_pos()
    
    	pos.x = math.floor(pos.x + 0.5)
    	pos.y = math.floor(pos.y + 0.5)
    	pos.z = math.floor(pos.z + 0.5)
    
    	local pos_string = minetest.pos_to_string(pos)
    
    	minetest.log("action", "[death] player '" .. player_name .. "' died at " .. pos_string .. (is_creative and " (creative)" or ""))
    	minetest.chat_send_player(player_name, "You died at " .. pos_string)
    
    	local msg_string = ""
    
    	if not is_creative then
    		msg_string = "Bones"
    
    		if player.get_attribute then
    			-- [xp_redo] keeps track of deathcount, let's see if it is there
    			local count = player:get_attribute("died")
    			if count then
    				msg_string = "Bone #" .. tostring(count)
    			end
    		end
    	else
    		msg_string = "Death"
    	end
    
    	if death_markers[player_name] == nil then
    		death_markers[player_name] = {}
    	end
    	death_markers[player_name][pos_string] = {
    		text = msg_string,
    		timestamp = os.time(),
    		is_creative = is_creative,
    	}
    	mark_dirty_and_schedule_writeback()
    
    	update_hud_markers(player_name)
    end)
    
    minetest.register_on_joinplayer(function(player)
    	local player_name = player:get_player_name()
    	update_hud_markers(player_name)
    
    	if death_markers[player_name] ~= nil then
    		minetest.after(2, function()
    			local markers = {}
    			for pos_string, marker in pairs(death_markers[player_name]) do
    				table.insert(markers, pos_string.." "..marker.text..(marker.is_creative and " (creative)" or ""))
    			end
    			--minetest.chat_send_player(player_name, "Your death markers ("..tostring(#markers).."): "..table.concat(markers, ", "))
    		end)
    	end
    end)
    
    minetest.register_on_leaveplayer(function(player)
    	local player_name = player:get_player_name()
    
    	--[[
    	for pos_string, marker in pairs(managed_hud_ids[player_name]) do
    		player:hud_remove(hud_id)
    	end
    	managed_hud_ids[player_name] = nil
    	]]--
    end)
    
    
    local update_loop
    update_loop = function()
    	for player_name, markers in pairs(managed_hud_ids) do
    		update_hud_markers(player_name)
    	end
    
    	minetest.after(UPDATE_INTERVAL, update_loop)
    end
    
    update_loop()