local ns = artifact local db = minetest.get_mod_storage() function ns.apply_key(m) m.object:set_properties { textures = {"artifact_key.png"}, visual_size = vector.new(1,1,1) *0.88, eye_height = 1.6 } m.eye_height = 1.6 -- Switch hand appearance. m.inv:set_stack("main", 1, ItemStack("input_"..m.character)) if m.healthbar then m.object:hud_change(m.healthbar, "text", "artifact_heart.png") end m.blackrod = minetest.add_entity(m.object:get_pos(), "display") m.blackrod:set_properties { visual = "mesh", mesh = "artifact_blackrod.obj", textures = {"artifact_blackrod.png"}, visual_size = vector.new(1,1,1) *10 } m.blackrod:set_attach(m.object, "RightArm", vector.new(0.25, -5.5, 0), vector.new(90,0,0)) end function ns.apply_vix(m) m.object:set_properties { textures = {"artifact_vix.png"}, visual_size = vector.new(1,1,1) *0.8, eye_height = 1.5 } m.eye_height = 1.5 -- Switch hand appearance. m.inv:set_stack("main", 1, ItemStack("input_"..m.character)) if m.healthbar then m.object:hud_change(m.healthbar, "text", "artifact_heart_vix.png") end if m.blackrod then m.blackrod:remove() m.blackrod = nil end end function ns._swap_character(m) -- If Key was pointing at something Vix shouldn't be able to interact with, -- but Vix is also pointing at it, then remove the interaction marker since -- it would be misleading. if m.pointed_obj and m.interaction_marker and (not m.pointed_obj._can_interact or m.pointed_obj:_can_interact(m)) then m.object:hud_remove(m.interaction_marker) m.interaction_marker = nil m.interaction_start = nil end if m.character == "vix" then artifact.sidekick.character = "vix" m:set_character("key") ns.apply_key(m) else artifact.sidekick.character = "key" m:set_character("vix") ns.apply_vix(m) end -- If Vix was pointing at something whackable, and the player then switches -- to Key who is pointing at the same thing, we should show the whack icon. if m.character == "key" and m.pointed_node and minetest.registered_nodes[m.pointed_node.node_under.name].groups.whackable then m.whack_hud = m.object:hud_add { type = "image_waypoint", world_pos = m.pointed_node.under, scale = {x=3,y=3}, text = "artifact_icon_whack.png" } end -- We don't need to have the sidekick entity during testing. if artifact.sidekick.pos or not artifact.debug then -- `m.pos` includes eye_height, and we don't want that here. local pos = m.object:get_pos() local yaw = m.yaw local pitch = m.pitch if not artifact.sidekick.pos then artifact.sidekick.pos = pos end m.object:set_pos(artifact.sidekick.pos) m.object:set_look_horizontal(artifact.sidekick.yaw) m.object:set_look_vertical(artifact.sidekick.pitch) if not artifact.sidekick.ref then minetest.add_entity(pos, "artifact:sidekick") end artifact.sidekick.ref.object:set_pos(pos) artifact.sidekick.ref.object:set_yaw(yaw) artifact.sidekick.ref.object:set_bone_override("Head", m.object:get_bone_override("Head")) artifact.sidekick.ref.object:set_bone_override("root", m.object:get_bone_override("root")) artifact.sidekick.pos = pos artifact.sidekick.yaw = yaw artifact.sidekick.pitch = pitch local e = artifact.sidekick.ref if artifact.sidekick.character == "vix" then artifact.sidekick.ref.object:set_properties { textures = {"artifact_vix.png"}, visual_size = vector.new(1,1,1) *0.8 } if e.blackrod then e.blackrod:remove() e.blackrod = nil end else e.object:set_properties { textures = {"artifact_key.png"}, visual_size = vector.new(1,1,1) *0.88 } e.blackrod = minetest.add_entity(e.object:get_pos(), "display") e.blackrod:set_properties { visual = "mesh", mesh = "artifact_blackrod.obj", textures = {"artifact_blackrod.png"}, visual_size = vector.new(1,1,1) *10 } e.blackrod:set_attach(e.object, "RightArm", vector.new(0.25, -5.5, 0), vector.new(90,0,0)) end end artifact.sidekick.save() end function ns.swap_character(m) if m._swapping_character then return end if artifact.sidekick.ref then artifact.sidekick.ref._no_interact = true end m._swapping_character = true local fade = artifact.hud_add(m, { type = "image", pos = {x=0.5,y=1}, offset = {x=0,y=0}, align = {x=0,y=0}, scale = {x=50000,y=50000}, opacity = 0, image = "[fill:1x1:0,0:#000", }) fade:animate { opacity = { value = 256, duration = 0.3 } } artifact.play_sound { name = "artifact_character_swap", to_player = m.name } minetest.after(0.3, function() ns._swap_character(m) fade:animate { opacity = { value = 0, duration = 0.3 } } minetest.after(0.3, function() m._swapping_character = nil if artifact.sidekick.ref then artifact.sidekick.ref._no_interact = nil end end) end) end include "key.lua" include "vix.lua" artifact.sidekick = setmetatable(minetest.deserialize(db:get("sidekick") or "return nil") or { pitch = 0, yaw = 0, character = "vix", }, { __index = { save = function() local ref = artifact.sidekick.ref -- Temporarily erase the entity so we can serialize properly. artifact.sidekick.ref = nil db:set_string("sidekick", minetest.serialize(artifact.sidekick)) artifact.sidekick.ref = ref end } }) minetest.register_entity(":artifact:sidekick", { initial_properties = { visual = "mesh", mesh = "artifact_character.gltf", textures = {"artifact_vix.png"}, visual_size = vector.new(1,1,1) *0.8, physical = true, collisionbox = { -0.3, 0,-0.3, 0.3, 1.77, 0.3 }, collide_with_objects = false }, _interact_marker_offset = function() return vector.new(0, 1.1,0) end, _interact_time = 0.4, on_activate = function(e, data) if data then extend(e, minetest.deserialize(data) or {}) end if artifact.sidekick.character == "key" then e.object:set_properties { textures = {"artifact_key.png"}, visual_size = vector.new(1,1,1) *0.88 } end -- Gravity. e.object:set_acceleration(vector.new(0,-9.81,0)) -- Make quite sure that we only ever have one of these. -- Remove this one because the first one we spawned is _probably_ the -- right one (e.g. if someone got unloaded, then loaded again after -- a replacement was spawned). if artifact.sidekick.ref then e.object:remove() return end artifact.sidekick.pos = e.object:get_pos() artifact.sidekick.ref = e end, on_deactivate = function(e) artifact.sidekick.ref = nil end, get_staticdata = function(e) return minetest.serialize{ cahracter = e.character } end, -- We need this to ensure that the stored position takes gravity into account. on_step = function(e) artifact.sidekick.pos = e.object:get_pos() end, on_interact = function(e, m) ns.swap_character(m) end })