217 lines
6.3 KiB
Lua
217 lines
6.3 KiB
Lua
--[[ Config ]]--
|
|
local disable_inventory = false
|
|
local R = 1 -- Size of vbar radius
|
|
local shape = "belt" -- Mode (belt or ring)
|
|
|
|
local visuals = {}
|
|
local hud = {}
|
|
local toggle = {}
|
|
|
|
local def_size = vector.multiply({x = 0.25, y = 0.25, z = 0.25}, R)
|
|
local def_sel = vector.multiply({x = 0.265, y = 0.265, z = 0.265}, R)
|
|
|
|
-- Swap hotbar items around
|
|
local function set_item(entity, player)
|
|
local inv = player:get_inventory()
|
|
local main = inv:get_list("main")
|
|
inv:set_stack("main", entity.idx, player:get_wielded_item())
|
|
player:set_wielded_item(main[entity.idx])
|
|
visuals[player:get_player_name()] = nil
|
|
end
|
|
|
|
vector.cross = vector.cross or function(a, b)
|
|
return {
|
|
x = a.y * b.z - a.z * b.y,
|
|
y = a.z * b.x - a.x * b.z,
|
|
z = a.x * b.y - a.y * b.x
|
|
}
|
|
end
|
|
|
|
local function dir_to_pitch(dir)
|
|
local pitch = minetest.dir_to_yaw({x = -dir.y, y = 0, z = math.sqrt(1 - dir.y * dir.y)})
|
|
return (pitch > math.pi) and (pitch - math.pi * 2) or pitch
|
|
end
|
|
|
|
local shapes = {
|
|
belt = function(player, slot)
|
|
local pos = player:get_pos()
|
|
pos.y = pos.y + 1
|
|
local angle = (-(360 / 8) * slot) + 45
|
|
local y = player:get_look_horizontal()
|
|
local rel = vector.multiply(minetest.yaw_to_dir(math.rad(angle) + y), R)
|
|
local target = vector.add(rel, pos)
|
|
local rot = vector.direction(target, pos)
|
|
return target, {x = 0, y = math.rad(angle) + y, z = 0}
|
|
end,
|
|
ring = function(player, slot) -- Thanks to Aaron Suen (Warr1024) for this
|
|
local camera_z = player:get_look_dir()
|
|
local camera_x = minetest.yaw_to_dir(player:get_look_horizontal() + math.pi / 2)
|
|
local camera_y = vector.cross(camera_x, camera_z)
|
|
local angle = ((360 / 8) * slot) + 45
|
|
local cv = {x = math.cos(math.rad(angle)) * R, y = math.sin(math.rad(angle)) * R, z = R * 2}
|
|
local wv = player:get_pos()
|
|
wv.y = wv.y + player:get_properties().eye_height
|
|
wv = vector.add(wv, vector.multiply(camera_x, cv.x))
|
|
wv = vector.add(wv, vector.multiply(camera_y, cv.y))
|
|
wv = vector.add(wv, vector.multiply(camera_z, cv.z))
|
|
return wv, {x = dir_to_pitch(camera_z), y = minetest.dir_to_yaw(camera_z), z = 0}
|
|
end,
|
|
}
|
|
|
|
minetest.register_entity("visualbar:item", {
|
|
initial_properties = {
|
|
visual = "wielditem",
|
|
wield_item = "",
|
|
visual_size = def_size,
|
|
selectionbox = {-0.25 * R, -0.25 * R, -0.25 * R, 0.25 * R, 0.25 * R, 0.25 * R},
|
|
collisionbox = {-0.25 * R, -0.25 * R, -0.25 * R, 0.25 * R, 0.25 * R, 0.25 * R},
|
|
},
|
|
parent = nil, -- You aren't really supposed to store references, but... sue me
|
|
timer = 0,
|
|
idx = 0,
|
|
on_activate = function(self)
|
|
self.object:set_armor_groups({immortal = 1})
|
|
end,
|
|
on_step = function(self, dt) -- Most of this is just fancy visuals
|
|
self.timer = self.timer + dt
|
|
if self.timer > 0.1 then
|
|
if not self.parent or not visuals[self.parent:get_player_name()] then
|
|
self.object:remove()
|
|
elseif self.object:get_properties().wield_item ~= "" then
|
|
local pointed = false
|
|
local player = self.parent
|
|
local pos = player:get_pos()
|
|
pos.y = pos.y + player:get_properties().eye_height
|
|
local dir = player:get_look_dir()
|
|
local ray = minetest.raycast(pos, vector.add(pos, vector.multiply(dir, 2)))
|
|
for pt in ray do
|
|
if pt.type == "object" and pt.ref == self.object then
|
|
pointed = true
|
|
break
|
|
end
|
|
end
|
|
if pointed then
|
|
self.object:set_properties({
|
|
visual_size = def_sel
|
|
})
|
|
else
|
|
self.object:set_properties({
|
|
visual_size = def_size
|
|
})
|
|
end
|
|
end
|
|
self.timer = 0
|
|
end
|
|
end,
|
|
on_punch = set_item,
|
|
on_rightclick = set_item,
|
|
})
|
|
|
|
local function display(player)
|
|
local name = player:get_player_name()
|
|
local inv = player:get_inventory()
|
|
local list = inv:get_list("main")
|
|
local pos = player:get_pos()
|
|
|
|
visuals[name] = table.copy(pos)
|
|
|
|
for i = 1, 8 do
|
|
local target, rot = shapes[shape](player, i)
|
|
local ent = minetest.add_entity(target, "visualbar:item")
|
|
local luen = ent:get_luaentity()
|
|
local item = list[i]:get_name()
|
|
if item ~= "" then
|
|
ent:set_properties({wield_item = item, infotext = minetest.registered_items[item].description or item})
|
|
ent:set_rotation(rot)
|
|
if list[i]:get_count() > 1 then
|
|
ent:set_nametag_attributes({
|
|
color = "white",
|
|
text = list[i]:get_count()
|
|
})
|
|
end
|
|
else
|
|
ent:set_properties({visual_size = {x = 0, y = 0, z = 0}})
|
|
end
|
|
luen.parent = player
|
|
luen.idx = i
|
|
end
|
|
end
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
local name = player:get_player_name()
|
|
|
|
player:hud_set_flags({
|
|
hotbar = false
|
|
})
|
|
player:hud_set_hotbar_itemcount(1) -- Force player to hold selected item
|
|
|
|
-- Display stack size
|
|
hud[name] = player:hud_add({
|
|
hud_elem_type = "text",
|
|
position = {x = 0.5, y = 1},
|
|
text = "",
|
|
alignment = 0,
|
|
offset = {x = 0, y = -20},
|
|
number = 0xFFFFFF,
|
|
})
|
|
|
|
if disable_inventory then
|
|
minetest.after(0, function(name)
|
|
local player = minetest.get_player_by_name(name)
|
|
if player then
|
|
player:set_inventory_formspec("size[0,0] no_prepend[] bgcolor[#00000000]")
|
|
end
|
|
end, name)
|
|
player:get_inventory():set_size("main", 8)
|
|
else
|
|
player:get_inventory():set_size("main", 8 * 4)
|
|
minetest.register_on_player_inventory_action(function(player)
|
|
visuals[player:get_player_name()] = nil
|
|
end)
|
|
end
|
|
|
|
minetest.register_on_placenode(function(_, _, player)
|
|
visuals[player:get_player_name()] = nil
|
|
end)
|
|
minetest.register_on_dignode(function(_, _, player)
|
|
visuals[player:get_player_name()] = nil
|
|
end)
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
visuals[player:get_player_name()] = nil
|
|
end)
|
|
|
|
local function precise_time()
|
|
return minetest.get_us_time() / 1000000
|
|
end
|
|
|
|
minetest.register_globalstep(function()
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
local name = player:get_player_name()
|
|
local ctrl = player:get_player_control()
|
|
if visuals[name] then -- Remove visuals if aux1 is pressed or the player moves
|
|
if ctrl.aux1 or not vector.equals(vector.floor(player:get_pos()), vector.floor(visuals[name])) then
|
|
visuals[name] = nil
|
|
toggle[name] = 0
|
|
end
|
|
else
|
|
if ctrl.aux1 then -- Start the timer if aux1 is pressed
|
|
toggle[name] = toggle[name] or precise_time()
|
|
elseif toggle[name] then
|
|
if precise_time() - toggle[name] <= 0.12 then
|
|
display(player) -- Display if aux1 was released within 0.12 seconds
|
|
end
|
|
toggle[name] = nil
|
|
end
|
|
end
|
|
|
|
-- Update stack count HUD element
|
|
local count = player:get_wielded_item():get_count()
|
|
if count < 1 then
|
|
count = ""
|
|
end
|
|
player:hud_change(hud[name], "text", count)
|
|
end
|
|
end)
|