Add multi-signal doors, basic device deployment, and a target trigger.

This commit is contained in:
Signal 2025-11-17 03:04:16 -05:00
parent 1b2199705b
commit 9acd605c86
35 changed files with 660 additions and 75 deletions

View file

@ -52,14 +52,21 @@ function ns.swap_character(m)
ns.apply_vix(m)
end
if artifact.sidekick.ref then
-- 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
m.object:set_pos(artifact.sidekick.ref.object:get_pos())
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"))
@ -76,6 +83,7 @@ function ns.swap_character(m)
}
if e.blackrod then
e.blackrod:remove()
e.blackrod = nil
end
else
e.object:set_properties {
@ -101,7 +109,6 @@ include "key.lua"
include "vix.lua"
artifact.sidekick = setmetatable(minetest.deserialize(db:get("sidekick") or "return nil") or {
pos = vector.zero(),
pitch = 0,
yaw = 0,
character = "vix",
@ -121,12 +128,14 @@ minetest.register_entity(":artifact:sidekick", {
initial_properties = {
visual = "mesh",
mesh = "artifact_character.gltf",
textures = {"artifact_key.png"},
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,
@ -134,7 +143,7 @@ minetest.register_entity(":artifact:sidekick", {
if data then
extend(e, minetest.deserialize(data) or {})
end
if artifact.sidekick.character == "vix" then
if artifact.sidekick.character == "key" then
e.object:set_properties {
textures = {"artifact_key.png"},
visual_size = vector.new(1,1,1) *0.88
@ -149,9 +158,9 @@ minetest.register_entity(":artifact:sidekick", {
if artifact.sidekick.ref then
e.object:remove()
return
else
artifact.sidekick.ref = e
end
artifact.sidekick.pos = e.object:get_pos()
artifact.sidekick.ref = e
end,
on_deactivate = function(e)
artifact.sidekick.ref = nil
@ -161,6 +170,10 @@ minetest.register_entity(":artifact:sidekick", {
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

View file

@ -2,5 +2,33 @@ local ns = artifact
function ns.do_whack(m)
if m.pointed_node then
local pos = m.pointed_node.under
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if not def.groups.whackable then return end
minetest.remove_node(pos)
minetest.add_particlespawner {
pos = {
min = pos:offset(-0.5, -0.5, -0.5),
max = pos:offset(0.5, 0.5, 0.5)
},
vel = {
min = vector.new(-1, 0, -1) *1.5,
max = vector.new(1, 2, 1) *1.5
},
acc = vector.new(0,-9.81,0),
collisiondetection = true,
amount = 50,
node = {name = node.name},
time = 0.1
}
elseif m.pointed_obj and m.pointed_obj.on_whack then
if m.pointed_obj:on_whack() then
-- For use in artifact_help.
if artifact.on_whacked then
artifact.on_whacked()
end
end
end
end

View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[1],"name":"blockbench_export"}],"scene":0,"nodes":[{"rotation":[0.003890431239830433,-0.2024051618564428,-0.37176938873941,0.9059826359235373],"name":"cube","mesh":0},{"children":[0]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963}],"buffers":[{"byteLength":840,"uri":"data:application/octet-stream;base64,AAC0vwAA8D8AAIy/AAC0vwAA8D8AANy/AAC0vwAAesEAAIy/AAC0vwAAesEAANy/AAACwAAA8D8AANy/AAACwAAA8D8AAIy/AAACwAAAesEAANy/AAACwAAAesEAAIy/AAACwAAA8D8AANy/AAC0vwAA8D8AANy/AAACwAAA8D8AAIy/AAC0vwAA8D8AAIy/AAACwAAAesEAAIy/AAC0vwAAesEAAIy/AAACwAAAesEAANy/AAC0vwAAesEAANy/AAACwAAA8D8AAIy/AAC0vwAA8D8AAIy/AAACwAAAesEAAIy/AAC0vwAAesEAAIy/AAC0vwAA8D8AANy/AAACwAAA8D8AANy/AAC0vwAAesEAANy/AAACwAAAesEAANy/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAPQAAAAAAAIA9AAAAAAAAAD0AAGA/AACAPQAAYD8AAMA9AAAAAAAAAD4AAAAAAADAPQAAYD8AAAA+AABgPwAAID4AAAA9AAAAPgAAAD0AACA+AAAAAAAAAD4AAAAAAAAgPgAAAD0AAAA+AAAAPQAAID4AAIA9AAAAPgAAgD0AAIA9AAAAAAAAwD0AAAAAAACAPQAAYD8AAMA9AABgPwAAAAAAAAAAAAAAPQAAAAAAAAAAAABgPwAAAD0AAGA/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[-1.40625,1.875,-1.09375],"min":[-2.03125,-15.625,-1.71875],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.15625,0.875],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"artifact_blackrod.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"artifact_blackrod.png","uri":"artifact_blackrod.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,005 B

View file

@ -6,7 +6,7 @@ minetest.register_entity(":artifact:burst", {
textures = {"blank.png"},
pointable = false,
physical = true,
collide_with_objects = false,
-- collide_with_objects = false,
collisionbox = {
-0.2, -0.2, -0.2,
0.2, 0.2, 0.2
@ -49,6 +49,13 @@ minetest.register_entity(":artifact:burst", {
time = 0.1,
}
e.object:remove()
if movement.collisions[1].type == "node" then
local pos = movement.collisions[1].node_pos
local name = minetest.get_node(pos).name
if minetest.registered_nodes[name].on_impact then
minetest.registered_nodes[name].on_impact(pos)
end
end
end
end,
impulse = function(e, vel)

View file

@ -0,0 +1,37 @@
minetest.register_entity(":artifact:device_block", {
initial_properties = {
visual = "cube",
textures = {"artifact_device_block.png", "artifact_device_block.png", "artifact_device_block.png", "artifact_device_block.png", "artifact_device_block.png", "artifact_device_block.png"},
use_texture_alpha = true,
glow = 8,
static_save = false,
},
_grabbable = true,
on_activate = function(e)
e.object:set_armor_groups{immortal = 1}
end,
on_hit = function(e, m)
artifact.grab_device(m, e)
end,
})
function artifact.grab_device(m, e)
e._no_interact = true
m._grabbed_item = e.object
m._on_ungrab = function()
e._no_interact = nil
end
end
function artifact.summon_device(m, device)
local e
if device == "block" then
e = minetest.add_entity(m.pos, "artifact:device_block"):get_luaentity()
end
if e then
artifact.grab_device(m, e)
end
end

View file

@ -0,0 +1,2 @@
name = artifact_devices
depends = artifact_mechanisms

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

104
mods/artifact_help/init.lua Normal file
View file

@ -0,0 +1,104 @@
local help_toasts = {}
function artifact.show_help_message(m, msg, icon)
local box = {}
local w = math.max(400, #msg *10) +(icon and 50 or 0)
box.left = artifact.hud_add(m, {
type = "image",
pos = {x=1,y=0.7},
offset={x=-w +500,y=0},
align = {x=1,y=1},
scale = {x=4,y=4},
image = "artifact_chat_box_side.png"
})
box.middle = artifact.hud_add(m, {
type = "image",
pos = {x=1,y=0.7},
offset={x=-w +4 +500,y=0},
align = {x=1,y=1},
scale = {x=w -24,y=4},
image = "artifact_chat_box_middle.png"
})
box.right = artifact.hud_add(m, {
type = "image",
pos = {x=1,y=0.7},
offset={x=-16 +500,y=0},
align = {x=-1,y=1},
scale = {x=4,y=4},
image = "artifact_chat_box_side.png"
})
box.text = artifact.hud_add(m, {
type = "text",
pos = {x=1,y=0.7},
padding_y = 10,
offset={x=-w +8 +500 +(icon and 50 or 0),y=32},
align = {x=1,y=0},
scale = {x=4,y=4},
text = msg
})
if icon then
box.icon = artifact.hud_add(m, {
type = "image",
pos = {x=1,y=0.7},
offset={x=-w +36 +500,y=32},
align = {x=0,y=0},
scale = {x=2,y=2},
image = "artifact_icon_"..icon..".png"
})
end
if #help_toasts > 0 then
for i, toast in pairs(help_toasts) do
for _, x in pairs(toast) do
x:animate {
offset = {
value = {x=x.offset.x, y=x.offset.y -75},
duration = 0.3,
}
}
end
end
end
table.insert(help_toasts, box)
for _, x in pairs(box) do
x:animate {
offset = {
value = {x=x.offset.x -500, y=x.offset.y},
duration = 0.4,
ease_fn = {0.42,0, 0.58,1.5}
}
}
end
minetest.after(10, function()
for _, x in pairs(box) do
x:animate {
offset = {
value = {x=x.offset.x +500, y=x.offset.y},
duration = 0.4,
ease_fn = {0.42,-0.5, 0.58,1}
}
}
end
minetest.after(0.4, function()
for _, x in pairs(box) do
x:remove(m)
end
table.remove(help_toasts, table.indexof(help_toasts, box))
end)
end)
end
function artifact.show_hint_particles(def)
minetest.add_particlespawner(extend({
texture = "[fill:1x1:0,0:#fff"
}, def))
end
if artifact.debug then
minetest.register_chatcommand("h", {
func = function(name, args)
artifact.show_help_message(artifact.players[name], args or "This is a test")
end
})
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View file

@ -19,9 +19,18 @@ minetest.register_entity(":artifact:lever_display", {
e.object:remove()
return
end
e._name = ""..math.random()
e.object:set_armor_groups{immortal = 1}
extend(e, minetest.deserialize(data) or {})
if not e.rotation then e.rotation = vector.zero() end
e.object:set_properties {
selectionbox = artifact.rotate_selectionbox({
-3/16, -0.5, -4/16,
3/16, -3/16, 4/16
}, e.rotation)
}
levers[e.object:get_pos():round():to_string()] = e
end,
on_deactivte = function(e)
@ -108,7 +117,6 @@ artifact.register_node("lever", {
end,
on_load = function(pos)
local m = minetest.get_meta(pos)
-- Dynamically initialize doors that were mapgen'd in.
if not m:contains("initialized") then
m:set_string("initialized", "true")
local rot = artifact.facedir_to_rotation(minetest.get_node(pos).param2)
@ -127,3 +135,39 @@ artifact.register_node("lever", {
return true
end
})
artifact.register_node("target", {
tiles = {"artifact_target.png"},
on_impact = function(pos)
local receivers = minetest.deserialize(minetest.get_meta(pos):get("receivers") or "return nil")
if receivers then
artifact.dispatch_event(receivers, {type = "pulse"})
end
end
})
artifact.register_node("target_off", {
tiles = {"artifact_target_off.png"},
on_impact = function(pos)
local receivers = minetest.deserialize(minetest.get_meta(pos):get("receivers") or "return nil")
if receivers then
artifact.dispatch_event(receivers, {type = "on"})
end
minetest.swap_node(pos, {name = "target_on"})
end
})
artifact.register_node("target_on", {
tiles = {"artifact_target_on.png"},
on_impact = function(pos)
local receivers = minetest.deserialize(minetest.get_meta(pos):get("receivers") or "return nil")
if receivers then
artifact.dispatch_event(receivers, {type = "off"})
end
minetest.swap_node(pos, {name = "target_off"})
end
})

View file

@ -18,12 +18,25 @@ minetest.register_entity(":artifact:door", {
selectionbox = {
-0.5, -0.5, -0.5,
0.5, 1.5, -6/16
}
},
physical = true
},
_interact_time = 0.2,
_interact_marker_offset = function(e)
return (e._open and vector.new(-0.5, 0.5, 0) or vector.new(0, 0.5, 0.5)):rotate(e.object:get_rotation())
return (e._open and vector.new(e.inverted and 0.5 or -0.5, 0.5, 0) or vector.new(0, 0.5, 0.5)):rotate(e.object:get_rotation())
end,
box_open_normal = {
-0.5, -0.5, -0.5,
-6/16, 1.5, 0.5
},
box_open_inverted = {
0.5, -0.5, -0.5,
6/16, 1.5, 0.5
},
box_closed_normal = {
-0.5, -0.5, 0.5,
0.5, 1.5, 6/16
},
on_activate = function(e, data)
local node = minetest.get_node(e.object:get_pos())
if not node.name:find "door" then
@ -43,12 +56,21 @@ minetest.register_entity(":artifact:door", {
if e.rotation then
e.rotation.y = e.rotation.y +math.pi
e:rotate(e.rotation)
else
e.rotation = vector.zero()
end
local box = artifact.rotate_selectionbox(e.box_closed_normal, e.rotation)
e.object:set_properties {
selectionbox = box,
collisionbox = box
}
e._name = ""..math.random()
local nm = minetest.get_meta(e.object:get_pos())
if (node.name:find "_open") and not e._open then
local open = nm:get("open") == "true"
if open and not e._open then
e:open(true)
elseif not (node.name:find "_open") and e._open then
elseif not open and e._open then
e:close(true)
end
if nm:get_string("locked") == "true" then
@ -57,6 +79,7 @@ minetest.register_entity(":artifact:door", {
if e._locked then
e._no_interact = true
end
if e.inverted then e:invert() end
doors[e.object:get_pos():round():to_string()] = e
end,
on_deactivate = function(e)
@ -78,14 +101,11 @@ minetest.register_entity(":artifact:door", {
e.object:set_animation({x=snap and 0.5 or 0,y=0.5}, 1.5, 0.1, false)
minetest.after(snap and 0 or 0.1, function()
local pos = e.object:get_pos():round()
local node = minetest.get_node(pos)
node.name = "door_"..e.type.."_open"
minetest.swap_node(pos, node)
minetest.get_meta(pos):set_string("open", "true")
local box = artifact.rotate_selectionbox(e.inverted and e.box_open_inverted or e.box_open_normal, e.rotation)
e.object:set_properties {
selectionbox = artifact.rotate_selectionbox({
0.5, -0.5, -0.5,
6/16, 1.5, 0.5
}, e.rotation)
selectionbox = box,
collisionbox = table.copy(box)
}
end)
if not e._locked then
@ -102,14 +122,11 @@ minetest.register_entity(":artifact:door", {
e.object:set_animation({x=snap and 1 or 0.5,y=1}, 1.5, 0.1, false)
minetest.after(snap and 0 or 0.1, function()
local pos = e.object:get_pos():round()
local node = minetest.get_node(pos)
node.name = "door_"..e.type
minetest.swap_node(pos, node)
minetest.get_meta(pos):set_string("open", "false")
local box = artifact.rotate_selectionbox(e.box_closed_normal, e.rotation)
e.object:set_properties {
selectionbox = artifact.rotate_selectionbox({
-0.5, -0.5, -0.5,
0.5, 1.5, -6/16
}, e.rotation)
selectionbox = box,
collisionbox = box
}
end)
if not e._locked then
@ -118,8 +135,17 @@ minetest.register_entity(":artifact:door", {
end)
end
end,
invert = function(e)
e.inverted = true
local box = artifact.rotate_selectionbox(e.box_closed_normal, e.rotation)
e.object:set_properties {
mesh = "artifact_door_inverted.gltf",
selectionbox = box,
collisionbox = box
}
end,
get_staticdata = function(e)
return minetest.serialize{type = e.type, _locked = e._locked, rotation = e.rotation}
return minetest.serialize{type = e.type, _locked = e._locked, rotation = e.rotation, inverted = e.inverted}
end,
unlock = function(e)
if e._locked then
@ -129,11 +155,32 @@ minetest.register_entity(":artifact:door", {
end,
rotate = function(e, rot)
e.object:set_rotation(rot)
rot.y = rot.y -math.pi
e.rotation = rot
e.object:set_properties {
selectionbox = artifact.rotate_selectionbox(e.object:get_properties().selectionbox, e.rotation)
selectionbox = box
}
end,
on_whack = function(e)
if e.type == "wood" then
local pos = e.object:get_pos():round()
minetest.remove_node(pos)
minetest.add_particlespawner {
pos = {
min = pos:offset(-0.5, -0.5, -0.5),
max = pos:offset(0.5, 1.5, 0.5)
},
vel = {
min = vector.new(-1, 0, -1) *1.5,
max = vector.new(1, 2, 1) *1.5
},
acc = vector.new(0,-9.81,0),
collisiondetection = true,
amount = 50,
texture = "artifact_door_wood.png^[sheet:2x8:0,3",
time = 0.1
}
return true
end
end
})
@ -143,15 +190,11 @@ local function register_basic_door(type)
-- Dynamically initialize doors that were mapgen'd in.
if not m:contains("initialized") then
m:set_string("initialized", "true")
local rot = minetest.facedir_to_dir(minetest.get_node(pos).param2):dir_to_rotation()
rot.y = rot.y -math.pi
local rot = artifact.facedir_to_rotation(minetest.get_node(pos).param2)
minetest.add_entity(pos, "artifact:door", minetest.serialize{type = type}):get_luaentity():rotate(rot)
end
end
local function ondestruct(pos, reason)
if reason == "whack" then
-- TODO: Particles
end
doors[pos:to_string()].object:remove()
doors[pos:to_string()] = nil
end
@ -176,16 +219,17 @@ local function register_basic_door(type)
end
end
artifact.register_node("door_"..type, {
drawtype = "nodebox",
node_box = {
drawtype = "airlike",
walkable = false,
selection_box = {
type = "fixed",
fixed = {
-0.5, -0.5, -0.5,
0.5, 1.5, -6/16
-0.5, -0.5, 0.5,
0.5, 1.5, 6/16
}
},
paramtype2 = "facedir",
tiles = {"blank.png"},
tiles = {"artifact_door_"..type..".png"},
use_texture_alpha = "clip",
paramtype = "light",
pointable = false,
@ -193,27 +237,22 @@ local function register_basic_door(type)
on_construct = onload,
on_destruct = ondestruct,
on_load = onload,
on_signal = onsignal
})
artifact.register_node("door_"..type.."_open", {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
0.5, -0.5, -0.5,
6/16, 1.5, 0.5
}
},
paramtype2 = "facedir",
tiles = {"blank.png"},
use_texture_alpha = "clip",
paramtype = "light",
pointable = false,
groups = {call_on_load = 1, whackable = type == "wood" and 1 or nil},
on_construct = onload,
on_destruct = ondestruct,
on_load = onload,
on_signal = onsignal
on_signal = onsignal,
on_place = function(s, p, pt)
local out, pos = minetest.item_place_node(s, p, pt)
if artifact.players[p:get_player_name()].ctl.sneak then
minetest.get_meta(pos):set_string("inverted", "true")
doors[pos:to_string()]:invert()
end
return out
end,
on_rotate = function(pos, node, p, click, param2)
node.param2 = param2
minetest.swap_node(pos, node)
local rot = artifact.facedir_to_rotation(param2)
doors[pos:to_string()]:rotate(rot)
return true
end
})
end

View file

@ -96,6 +96,7 @@ if artifact.debug then
local link_colors = {
"gold",
"red",
"green",
"blue"
}
@ -171,7 +172,7 @@ if artifact.debug then
on_secondary_use = function(s, p, pt)
local m = s:get_meta()
-- Just cycle through the colors list.
local color = link_colors[(table.indexof(link_colors, m:get("color") or "gold") +1) %#link_colors +1]
local color = link_colors[table.indexof(link_colors, m:get("color") or "gold") %#link_colors +1]
m:set_string("color", color)
m:set_string("inventory_image", "[fill:16x16:0,0:"..color.."#00^artifact_linker_tool.png")
return s

View file

@ -0,0 +1,238 @@
local large_doors = {}
minetest.register_entity(":artifact:large_door_display", {
initial_properties = {
visual = "mesh",
mesh = "artifact_door_large.gltf",
textures = {"artifact_door_large.png"},
selectionbox = {
-1.5, -0.5, -2/16,
1.5, 2.5, 2/16
},
pointable = artifact.debug
},
on_activate = function(e, data)
local pos = e.object:get_pos():round()
local node = minetest.get_node(pos)
if not node.name:find "large_door" then
e.object:remove()
return
end
e.object:set_armor_groups{immortal = 1}
extend(e, minetest.deserialize(data) or {})
if e.rotation then
e.rotation.y = e.rotation.y +math.pi
e:rotate(e.rotation)
else
e.rotation = vector.zero()
end
e._name = ""..math.random()
if e._locked == nil then
e._locked = true
end
local nm = minetest.get_meta(e.object:get_pos())
if (node.name:find "_open") and not e._open then
e:open(true)
elseif not (node.name:find "_open") and e._open then
e:close(true)
end
-- In case our saved state differs from the node's stored state, e.g. if a trigger
-- updated an effector in an unloaded area and couldn't get at the display entity,
-- we should always be sure to match the node meta.
if nm:get_string("locked") == "true" then
e._locked = true
end
if nm:contains("locks") then
e.locks = minetest.deserialize(nm:get_string("locks"))
end
if e.locks then
e:set_locks(e.locks)
end
e.collider_a = minetest.add_entity(pos, "display")
e.collider_a:set_properties {
physical = true,
collisionbox = artifact.rotate_selectionbox({
-0.75, -1.5, -2/16,
0.75, 1.5, 2/16
}, e.rotation)
}
e.collider_a:set_attach(e.object, "a")
e.collider_b = minetest.add_entity(pos, "display")
e.collider_b:set_properties {
physical = true,
collisionbox = artifact.rotate_selectionbox({
-0.75, -1.5, -2/16,
0.75, 1.5, 2/16
}, e.rotation)
}
e.collider_b:set_attach(e.object, "b")
large_doors[e.object:get_pos():round():to_string()] = e
end,
on_deactivate = function(e)
large_doors[e.object:get_pos():round():to_string()] = nil
if e.collider_a then
e.collider_a:remove()
e.collider_a = nil
end
if e.collider_b then
e.collider_b:remove()
e.collider_b = nil
end
end,
get_staticdata = function(e)
return minetest.serialize{type = e.type, _locked = e._locked, rotation = e.rotation, locks = e.locks}
end,
open = function(e)
-- We're already open, so there's nothing to do.
if e._open then return end
e._open = true
e._animating = true
e.object:set_animation({x=0,y=1}, 1.25, 0.1, false)
local pos = e.object:get_pos():round()
minetest.get_meta(pos):set_string("open", "true")
minetest.after(0.75, function()
e._animating = nil
end)
end,
close = function(e)
if not e._open then return end
e._open = false
e._animating = true
e.object:set_animation({x=1,y=2}, 1.25, 0.1, false)
local pos = e.object:get_pos():round()
minetest.get_meta(pos):set_string("open", "false")
minetest.after(0.75, function()
e._animating = nil
end)
end,
on_step = function(e)
-- If we're locked or in a transition state, there's no need to run these checks.
if e._locked or e._animating then return end
-- We don't use objects_inside_radius to avoid wasting time finding and ignoring display entities.
-- Instead, we just do a radius check on each player.
local pos = e.object:get_pos()
local found = artifact.sidekick.pos and artifact.sidekick.pos:distance(pos) < 4
for _, m in pairs(artifact.players) do
if m.object:get_pos():distance(pos) < 4 then
found = true
break
end
end
if found and not e._open then
e:open()
elseif not found and e._open then
e:close()
end
end,
rotate = function(e, rot)
e.object:set_rotation(rot)
e.rotation = rot
e.object:set_properties {
selectionbox = artifact.rotate_selectionbox({
-1.5, -0.5, -2/16,
1.5, 2.5, 2/16
}, e.rotation)
}
if e.collider_a then
e.collider_a:set_properties {
collisionbox = artifact.rotate_selectionbox({
-0.75, -1.5, -2/16,
0.75, 1.5, 2/16
}, e.rotation)
}
end
if e.collider_b then
e.collider_b:set_properties {
collisionbox = artifact.rotate_selectionbox({
-0.75, -1.5, -2/16,
0.75, 1.5, 2/16
}, e.rotation)
}
end
end,
-- We include this so we can update the entity's locks without having to unload and reload them.
on_punch = function(e)
local locks = minetest.deserialize(minetest.get_meta(e.object:get_pos():round()):get_string("locks"))
e:set_locks(locks)
end,
set_locks = function(e, locks)
e.locks = locks
local mod = ""
local locked = false
for i, color in ipairs(locks) do
if not locks[color] then locked = true end
mod = mod..":"..((i -1) *5 +74)..",0=artifact_lock_"..color.."_"..(locks[color] and "on" or "off")..".png"
end
e._locked = locked
e.object:set_properties {
textures = {"[combine:128x128:0,0=artifact_door_large.png"..mod}
}
end,
})
local function onload(pos)
local m = minetest.get_meta(pos)
-- Dynamically initialize doors that were mapgen'd in.
if not m:contains("initialized") then
m:set_string("initialized", "true")
local rot = artifact.facedir_to_rotation(minetest.get_node(pos).param2)
local locks = {red = false, blue = false, green = false, "red", "green", "blue"}
minetest.add_entity(pos, "artifact:large_door_display", minetest.serialize{locks = locks}):get_luaentity():rotate(rot)
minetest.get_meta(pos):set_string("locks", minetest.serialize(locks))
end
end
local function ondestruct(pos)
large_doors[pos:to_string()].object:remove()
large_doors[pos:to_string()] = nil
end
local function onsignal(pos, event, channel)
if event.type == "on" or event.type == "pulse" then
local e = large_doors[vector.to_string(pos)]
if e then
local locks = e.locks
if locks[channel] ~= nil then
locks[channel] = true
end
e:set_locks(locks)
minetest.get_meta(pos):set_string("locks", minetest.serialize(locks))
else
local m = minetest.get_meta(pos)
local locks = minetest.deserialize(m:get_string("locks"))
if locks[channel] ~= nil then
locks[channel] = true
end
e:set_locks(locks)
m:set_string("locks", minetest.serialize(locks))
end
end
end
artifact.register_node("large_door", {
drawtype = "airlike",
paramtype = "light",
walkable = false,
selection_box = {
type = "fixed",
fixed = {
-1.5, -0.5, -2/16,
1.5, 3.5, 2/16
}
},
paramtype2 = "facedir",
groups = {call_on_load = 1},
on_construct = onload,
on_load = onload,
on_destruct = ondestruct,
on_signal = onsignal
})

View file

@ -1 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[2],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[4.375,0,-4.375],"name":"cube","mesh":0},{"translation":[-4.375,0,-4.375],"name":"door","children":[0]},{"children":[1]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":64},{"buffer":0,"byteOffset":904,"byteLength":256}],"buffers":[{"byteLength":1160,"uri":"data:application/octet-stream;base64,AACgQAAAcEEAAKBAAACgQAAAcEEAAHBAAACgQAAAoMAAAKBAAACgQAAAoMAAAHBAAACgwAAAcEEAAHBAAACgwAAAcEEAAKBAAACgwAAAoMAAAHBAAACgwAAAoMAAAKBAAACgwAAAcEEAAHBAAACgQAAAcEEAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgwAAAoMAAAHBAAACgQAAAoMAAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgQAAAcEEAAHBAAACgwAAAcEEAAHBAAACgQAAAoMAAAHBAAACgwAAAoMAAAHBAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAD8AAAA9AAAAPwAAAAAAAIA/AAAAPQAAgD8AAAA/AAAAAAAACD8AAAAAAAAAPwAAAD8AAAg/AAAAPwAAkD4AAAg/AAAAPQAACD8AAJA+AAAAPwAAAD0AAAA/AAAIPwAAAD8AAJA+AAAAPwAACD8AAAg/AACQPgAACD8AAIA+AAAAAAAAAD8AAAAAAACAPgAAAD8AAAA/AAAAPwAAAAAAAAAAAACAPgAAAAAAAAAAAAAAPwAAgD4AAAA/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAAAAAKuqKj2rqqo9AAAAPlVVVT5VVZU+q6qqPgAAwD5VVdU+AAAAP1VVFT+rqio/AABAP1VVVT+rqmo/AACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAPnsAvAAAAAD8/X8/AAAAAAQLCL0AAAAA2Nt/PwAAAABsyaW9AAAAAOsofz8AAAAAKj6FvgAAAADkLXc/AAAAAOxY/74AAAAA/eNdPwAAAABOiRa/AAAAAPUPTz8AAAAAisUlvwAAAAAxFEM/AAAAADvoLr8AAAAAie46PwAAAADzBDW/AAAAAPMENT8AAAAAriAvvwAAAACnuTo/AAAAAIrMFr8AAAAAAt9OPwAAAAAV78O+AAAAAF6DbD8AAAAAkpgevgAAAAA16Xw/AAAAABU2A70AAAAAXt5/PwAAAAAAAAAAAAAAAAAAgD8="}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[5,15,5],"min":[-5,-5,3.75],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.53125,1],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":16,"max":[1],"min":[0],"type":"SCALAR"},{"bufferView":5,"componentType":5126,"count":16,"max":[0,0,0,1],"min":[0,-0.7071067690849304,0,0.7071067690849304],"type":"VEC4"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"artifact_door_wood"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"artifact_door_wood.png","uri":"artifact_door_wood.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}],"animations":[{"name":"animation","samplers":[{"input":4,"output":5,"interpolation":"LINEAR"}],"channels":[{"sampler":0,"target":{"node":1,"path":"rotation"}}]}]}
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[2],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[4.375,0,-4.375],"name":"cube","mesh":0},{"translation":[-4.375,0,-4.375],"name":"door","children":[0]},{"children":[1]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":64},{"buffer":0,"byteOffset":904,"byteLength":256}],"buffers":[{"byteLength":1160,"uri":"data:application/octet-stream;base64,AACgQAAAcEEAAKBAAACgQAAAcEEAAHBAAACgQAAAoMAAAKBAAACgQAAAoMAAAHBAAACgwAAAcEEAAHBAAACgwAAAcEEAAKBAAACgwAAAoMAAAHBAAACgwAAAoMAAAKBAAACgwAAAcEEAAHBAAACgQAAAcEEAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgwAAAoMAAAHBAAACgQAAAoMAAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgQAAAcEEAAHBAAACgwAAAcEEAAHBAAACgQAAAoMAAAHBAAACgwAAAoMAAAHBAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAD8AAAA9AAAAPwAAAAAAAIA/AAAAPQAAgD8AAAA/AAAAAAAACD8AAAAAAAAAPwAAAD8AAAg/AAAAPwAAkD4AAAg/AAAAPQAACD8AAJA+AAAAPwAAAD0AAAA/AAAIPwAAAD8AAJA+AAAAPwAACD8AAAg/AACQPgAACD8AAIA+AAAAAAAAAD8AAAAAAACAPgAAAD8AAAA/AAAAPwAAAAAAAAAAAACAPgAAAAAAAAAAAAAAPwAAgD4AAAA/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAAAAAKuqKj2rqqo9AAAAPlVVVT5VVZU+q6qqPgAAwD5VVdU+AAAAP1VVFT+rqio/AABAP1VVVT+rqmo/AACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAPnsAvAAAAAD8/X8/AAAAAAQLCL0AAAAA2Nt/PwAAAABsyaW9AAAAAOsofz8AAAAAKj6FvgAAAADkLXc/AAAAAOxY/74AAAAA/eNdPwAAAABOiRa/AAAAAPUPTz8AAAAAisUlvwAAAAAxFEM/AAAAADvoLr8AAAAAie46PwAAAADzBDW/AAAAAPMENT8AAAAAriAvvwAAAACnuTo/AAAAAIrMFr8AAAAAAt9OPwAAAAAV78O+AAAAAF6DbD8AAAAAkpgevgAAAAA16Xw/AAAAABU2A70AAAAAXt5/PwAAAAAAAAAAAAAAAAAAgD8="}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[5,15,5],"min":[-5,-5,3.75],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.53125,1],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":16,"max":[1],"min":[0],"type":"SCALAR"},{"bufferView":5,"componentType":5126,"count":16,"max":[0,0,0,1],"min":[0,-0.7071067690849304,0,0.7071067690849304],"type":"VEC4"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"artifact_door_wood.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"artifact_door_iron.png","uri":"artifact_door_iron.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}],"animations":[{"name":"animation","samplers":[{"input":4,"output":5,"interpolation":"LINEAR"}],"channels":[{"sampler":0,"target":{"node":1,"path":"rotation"}}]}]}

View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[2],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[-4.375,0,-4.375],"name":"cube","mesh":0},{"translation":[4.375,0,-4.375],"name":"door","children":[0]},{"children":[1]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":64},{"buffer":0,"byteOffset":904,"byteLength":256}],"buffers":[{"byteLength":1160,"uri":"data:application/octet-stream;base64,AACgQAAAcEEAAKBAAACgQAAAcEEAAHBAAACgQAAAoMAAAKBAAACgQAAAoMAAAHBAAACgwAAAcEEAAHBAAACgwAAAcEEAAKBAAACgwAAAoMAAAHBAAACgwAAAoMAAAKBAAACgwAAAcEEAAHBAAACgQAAAcEEAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgwAAAoMAAAHBAAACgQAAAoMAAAHBAAACgwAAAcEEAAKBAAACgQAAAcEEAAKBAAACgwAAAoMAAAKBAAACgQAAAoMAAAKBAAACgQAAAcEEAAHBAAACgwAAAcEEAAHBAAACgQAAAoMAAAHBAAACgwAAAoMAAAHBAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAIPwAAAAAAAAA/AAAAAAAACD8AAAA/AAAAPwAAAD8AAAA9AAAAPwAAAAAAAAA/AAAAPQAAgD8AAAAAAACAPwAAAD0AAAg/AACQPgAACD8AAAA9AAAAPwAAkD4AAAA/AACQPgAAAD8AAAg/AAAAPwAAkD4AAAg/AAAIPwAACD8AAAA/AAAAAAAAgD4AAAAAAAAAPwAAAD8AAIA+AAAAPwAAgD4AAAAAAAAAAAAAAAAAAIA+AAAAPwAAAAAAAAA/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAAAAAKuqKj2rqqo9AAAAPlVVVT5VVZU+q6qqPgAAwD5VVdU+AAAAP1VVFT+rqio/AABAP1VVVT+rqmo/AACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAlSfqOwAAAABU/n8/AAAAABU2Az0AAAAAXt5/PwAAAABM8aI9AAAAAD8wfz8AAAAAUtyEPgAAAAAOO3c/AAAAALqw/z4AAAAAtcpdPwAAAACKzBY/AAAAAALfTj8AAAAAFAsmPwAAAAAE2UI/AAAAAK4gLz8AAAAAp7k6PwAAAADzBDU/AAAAAPMENT8AAAAAO+guPwAAAACJ7jo/AAAAAE6JFj8AAAAA9Q9PPwAAAAAV78M+AAAAAF6DbD8AAAAAMOEfPgAAAABG3Hw/AAAAAAQLCD0AAAAA2Nt/PwAAAAAAAAAAAAAAAAAAgD8="}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[5,15,5],"min":[-5,-5,3.75],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.53125,1],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":16,"max":[1],"min":[0],"type":"SCALAR"},{"bufferView":5,"componentType":5126,"count":16,"max":[0,0.7071067690849304,0,1],"min":[0,0,0,0.7071067690849304],"type":"VEC4"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"artifact_door_wood.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"artifact_door_iron.png","uri":"artifact_door_iron.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}],"animations":[{"name":"animation","samplers":[{"input":4,"output":5,"interpolation":"LINEAR"}],"channels":[{"sampler":0,"target":{"node":1,"path":"rotation"}}]}]}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

View file

@ -16,6 +16,7 @@ Player = setmetatable({
m.name = p:get_player_name()
m.meta = p:get_meta()
m.character = m.meta:get("character") or "key"
m.spawn_point = m.meta:get("spawnpoint") or artifact.origin
m.inv = p:get_inventory()
m.inv:set_stack("main", 1, ItemStack("input_"..m.character))
@ -125,7 +126,8 @@ Player = setmetatable({
local pointed_found = nil
m.pointed_node = nil
for x in minetest.raycast(m.pos, m.pos +(dir *5)) do
if x and x.type == "object" then
-- We should ignore all objects when placing a grabbed node.
if x and x.type == "object" and not m._grabbed_item then
local e = x.ref:get_luaentity()
-- Ignore players.
if e then
@ -231,6 +233,34 @@ Player = setmetatable({
rotation = {vec = vector.new(0,yaw -m.rot,0), interpolation = 0.1, absolute = true}
})
-- Handle grabbed devices. This trumps other input handling like the radial menu and on_interact.
if m._grabbed_item then
m._grabbed_item:move_to(m.pos +(dir *2))
if ctl.place and m.pointed_node then
m._grabbed_item:move_to(m.pointed_node.above)
m._grabbed_item = nil
-- This should be set dynamically by whatever function put us into the grabbing
-- state, and accordingly should only be valid for the duration of that state.
if m._on_ungrab then
m._on_ungrab()
m._on_ungrab = nil
end
end
-- This code is duplicated from the bottom... but since the
-- only cleaner alternative is goto, I decided to support PUC Lua.
if m.next_regen and time -m.next_regen >= 0 then
m.object:set_hp(m.object:get_hp() +1)
end
m.ctl = ctl
m.yaw = yaw
m.pitch = pitch
m.dir = dir
return
end
-- MARK: Progressive interaction
if ctl.place and m.ctl.place and m.pointed_obj and m.pointed_obj.on_interact and not m.pointed_obj._no_interact then
@ -268,7 +298,7 @@ Player = setmetatable({
-- MARK: Radial menu handling
-- This should only work once we have Vix, since we can't use it without her.
if state >= artifact.story.states.main and ctl.place and not m.ctl.place and wi:get_name():find "artifact:input" and (not m.pointed_obj or m.pointed_obj._no_interact) then
if state >= artifact.story.states.main and ctl.place and not m.ctl.place and wi:get_name():find "artifact:input" and (not m.pointed_obj or not m.pointed_obj.on_interact or m.pointed_obj._no_interact) then
artifact.show_radial_menu(m, {
name = "construct",
"test",
@ -277,7 +307,14 @@ Player = setmetatable({
"test4",
"test5"
})
elseif m._menu and not (ctl.place and wi:get_name():find "artifact:input") or (m.pointed_obj and not m.pointed_obj._no_interact) then
elseif m._menu and not (ctl.place and wi:get_name():find "artifact:input") or (m._menu and m.pointed_obj and m.pointed_obj.on_interact and not m.pointed_obj._no_interact) then
local sel = m._menu[m._menu.selected]
if sel then
local choice = sel.item
if choice == "test" then
artifact.summon_device(m, "block")
end
end
artifact.dismiss_radial_menu(m, "construct")
elseif m._menu then
local dx = m.yaw -yaw
@ -374,12 +411,25 @@ Player = setmetatable({
p:hud_set_hotbar_image("[combine:"..(21 *slots +1).."x22"..list)
p:hud_set_hotbar_selected_image("artifact_hotbar_selected_bg.png")
end,
set_spawnpoint = function(m, pos)
m.spawn_point = pos
m.meta:set_string("spawnpoint", pos:to_string())
end
}, {
__call = function(_, ...)
return Player.new(...)
end
})
-- Override respawning, so we can save progress.
minetest.register_on_respawnplayer(function(p)
local m = artifact.players[p:get_player_name()]
if m.spawn_point then
p:set_pos(m.spawn_point)
return true
end
end)
-- Mirror the player's HP in our custom HUD.
-- (We need a custom HUD so that we can change its appearance dynamically.)
minetest.register_on_player_hpchange(function(p, delta)
@ -403,8 +453,8 @@ function artifact.register_input(name)
description = "",
paramtype = "light",
drawtype = "mesh",
mesh = "artifact_hand.gltf",
tiles = {"artifact_"..name..".png"},
mesh = name == "key" and "artifact_hand_key.gltf" or "artifact_hand.gltf",
tiles = name == "key" and {"artifact_blackrod.png"} or {"artifact_"..name..".png", "artifact_blackrod.png"},
use_texture_alpha = "opaque",
visual_scale = 1,
wield_scale = vector.new(2,2,2),
@ -423,6 +473,11 @@ function artifact.register_input(name)
end,
on_use = function(s, p)
local m = artifact.players[p:get_player_name()]
if m._grabbed_item then return end
if m.pointed_obj and m.pointed_obj._grabbable then
artifact.grab_device(m, m.pointed_obj)
return
end
if m.character == "vix" then
artifact.do_shoot(m)
else
@ -434,6 +489,11 @@ end
artifact.register_input "key"
artifact.register_input "vix"
-- Apparently the hand range is applied very briefly when switching items.
if not artifact.debug then
minetest.override_item("", {range = 0})
end
minetest.register_globalstep(function()
for _, m in pairs(artifact.players) do

View file

@ -18,6 +18,7 @@ function ns.show_radial_menu(m, menu)
local angle = m._menu.step *(i -1) -math.pi
local el = artifact.hud_add(m, {
name = menu.name.."_"..i,
item = x,
type = "image",
pos = {x=0.5,y=0.5},
scale = {x=0.1,y=0.1},

View file

@ -33,7 +33,14 @@ function ns.enter_pre_vix_state()
crosshair = true,
wielditem = true,
}
m.object:set_pos(artifact.origin:offset(0, -73.5, -4))
m:set_spawnpoint(artifact.origin:offset(0, -73.5, -4))
end
minetest.after(5, function()
for _, m in pairs(artifact.players) do
artifact.show_help_message(m, "Certain nodes can be broken by punching them with the blackrod.", "info")
end
end)
end
function ns.enter_state(to)
@ -240,12 +247,11 @@ function ns.play_intro_cutscene()
for _, m in pairs(artifact.players) do
m.object:set_detach()
minetest.close_formspec(m.name, "artifact:lock_camera")
m.object:set_pos(artifact.origin:offset(0, -73.5, -4))
artifact.look_at(m, ns.camera:get_pos(), artifact.origin:offset(0, -73.5, -8))
end
ns.enter_state(ns.states.pre_vix)
minetest.after(3, function()
artifact.push_chat_message("Interesting...", "Key", "artifact_key_splash_low.png")
artifact.push_chat_message("I'd better take a few practice swings.", "Key", "artifact_key_splash_low.png")
end)
end)
end)
@ -327,7 +333,7 @@ function ns.load_map()
m.hud.loading_map_bg.remove_after = 0.3
m.object:set_pos(start)
end
ns.enter_state(artifact.story.states.init)
ns.enter_state(artifact.story.states.pre_vix)
end)
end)
end)

View file

@ -283,7 +283,8 @@ artifact.register_node("vines_dry", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"artifact_vines_dry.png"},
use_texture_alpha = "clip"
use_texture_alpha = "clip",
groups = {whackable = 1}
})
artifact.register_node("leaves", {
@ -296,7 +297,8 @@ artifact.register_node("leaves_dry", {
drawtype = "allfaces",
-- paramtype = "light",
tiles = {"artifact_leaves_dry.png"},
use_texture_alpha = "clip"
use_texture_alpha = "clip",
groups = {whackable = 1}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B