af1f808c68
Guarantee 2 usable slots no matter how many different injury effects accumulate. Filled slots will be shared among different damage types roughly proportionally.
112 lines
2.6 KiB
Lua
112 lines
2.6 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local math, minetest, nodecore, pairs, table
|
|
= math, minetest, nodecore, pairs, table
|
|
local math_floor, math_random, table_remove, table_sort
|
|
= math.floor, math.random, table.remove, table.sort
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
nodecore.register_healthfx,
|
|
nodecore.registered_healthfx
|
|
= nodecore.mkreg()
|
|
|
|
local function pickend(q)
|
|
for i = q, 1, -1 do
|
|
if math_random() < 0.5 then return i end
|
|
end
|
|
return pickend(q)
|
|
end
|
|
|
|
local function rounddist(n)
|
|
n = n - math_floor(n)
|
|
if n < 0.5 then return n end
|
|
return 1 - n
|
|
end
|
|
|
|
local function checkinv(player)
|
|
local inv = player:get_inventory()
|
|
local size = inv:get_size("main")
|
|
local max = size - 2
|
|
|
|
local items = {}
|
|
for _, def in pairs(nodecore.registered_healthfx) do
|
|
items[def.item] = {}
|
|
end
|
|
|
|
local reg = {}
|
|
for i = 1, size do
|
|
local name = inv:get_stack("main", i):get_name()
|
|
local tbl = items[name]
|
|
if tbl then
|
|
tbl[#tbl + 1] = i
|
|
else
|
|
reg[#reg + 1] = i
|
|
end
|
|
end
|
|
|
|
local slots = {}
|
|
local total = 0
|
|
for _, def in pairs(nodecore.registered_healthfx) do
|
|
local q = def.getqty(player) * (max + 1) - 1
|
|
if q > max then q = max end
|
|
if q < 0 then q = 0 end
|
|
slots[#slots + 1] = {item = def.item, qty = size - q}
|
|
total = total + 1
|
|
end
|
|
if total > max then
|
|
for _, v in pairs(slots) do
|
|
v.qty = v.qty * max / total
|
|
end
|
|
table_sort(slots, function(a, b) return rounddist(a.qty) < rounddist(b.qty) end)
|
|
local resid = 0
|
|
for _, v in pairs(slots) do
|
|
resid = resid + v.qty - math_floor(v.qty)
|
|
if resid > 0.5 then
|
|
v.qty = v.qty + 1
|
|
resid = resid - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
local slotidx = {}
|
|
for _, v in pairs(slots) do slotidx[v.item] = math_floor(v.qty) end
|
|
|
|
for _, def in pairs(nodecore.registered_healthfx) do
|
|
local need = slotidx[def.item]
|
|
|
|
if #reg > need then
|
|
local pos = player:get_pos()
|
|
while #reg > need do
|
|
local n = pickend(#reg)
|
|
local i = reg[n]
|
|
table_remove(reg, n)
|
|
local stack = inv:get_stack("main", i)
|
|
if not (stack:get_definition() or {}).virtual_item then
|
|
nodecore.item_eject(pos, stack, 5)
|
|
end
|
|
inv:set_stack("main", i, def.item)
|
|
end
|
|
return
|
|
end
|
|
|
|
local inj = items[def.item]
|
|
local fill = size - need
|
|
if #inj > fill then
|
|
for i = 1, #inj / 2 do
|
|
inj[i], inj[#inj + 1 - i] = inj[#inj + 1 - i], inj[i]
|
|
end
|
|
while #inj > fill do
|
|
local n = pickend(#inj)
|
|
local i = inj[n]
|
|
table_remove(inj, n)
|
|
inv:set_stack("main", i, "")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_globalstep(function()
|
|
for _, p in pairs(minetest.get_connected_players()) do
|
|
if p:get_hp() > 0 then checkinv(p) end
|
|
end
|
|
end)
|