forked from VoxeLibre/VoxeLibre
Merge pull request 'Fix fire HUD' (#2042) from kabou/MineClone2:fix-burning-HUD into master
Reviewed-on: MineClone2/MineClone2#2042
This commit is contained in:
commit
f7d712543f
|
@ -26,20 +26,64 @@ function mcl_burning.get_collisionbox(obj, smaller, storage)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local find_nodes_in_area = minetest.find_nodes_in_area
|
||||||
|
|
||||||
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
||||||
local pos = obj:get_pos()
|
local pos = obj:get_pos()
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
||||||
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
local nodes = find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||||
return nodes
|
return nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Manages the fire animation on a burning player's HUD
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- player - a valid player object;
|
||||||
|
--
|
||||||
|
-- If the player already has a fire HUD, updates the burning animation.
|
||||||
|
-- If the fire does not have a fire HUD, initializes the HUD.
|
||||||
|
--
|
||||||
|
function mcl_burning.update_hud(player)
|
||||||
|
local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
|
local hud_flame_animated = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. animation_frames .. ":"
|
||||||
|
|
||||||
|
local storage = mcl_burning.get_storage(player)
|
||||||
|
if not storage.fire_hud_id then
|
||||||
|
storage.animation_frame = 1
|
||||||
|
storage.fire_hud_id = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 0.5},
|
||||||
|
scale = {x = -100, y = -100},
|
||||||
|
text = hud_flame_animated .. storage.animation_frame,
|
||||||
|
z_index = 1000,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
storage.animation_frame = storage.animation_frame + 1
|
||||||
|
if storage.animation_frame > animation_frames - 1 then
|
||||||
|
storage.animation_frame = 0
|
||||||
|
end
|
||||||
|
player:hud_change(storage.fire_hud_id, "text", hud_flame_animated .. storage.animation_frame)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sets and object state as burning and adds a fire animation to the object.
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- obj - may be a player or a lua_entity;
|
||||||
|
-- burn_time - sets the object's burn duration;
|
||||||
|
--
|
||||||
|
-- If obj is a player, adds a fire animation to the HUD, if obj is a
|
||||||
|
-- lua_entity, adds an animated fire entity to obj.
|
||||||
|
-- The effective burn duration is modified by obj's armor protection.
|
||||||
|
-- If obj was already burning, its burn duration is updated if the current
|
||||||
|
-- duration is less than burn_time.
|
||||||
|
-- If obj is dead, fireproof or a creative player, this function does nothing.
|
||||||
|
--
|
||||||
function mcl_burning.set_on_fire(obj, burn_time)
|
function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
if obj:get_hp() < 0 then
|
if obj:get_hp() < 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local storage = mcl_burning.get_storage(obj)
|
|
||||||
|
|
||||||
local luaentity = obj:get_luaentity()
|
local luaentity = obj:get_luaentity()
|
||||||
if luaentity and luaentity.fire_resistant then
|
if luaentity and luaentity.fire_resistant then
|
||||||
return
|
return
|
||||||
|
@ -60,37 +104,37 @@ function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if max_fire_prot_lvl > 0 then
|
if max_fire_prot_lvl > 0 then
|
||||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not storage.burn_time or burn_time >= storage.burn_time then
|
local storage = mcl_burning.get_storage(obj)
|
||||||
if obj:is_player() then
|
if storage.burn_time then
|
||||||
mcl_burning.channels[obj]:send_all(tostring(mcl_burning.animation_frames))
|
if burn_time > storage.burn_time then
|
||||||
mcl_burning.channels[obj]:send_all("start")
|
storage.burn_time = burn_time
|
||||||
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
storage.burn_time = burn_time
|
storage.burn_time = burn_time
|
||||||
storage.fire_damage_timer = 0
|
storage.fire_damage_timer = 0
|
||||||
|
|
||||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
||||||
local obj_size = obj:get_properties().visual_size
|
|
||||||
|
|
||||||
local vertical_grow_factor = 1.2
|
|
||||||
local horizontal_grow_factor = 1.1
|
|
||||||
local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor)
|
|
||||||
|
|
||||||
local size = vector.subtract(maxp, minp)
|
local size = vector.subtract(maxp, minp)
|
||||||
size = vector.multiply(size, grow_vector)
|
size = vector.multiply(size, vector.new(1.1, 1.2, 1.1))
|
||||||
size = vector.divide(size, obj_size)
|
size = vector.divide(size, obj:get_properties().visual_size)
|
||||||
local offset = vector.new(0, size.y * 10 / 2, 0)
|
|
||||||
|
|
||||||
|
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||||
fire_entity:set_properties({visual_size = size})
|
fire_entity:set_properties({visual_size = size})
|
||||||
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
fire_entity:set_attach(obj, "", vector.new(0, size.y * 5, 0), vector.new(0, 0, 0))
|
||||||
local fire_luaentity = fire_entity:get_luaentity()
|
|
||||||
|
|
||||||
|
if obj:is_player() then
|
||||||
|
mcl_burning.update_hud(obj)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FIXME: does this code make sense? It removes attached fire luaentities from
|
||||||
|
-- another object that happen to be at the same position.
|
||||||
|
local fire_luaentity = fire_entity:get_luaentity()
|
||||||
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
|
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
|
||||||
local other_luaentity = other:get_luaentity()
|
local other_luaentity = other:get_luaentity()
|
||||||
if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then
|
if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then
|
||||||
|
@ -98,14 +142,15 @@ function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.extinguish(obj)
|
function mcl_burning.extinguish(obj)
|
||||||
if mcl_burning.is_burning(obj) then
|
if mcl_burning.is_burning(obj) then
|
||||||
local storage = mcl_burning.get_storage(obj)
|
local storage = mcl_burning.get_storage(obj)
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
mcl_burning.channels[obj]:send_all("stop")
|
if storage.fire_hud_id then
|
||||||
|
obj:hud_remove(storage.fire_hud_id)
|
||||||
|
end
|
||||||
mcl_burning.storage[obj] = {}
|
mcl_burning.storage[obj] = {}
|
||||||
else
|
else
|
||||||
storage.burn_time = nil
|
storage.burn_time = nil
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
local pairs = pairs
|
|
||||||
|
|
||||||
local get_connected_players = minetest.get_connected_players
|
|
||||||
local get_item_group = minetest.get_item_group
|
|
||||||
|
|
||||||
mcl_burning = {
|
mcl_burning = {
|
||||||
storage = {},
|
-- the storage table holds a list of objects (players,luaentities) and tables
|
||||||
channels = {},
|
-- associated with these objects. These tables have the following attributes:
|
||||||
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
-- burn_time:
|
||||||
|
-- Remaining time that object will burn.
|
||||||
|
-- fire_damage_timer:
|
||||||
|
-- Timer for dealing damage every second while burning.
|
||||||
|
-- fire_hud_id:
|
||||||
|
-- HUD id of the flames animation on a burning player's HUD.
|
||||||
|
-- animation_frame:
|
||||||
|
-- The HUD's current animation frame, used by update_hud().
|
||||||
|
-- collisionbox_cache:
|
||||||
|
-- Used by mcl_burning.get_collisionbox() to avoid recalculations.
|
||||||
|
storage = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
dofile(modpath .. "/api.lua")
|
dofile(modpath .. "/api.lua")
|
||||||
|
|
||||||
|
local pairs = pairs
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local get_item_group = minetest.get_item_group
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
for _, player in pairs(get_connected_players()) do
|
for _, player in pairs(get_connected_players()) do
|
||||||
local storage = mcl_burning.storage[player]
|
local storage = mcl_burning.storage[player]
|
||||||
|
@ -44,25 +53,36 @@ minetest.register_on_respawnplayer(function(player)
|
||||||
mcl_burning.extinguish(player)
|
mcl_burning.extinguish(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function mcl_burning.init_player(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
local meta = player:get_meta()
|
local storage = {}
|
||||||
-- NOTE: mcl_burning:data may be "return nil" (which deserialize into nil) for reasons unknown.
|
local burn_data = player:get_meta():get_string("mcl_burning:data")
|
||||||
if meta:get_string("mcl_burning:data"):find("return nil", 1, true) then
|
if burn_data ~= "" then
|
||||||
minetest.log("warning", "[mcl_burning] 'mcl_burning:data' player meta field is invalid! Please report this bug")
|
storage = minetest.deserialize(burn_data)
|
||||||
end
|
end
|
||||||
mcl_burning.storage[player] = meta:contains("mcl_burning:data") and minetest.deserialize(meta:get_string("mcl_burning:data")) or {}
|
mcl_burning.storage[player] = storage
|
||||||
mcl_burning.channels[player] = minetest.mod_channel_join("mcl_burning:" .. player:get_player_name())
|
if storage.burn_time and storage.burn_time > 0 then
|
||||||
|
mcl_burning.update_hud(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function on_leaveplayer(player)
|
||||||
|
local storage = mcl_burning.storage[player]
|
||||||
|
storage.fire_hud_id = nil
|
||||||
|
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
|
||||||
|
mcl_burning.storage[player] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
|
||||||
mcl_burning.init_player(player)
|
|
||||||
end)
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
player:get_meta():set_string("mcl_burning:data", minetest.serialize(mcl_burning.storage[player]))
|
on_leaveplayer(player)
|
||||||
mcl_burning.storage[player] = nil
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_shutdown(function()
|
||||||
|
for _,player in ipairs(minetest.get_connected_players()) do
|
||||||
|
on_leaveplayer(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
|
|
||||||
minetest.register_entity("mcl_burning:fire", {
|
minetest.register_entity("mcl_burning:fire", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
|
@ -73,7 +93,7 @@ minetest.register_entity("mcl_burning:fire", {
|
||||||
"mcl_burning_entity_flame_animated.png",
|
"mcl_burning_entity_flame_animated.png",
|
||||||
"mcl_burning_entity_flame_animated.png"
|
"mcl_burning_entity_flame_animated.png"
|
||||||
},
|
},
|
||||||
spritediv = {x = 1, y = mcl_burning.animation_frames},
|
spritediv = {x = 1, y = animation_frames},
|
||||||
pointable = false,
|
pointable = false,
|
||||||
glow = -1,
|
glow = -1,
|
||||||
backface_culling = false,
|
backface_culling = false,
|
||||||
|
@ -81,26 +101,25 @@ minetest.register_entity("mcl_burning:fire", {
|
||||||
animation_frame = 0,
|
animation_frame = 0,
|
||||||
animation_timer = 0,
|
animation_timer = 0,
|
||||||
on_activate = function(self)
|
on_activate = function(self)
|
||||||
self.object:set_sprite({x = 0, y = 0}, mcl_burning.animation_frames, 1.0 / mcl_burning.animation_frames)
|
self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames)
|
||||||
end,
|
end,
|
||||||
on_step = function(self)
|
on_step = function(self, dtime)
|
||||||
if not self:sanity_check() then
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
sanity_check = function(self)
|
|
||||||
local parent = self.object:get_attach()
|
local parent = self.object:get_attach()
|
||||||
|
|
||||||
if not parent then
|
if not parent then
|
||||||
return false
|
self.object:remove()
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local storage = mcl_burning.get_storage(parent)
|
local storage = mcl_burning.get_storage(parent)
|
||||||
|
|
||||||
if not storage or not storage.burn_time then
|
if not storage or not storage.burn_time then
|
||||||
return false
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if parent:is_player() then
|
||||||
|
self.animation_timer = self.animation_timer + dtime
|
||||||
|
if self.animation_timer >= 0.1 then
|
||||||
|
self.animation_timer = 0
|
||||||
|
mcl_burning.update_hud(parent)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue