Add multi-signal doors, basic device deployment, and a target trigger.
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
37
mods/artifact_devices/init.lua
Normal 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
|
||||
2
mods/artifact_devices/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
name = artifact_devices
|
||||
depends = artifact_mechanisms
|
||||
104
mods/artifact_help/init.lua
Normal 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
|
||||
|
|
@ -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
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
BIN
mods/artifact_mechanisms/textures/artifact_door_large.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
mods/artifact_mechanisms/textures/artifact_door_locks.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_blue_off.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_blue_on.png
Normal file
|
After Width: | Height: | Size: 120 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_gold_off.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_gold_on.png
Normal file
|
After Width: | Height: | Size: 120 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_green_off.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_green_on.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_red_off.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
mods/artifact_mechanisms/textures/artifact_lock_red_on.png
Normal file
|
After Width: | Height: | Size: 128 B |
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||