xdecor-libre/handlers/animations.lua
2024-09-19 14:38:11 +02:00

155 lines
4.5 KiB
Lua

local mod_player_api = minetest.get_modpath("player_api") ~= nil
local sitting = {}
local seats_occupied = {}
local function bottom_face(pointed_thing)
if not pointed_thing then
return
end
return pointed_thing.above.y < pointed_thing.under.y
end
local function stand_up(player_name)
if not mod_player_api then
return
end
local player = minetest.get_player_by_name(player_name)
if not player then
return
end
player_api.player_attached[player_name] = false
local old_anim = player_api.get_animation(player)
if old_anim and old_anim.animation == "sit" then
player_api.set_animation(player, "stand")
end
local hash = minetest.hash_node_position(sitting[player_name])
seats_occupied[hash] = nil
sitting[player_name] = nil
minetest.log("action", "[xdecor] "..player_name.." stands up at "..minetest.pos_to_string(player:get_pos(), 0))
end
--[[ Used when player interacts with "sittable" node to sit down
or stand up when interacting with that node again. Should
be used in `on_rightclick` handler
* `pos`: Position where to sit down player (MUST only use integers for coordinates!)
* `node`: Node table of node to sit on
* `clicker`: Player who interacted with node (from `on_rightclick`)
* `pointed_thing`: From `on_rightclick` ]]
function xdecor.sit(pos, node, clicker, pointed_thing)
if not mod_player_api then
return
end
-- Can't sit down if bottom face was pointed at
if bottom_face(pointed_thing) then
return
end
local player_name = clicker:get_player_name()
local objs = minetest.get_objects_inside_radius(pos, 0.1)
local vel = clicker:get_velocity()
local ctrl = clicker:get_player_control()
-- Stand up if sitting
if sitting[player_name] then
stand_up(player_name)
-- Sit down if not sitting and not attached
elseif not sitting[player_name] and not player_api.player_attached[player_name] and node.param2 <= 3 and
not ctrl.sneak and vector.equals(vel, vector.new()) then
-- Can't sit down on note already occupied by player
local hash = minetest.hash_node_position(pos)
if seats_occupied[hash] then
return
end
player_api.player_attached[player_name] = true
player_api.set_animation(clicker, "sit")
sitting[player_name] = table.copy(pos)
seats_occupied[hash] = player_name
clicker:set_pos(pos)
if node.param2 == 0 then
clicker:set_look_horizontal(0)
elseif node.param2 == 1 then
clicker:set_look_horizontal(3*(math.pi/2))
elseif node.param2 == 2 then
clicker:set_look_horizontal(math.pi)
elseif node.param2 == 3 then
clicker:set_look_horizontal(math.pi/2)
end
minetest.log("action", "[xdecor] "..player_name.." sits down at "..minetest.pos_to_string(pos, 0))
end
end
-- Called when `digger` (a player object) wants to
-- dig a node at pos. Returns true if it's allowed,
-- false otherwise. This checks if the node at pos
-- is an occupied sittable node.
-- Can be used for the `can_dig` node function.
function xdecor.sit_dig(pos, digger)
if not mod_player_api then
return true
end
local hash = minetest.hash_node_position(pos)
if seats_occupied[hash] then
return false
end
return true
end
-- To be called when a seat (sittable node) got destroyed
-- to clean up state. Precisely, this should be used
-- as the `after_destruct` handler.
function xdecor.sit_destruct(pos)
local hash = minetest.hash_node_position(pos)
local occupier = seats_occupied[hash]
if occupier then
stand_up(occupier)
seats_occupied[hash] = nil
sitting[occupier] = nil
end
end
-- Automatically cause players to stand up if they pressed a control
-- or moved away from the seat
minetest.register_globalstep(function(dtime)
local to_stand_up = {}
for player_name, sitting_pos in pairs(sitting) do
local player = minetest.get_player_by_name(player_name)
if player then
local ctrl = player:get_player_control()
if ctrl.up or ctrl.down or ctrl.left or ctrl.right or ctrl.sneak or ctrl.jump then
table.insert(to_stand_up, player_name)
elseif vector.distance(player:get_pos(), sitting_pos) > 0.55 then
table.insert(to_stand_up, player_name)
end
end
end
for s=1, #to_stand_up do
stand_up(to_stand_up[s])
end
end)
-- Force player to stand on death (to the seat is released)
minetest.register_on_dieplayer(function(player)
local player_name = player:get_player_name()
if sitting[player_name] then
stand_up(player_name)
end
end)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
if sitting[player_name] then
local hash = minetest.hash_node_position(sitting[player_name])
seats_occupied[hash] = nil
sitting[player_name] = nil
end
end)