Add the intro cutscene, a start to the map, and various other things.

This commit is contained in:
Signal 2025-11-16 02:48:08 -05:00
parent d0c0a3ebb6
commit 1b2199705b
46 changed files with 1401 additions and 91 deletions

BIN
menu/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

BIN
menu/header.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View file

@ -2,6 +2,9 @@
minetest = core minetest = core
artifact = { artifact = {
-- This toggles a lot of things, including whether initialization takes place,
-- whether nodes can be pointed, and whether the player is permitted to
-- bypass certain restrictions imposed by the story.
debug = true debug = true
} }
@ -47,19 +50,38 @@ end
-- HACK: Lookup table for getting a rotation from a -- HACK: Lookup table for getting a rotation from a
-- facedir (because Minetest doesn't have any way -- facedir (because Minetest doesn't have any way
-- to get this) -- to get this information normally)
local facedir_rotations = { local facedir_rotations = {
-- +Y -- +Y
[0] = vector.new(0,0,0), [0] = vector.new(0, 0, 0),
[1] = vector.new(0, math.pi *1.5, 0), [1] = vector.new(0, math.pi * 1.5, 0),
[2] = vector.new(0, math.pi, 0), [2] = vector.new(0, math.pi * 1.0, 0),
[3] = vector.new(0, math.pi *0.5, 0), [3] = vector.new(0, math.pi * 0.5, 0),
-- +Z -- +Z
[4] = vector.new(math.pi *1.5, 0, 0), [4] = vector.new(math.pi * 1.5, 0, 0),
[5] = vector.new(math.pi *1.5, math.pi *1.5, 0), [5] = vector.new(0, math.pi * 1.5, math.pi * 1.5),
[6] = vector.new(math.pi *1.5, math.pi, 0), [6] = vector.new(math.pi * 0.5, math.pi * 1.0, 0),
[7] = vector.new(math.pi *1.5, math.pi *0.5, 0), [7] = vector.new(0, math.pi * 0.5, math.pi * 0.5),
-- -Z
[8] = vector.new(math.pi * 0.5, 0, 0),
[9] = vector.new(0, math.pi * 1.5, math.pi * 0.5),
[10] = vector.new(math.pi * 1.5, math.pi * 1.0, 0),
[11] = vector.new(0, math.pi * 0.5, math.pi * 1.5),
-- +X
[12] = vector.new(0, 0, math.pi * 0.5),
[13] = vector.new(math.pi * 1.5, math.pi * 1.5, 0),
[14] = vector.new(0, math.pi * 1.0, math.pi * 1.5),
[15] = vector.new(math.pi * 0.5, math.pi * 0.5, 0),
-- -X
[16] = vector.new(0, 0, math.pi * 1.5),
[17] = vector.new(math.pi * 0.5, math.pi * 1.5, 0),
[18] = vector.new(0, math.pi * 1.0, math.pi * 0.5),
[19] = vector.new(math.pi * 1.5, math.pi * 0.5, 0),
-- -Y
[20] = vector.new(0, 0, math.pi * 1.0),
[21] = vector.new(0, math.pi * 0.5, math.pi * 1.0),
[22] = vector.new(0, math.pi * 1.0, math.pi * 1.0),
[23] = vector.new(0, math.pi * 1.5, math.pi * 1.0),
} }
function artifact.facedir_to_rotation(facedir) function artifact.facedir_to_rotation(facedir)
return facedir_rotations[facedir] or minetest.facedir_to_dir(facedir):dir_to_rotation() return facedir_rotations[facedir] or minetest.facedir_to_dir(facedir):dir_to_rotation()

View file

@ -1,6 +1,8 @@
local ns = artifact local ns = artifact
local db = minetest.get_mod_storage()
function ns.apply_key(m) function ns.apply_key(m)
m.object:set_properties { m.object:set_properties {
textures = {"artifact_key.png"}, textures = {"artifact_key.png"},
@ -10,6 +12,17 @@ function ns.apply_key(m)
m.eye_height = 1.6 m.eye_height = 1.6
-- Switch hand appearance. -- Switch hand appearance.
m.inv:set_stack("main", 1, ItemStack("input_"..m.character)) 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 end
function ns.apply_vix(m) function ns.apply_vix(m)
@ -21,19 +34,135 @@ function ns.apply_vix(m)
m.eye_height = 1.5 m.eye_height = 1.5
-- Switch hand appearance. -- Switch hand appearance.
m.inv:set_stack("main", 1, ItemStack("input_"..m.character)) m.inv:set_stack("main", 1, ItemStack("input_"..m.character))
m.object:hud_change(m.healthbar, "text", "artifact_heart_vix.png")
if m.blackrod then
m.blackrod:remove()
m.blackrod = nil
end
end end
function ns.swap_character(m) function ns.swap_character(m)
if m.character == "vix" then if m.character == "vix" then
artifact.sidekick.character = "vix"
m:set_character("key") m:set_character("key")
ns.apply_key(m) ns.apply_key(m)
else else
artifact.sidekick.character = "key"
m:set_character("vix") m:set_character("vix")
ns.apply_vix(m) ns.apply_vix(m)
end end
if artifact.sidekick.ref 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())
m.object:set_look_horizontal(artifact.sidekick.yaw)
m.object:set_look_vertical(artifact.sidekick.pitch)
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()
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 end
include "key.lua" include "key.lua"
include "vix.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",
}, {
__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_key.png"},
physical = true,
collisionbox = {
-0.3, 0,-0.3,
0.3, 1.77, 0.3
}
},
_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 == "vix" 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
else
artifact.sidekick.ref = e
end
end,
on_deactivate = function(e)
artifact.sidekick.ref = nil
end,
get_staticdata = function(e)
return minetest.serialize{
cahracter = e.character
}
end,
on_interact = function(e, m)
ns.swap_character(m)
end
})

View file

@ -1,3 +1,6 @@
local ns = artifact local ns = artifact
function ns.do_whack(m)
end

View file

@ -1,2 +1,2 @@
name = artifact_characters name = artifact_characters
depends = artifact_story depends = artifact_base

View file

@ -0,0 +1,49 @@
# Made in Blockbench 4.12.5
mtllib artifact_blackrod.mtl
o cube
v 0.03125000000000003 1 0.03125
v 0.03125000000000003 1 -0.03125
v 0.03125000000000003 -0.75 0.03125
v 0.03125000000000003 -0.75 -0.03125
v -0.03125 1 -0.03125
v -0.03125 1 0.03125
v -0.03125 -0.75 -0.03125
v -0.03125 -0.75 0.03125
vt 0 1
vt 0.03125 1
vt 0.03125 0.125
vt 0 0.125
vt 0.03125 1
vt 0.0625 1
vt 0.0625 0.125
vt 0.03125 0.125
vt 0.0625 1
vt 0.09375 1
vt 0.09375 0.125
vt 0.0625 0.125
vt 0.09375 1
vt 0.125 1
vt 0.125 0.125
vt 0.09375 0.125
vt 0.15625 0.96875
vt 0.125 0.96875
vt 0.125 1
vt 0.15625 1
vt 0.15625 0.96875
vt 0.125 0.96875
vt 0.125 0.9375
vt 0.15625 0.9375
vn 0 0 -1
vn 1 0 0
vn 0 0 1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
usemtl m_99dd5155-5cc9-5980-76ce-3093fe3734a6
f 4/4/1 7/3/1 5/2/1 2/1/1
f 3/8/2 4/7/2 2/6/2 1/5/2
f 8/12/3 3/11/3 1/10/3 6/9/3
f 7/16/4 8/15/4 6/14/4 5/13/4
f 6/20/5 1/19/5 2/18/5 5/17/5
f 7/24/6 4/23/6 3/22/6 8/21/6

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

View file

@ -0,0 +1,99 @@
local ns = artifact
minetest.register_entity(":artifact:burst", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false,
physical = true,
collide_with_objects = false,
collisionbox = {
-0.2, -0.2, -0.2,
0.2, 0.2, 0.2
},
static_save = false,
},
on_activate = function(e, rot)
e.object:set_armor_groups{immortal = 1}
end,
on_deactivate = function(e)
for _, x in ipairs(e._particles) do
minetest.delete_particlespawner(x)
end
end,
on_step = function(e, dtime, movement)
if movement.collides then
minetest.add_particlespawner {
pos = e.object:get_pos(),
radius = 0.1,
texture = {
name = "artifact_light.png",
alpha_tween = {1, 0}
},
glow = 8,
size_tween = {
{min = 2, max = 3},
{min = 4, max = 5}
},
attract = {
kind = "point",
strength = {
min = -50,
max = -20,
},
origin = e.object:get_pos()
},
amount = 25,
exptime = 0.5,
drag = 1,
time = 0.1,
}
e.object:remove()
end
end,
impulse = function(e, vel)
-- The documentation said that `vel` is relative to the parent entity...
-- I guess the documentation is wrong?
local rot = vel:normalize():dir_to_rotation()
local min, max = vector.sort(vector.new(-1,-1,-1):rotate(rot), vector.new(1,1,0):rotate(rot))
e._particles = {
-- Tail
minetest.add_particlespawner {
attached = e.object,
pos = {
min = vector.new(-1,-1,-1) *0.2,
max = vector.new(1,1,1) *0.2
},
vel = {
min = min,
max = max
},
texture = {
name = "artifact_light.png",
alpha_tween = {1, 0}
},
size = 0.4,
glow = 10,
amount = 450,
time = 0
},
-- Head
minetest.add_particlespawner {
attached = e.object,
pos = vector.zero(),
vel = vel,
texture = "[fill:16x16:0,0:#fff",
size = 3,
glow = 14,
amount = 150,
time = 0,
exptime = 0.1
}
}
e.object:set_velocity(vel)
end
})
function ns.do_shoot(m)
minetest.add_entity(m.pos +m.dir, "artifact:burst", tostring(m.yaw)):get_luaentity():impulse(m.dir *30)
end

View file

@ -0,0 +1,2 @@
name = artifact_help
depends = artifact_hud

View file

@ -50,7 +50,7 @@ local function interpolate(ref, target, t, x1, y1, x2, y2)
local eased_t = bezier_ease(t, x1 or 0, y1 or 0, x2 or 1, y2 or 1) local eased_t = bezier_ease(t, x1 or 0, y1 or 0, x2 or 1, y2 or 1)
return ref + (target - ref) * eased_t return ref + (target - ref) * eased_t
end end
artifact.interpolate = interpolate
function ns.register_hud_type(def) function ns.register_hud_type(def)
ns.hud_types[def.name] = setmetatable(def, {__index = ns.Element}) ns.hud_types[def.name] = setmetatable(def, {__index = ns.Element})
@ -184,7 +184,7 @@ minetest.register_globalstep(function(dtime)
end) end)
function ns.color_to_number(color) function ns.color_to_number(color)
return tonumber(string.format("0x%.2x%.2x%.2x%.2x", color.r, color.g, color.b, color.a)) return tonumber(string.format("0x%.2x%.2x%.2x", color.r, color.g, color.b))
end end
ns.register_hud_type { ns.register_hud_type {
@ -193,12 +193,14 @@ ns.register_hud_type {
field_types = { field_types = {
offset = "vec2", offset = "vec2",
pos = "vec2", pos = "vec2",
size = "vec2",
color = "color" color = "color"
}, },
defaults = { defaults = {
dir = 0, dir = 0,
align = {x=0, y=0}, align = {x=0, y=0},
offset = {x=0, y=0}, offset = {x=0, y=0},
size = {x=1, y=1},
color = {r = 0xff, g = 0xff, b = 0xff, a = 0xff} color = {r = 0xff, g = 0xff, b = 0xff, a = 0xff}
}, },
add = function(e, m) add = function(e, m)
@ -209,6 +211,7 @@ ns.register_hud_type {
alignment = e.align, alignment = e.align,
offset = e.offset, offset = e.offset,
scale = {x=100, y=100}, scale = {x=100, y=100},
size = e.size,
text = e.text, text = e.text,
number = ns.color_to_number(e.color) number = ns.color_to_number(e.color)
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

After

Width:  |  Height:  |  Size: 167 B

Before After
Before After

View file

@ -77,6 +77,20 @@ artifact.register_node("lever", {
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
paramtype2 = "facedir", paramtype2 = "facedir",
collision_box = {
type = "fixed",
fixed = {
-3/16, -0.5, -4/16,
3/16, -3/16, 4/16
}
},
selection_box = {
type = "fixed",
fixed = {
-3/16, -0.5, -4/16,
3/16, -3/16, 4/16
}
},
pointable = false, pointable = false,
on_construct = function(pos) on_construct = function(pos)
local m = minetest.get_meta(pos) local m = minetest.get_meta(pos)

View file

@ -44,9 +44,6 @@ minetest.register_entity(":artifact:door", {
e.rotation.y = e.rotation.y +math.pi e.rotation.y = e.rotation.y +math.pi
e:rotate(e.rotation) e:rotate(e.rotation)
end end
if e._locked then
e._no_interact = true
end
e._name = ""..math.random() e._name = ""..math.random()
local nm = minetest.get_meta(e.object:get_pos()) local nm = minetest.get_meta(e.object:get_pos())
if (node.name:find "_open") and not e._open then if (node.name:find "_open") and not e._open then
@ -54,6 +51,12 @@ minetest.register_entity(":artifact:door", {
elseif not (node.name:find "_open") and e._open then elseif not (node.name:find "_open") and e._open then
e:close(true) e:close(true)
end end
if nm:get_string("locked") == "true" then
e._locked = true
end
if e._locked then
e._no_interact = true
end
doors[e.object:get_pos():round():to_string()] = e doors[e.object:get_pos():round():to_string()] = e
end, end,
on_deactivate = function(e) on_deactivate = function(e)

View file

View file

@ -1,6 +1,8 @@
minetest.register_entity(":display", { minetest.register_entity(":display", {
initial_properties = { initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false, pointable = false,
static_save = false static_save = false
}, },
@ -30,6 +32,7 @@ end
include "basics.lua" include "basics.lua"
include "doors.lua" include "doors.lua"
include "large_doors.lua"
include "chest.lua" include "chest.lua"
@ -58,28 +61,35 @@ function artifact.load_schematic(dst, path, rot)
end end
end end
function artifact.get_schem_size(path)
minetest.register_entity(":test", { local f = io.open(path..".mts", "rb")
initial_properties = {
static_save = false, local function read_u16(file)
visual = "mesh", local data = file:read(2)
mesh = "artifact_character.gltf", if not data or #data < 2 then return nil end
}, local a, b = data:byte(1, 2)
on_activate = function(e) return a + b
-- e.object:set_bone_override("root", { end
-- position = {vec = vector.new(15,15,15)} local magic = f:read(4)
-- }) if magic ~= "MTSM" then
end, f:close()
on_rightclick = function(e, p) error("Not a valid .mts file (missing` MTSM` header).")
local v = vector.new(0, p:get_properties().eye_height *10, 0)
p:set_eye_offset(v,v,v)
p:set_attach(e.object, "Head")
end,
on_punch = function(e, p)
p:set_detach()
end end
})
local version = read_u16(f)
if not version or version > 4 then
f:close()
error("Unsupported .mts version: "..tostring(version))
end
local size_x = read_u16(f)
local size_y = read_u16(f)
local size_z = read_u16(f)
f:close()
return vector.new(size_x, size_y, size_z)
end
if artifact.debug then if artifact.debug then
@ -103,6 +113,32 @@ if artifact.debug then
} }
}, },
}) })
minetest.override_item("testtools:remover", {
pointabilities = {
nodes = {
-- This gets added to everything in debug mode.
["group:dig_immediate"] = true,
air = false,
},
objects = {
-- The display entities should all be immortal.
["group:immortal"] = false
}
},
})
minetest.override_item("testtools:node_meta_editor", {
pointabilities = {
nodes = {
-- This gets added to everything in debug mode.
["group:dig_immediate"] = true,
air = false,
},
objects = {
-- The display entities should all be immortal.
["group:immortal"] = false
}
},
})
minetest.override_item("testtools:param2tool", { minetest.override_item("testtools:param2tool", {
pointabilities = { pointabilities = {
nodes = { nodes = {

View file

View file

@ -36,27 +36,68 @@ Player = setmetatable({
shaded = false shaded = false
} }
p:hud_set_flags {
healthbar = false,
breathbar = false,
hotbar = artifact.debug,
minimap = false,
basic_debug = artifact.debug,
crosshair = false, -- It gets set to true once we can play.
wielditem = false, -- Ditto.
chat = false, -- We provide our own implementation of the chat HUD.
}
-- The following exists to make sure that whatever physics
-- settings the server may have set are transparently ignored.
local defaults = {
speed_walk = 4,
speed_crouch = 1.35,
speed_fast = 20,
speed_climb = 3,
speed_jump = 6.5,
gravity = 9.81,
liquid_fluidity = 1,
liquid_fluidity_smooth = 0.5,
liquid_sink = 10,
acceleration_default = 3,
acceleration_air = 2,
acceleration_fast = 10,
}
local override = {
speed = 1,
sneak = true,
sneak_glitch = false,
new_move = true,
}
for key, def_value in pairs(defaults) do
local setting_name = "movement_"..key
local current = tonumber(minetest.settings:get(setting_name)) or def_value
override[key] = def_value /current
end
p:set_physics_override(override)
-- No unreasonable FOV settings here.
p:set_fov(72)
m.hud = {}
m.poi = {}
m.chat = {}
if not artifact.debug then
p:set_inventory_formspec ""
end
if m.character == "vix" then if m.character == "vix" then
artifact.apply_vix(m) artifact.apply_vix(m)
else else
artifact.apply_key(m) artifact.apply_key(m)
end end
p:hud_set_flags { -- Let us build in debug mode, but ensure we always wield the hand item otherwise.
healthbar = false, m:set_hotbar_size(artifact.debug and 8 or 1)
breathbar = false,
hotbar = artifact.debug,
minimap = false,
basic_debug = false,
chat = false, -- We provide our own implementation of the chat HUD.
}
m.hud = {}
m.poi = {}
m.chat = {}
m:create_hud()
m:set_hotbar_size(8)
m.ctl = p:get_player_control() m.ctl = p:get_player_control()
@ -74,6 +115,11 @@ Player = setmetatable({
m.pos = pos m.pos = pos
m.pos.y = m.pos.y +m.eye_height m.pos.y = m.pos.y +m.eye_height
local state = artifact.story.get_state()
-- Sleep if we are not yet ready for the player to do things.
if not artifact.debug and state <= artifact.story.states.init then return end
-- MARK: Pointing callbacks -- MARK: Pointing callbacks
local pointed_found = nil local pointed_found = nil
@ -221,7 +267,8 @@ Player = setmetatable({
-- MARK: Radial menu handling -- MARK: Radial menu handling
if 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 -- 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
artifact.show_radial_menu(m, { artifact.show_radial_menu(m, {
name = "construct", name = "construct",
"test", "test",
@ -288,26 +335,33 @@ Player = setmetatable({
end end
end end
-- MARK: Health regen
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.ctl = ctl
m.yaw = yaw m.yaw = yaw
m.pitch = pitch m.pitch = pitch
m.dir = dir
end, end,
set_character = function(m, to) set_character = function(m, to)
m.character = to m.character = to
m.meta:set_string("character", to) m.meta:set_string("character", to)
end, end,
-- Initialize the player's primary HUD display based on saved state. add_health_bar = function(m)
create_hud = function(m)
m.healthbar = m.object:hud_add { m.healthbar = m.object:hud_add {
type = "statbar", type = "statbar",
position = {x=0.5,y=1}, position = {x=0.5,y=1},
offset = {x=-27 *5,y=artifact.debug and -96 or -30}, offset = {x=-27 *5,y=artifact.debug and -96 or -40},
scale = {x=4,y=4}, scale = {x=4,y=4},
alignment = {x=-1, y=-1}, alignment = {x=-1, y=-1},
size = {x=27,y=27}, size = {x=27,y=27},
text = "artifact_heart_vix.png", text = m.character == "vix" and "artifact_heart_vix.png" or "artifact_heart.png",
text2 = "artifact_heart_bg.png", text2 = "artifact_heart_bg.png",
number = 20 number = 20,
item = 20,
} }
end, end,
set_hotbar_size = function(m, slots) set_hotbar_size = function(m, slots)
@ -326,6 +380,21 @@ Player = setmetatable({
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)
local m = artifact.players[p:get_player_name()]
local hp = p:get_hp() +delta
if m.healthbar then
p:hud_change(m.healthbar, "number", hp)
end
if hp < 20 then
m.next_regen = minetest.get_us_time() +5000000
else
m.next_regen = nil
end
end)
local _hand = minetest.registered_items[""] local _hand = minetest.registered_items[""]
function artifact.register_input(name) function artifact.register_input(name)
@ -347,10 +416,18 @@ function artifact.register_input(name)
range = 0, range = 0,
on_drop = function(s, p, pos) on_drop = function(s, p, pos)
local m = artifact.players[p:get_player_name()] local m = artifact.players[p:get_player_name()]
if artifact.debug or artifat.story.state > artifact.story.states.pre_vix then if artifact.debug or artifact.story.get_state() > artifact.story.states.pre_vix then
artifact.swap_character(m) artifact.swap_character(m)
end end
return s return s
end,
on_use = function(s, p)
local m = artifact.players[p:get_player_name()]
if m.character == "vix" then
artifact.do_shoot(m)
else
artifact.do_whack(m)
end
end end
}) })
end end

View file

@ -1,19 +1,49 @@
artifact.story = { artifact.story = {
states = enum { -- We use an enum for this so that we can use relational operators to determine if the current state is before or after a target state. states = enum { -- We use an enum for this so that we can use relational operators to determine if the current state is before or after a target state.
"loading", -- For mapgen "loading", -- Mapgen is not yet complete.
"init", -- For the opening cutscene "init", -- For the opening cutscene.
"pre_vix", -- The player doesn't have Vix yet "pre_vix", -- The player doesn't have Vix yet.
"main", -- The main game state. Progress is managed by checkpoints here. "main", -- The main game state. Progress is managed by checkpoints here.
"end", -- The game is over. "end", -- The game is over.
},
poi = {
initial_cutscene = {
start_pos = vector.new(0, 0, 0),
end_pos = vector.new(0,0,0)
}
} }
} }
local ns = artifact.story local ns = artifact.story
local db = minetest.get_mod_storage() local db = minetest.get_mod_storage()
local state = db:get_int("state") -- Defaults to zero, i.e. "loading". local state = db:get_int("state") -- Defaults to zero, i.e. "loading".
artifact.origin = vector.from_string(db:get("origin") or "(0,0,0)")
function ns.set_state(to) if artifact.debug then state = ns.states.main end
function ns.enter_init_state()
ns.play_intro_cutscene()
end
function ns.enter_pre_vix_state()
for _, m in pairs(artifact.players) do
m:add_health_bar()
m.object:hud_set_flags {
crosshair = true,
wielditem = true,
}
end
end
function ns.enter_state(to)
state = to state = to
minetest.log("State changed to "..to..".")
if state == ns.states.init then
ns.enter_init_state()
elseif state == ns.states.pre_vix then
ns.enter_pre_vix_state()
end
db:set_int("state", state) db:set_int("state", state)
end end
@ -21,12 +51,330 @@ function ns.get_state()
return state return state
end end
function ns.before_state(target) -- Used for marking the start position in schematics.
-- Disappears when not in debug mode.
artifact.register_node("start_pos", {
drawtype = not artifact.debug and "airlike" or nil,
paramtype = "light",
walkable = artifact.debug or false,
pointable = artifact.debug or false,
tiles = {artifact.debug and "artifact_start_pos.png" or "blank.png"}
})
function artifact.look_at(m, pos, pos2)
local rot = (pos2 and pos or m.object:get_pos()):direction(pos2 or pos):dir_to_rotation()
m.object:set_look_horizontal(rot.y)
-- Pitch seems to be flipped on the player?
m.object:set_look_vertical(-rot.x)
end end
minetest.register_globalstep(function()
if state == "init" then minetest.register_chatcommand("splash", {
func = function(name)
local m = artifact.players[name]
minetest.show_formspec(m.name, "artifact:lock_camera", [[
formspec_version[10]
size[32,18]
padding[0,0]
bgcolor[#000]
animated_image[0,0;32,18;;artifact_splash.png;60;100;;]
]])
end
})
-- Play the opening cutscene.
function ns.play_intro_cutscene()
ns.camera = minetest.add_entity(artifact.origin:offset(0,-0.75,0), "display")
ns.scene = minetest.add_entity(artifact.origin:offset(-2.25,-0.5,7 -1/16), "display")
ns.scene:set_properties {
visual = "mesh",
mesh = "artifact_cutscene_a.gltf",
textures = {"artifact_key.png", "artifact_statue.png"}
}
ns.scene:set_animation({x=0,y=25}, 1, 0.1, false)
for _, m in pairs(artifact.players) do
m.object:set_attach(ns.camera)
minetest.show_formspec(m.name, "artifact:lock_camera", [[
formspec_version[10]
size[32,18]
padding[0,0]
allow_close[false]
bgcolor[#0000]
]])
m.object:set_look_vertical(0)
m.object:set_look_horizontal(0)
end
-- Begin mess.
minetest.after(17, function()
for x = -1, 1 do
for z = -1, 1 do
minetest.remove_node(artifact.origin:offset(x, -1, z -5))
minetest.add_particlespawner {
pos = {
min = artifact.origin:offset(x -0.5, -1, z -5 -0.5),
max = artifact.origin:offset(x +0.5, -0.5, z -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 = "artifact:stone_tile_brown"},
time = 0.1
}
end
end
end)
minetest.after(3.5, function()
-- Slowly move back as Key walks forward.
ns.camera:set_acceleration(vector.new(0,0,-0.5))
minetest.after(1, function()
-- Decelerate before switching angles, for smoothness.
ns.camera:set_acceleration(vector.new(0,0,0.3))
end)
minetest.after(2, function()
ns.camera:set_acceleration(vector.zero())
ns.camera:set_velocity(vector.zero())
ns.camera:set_pos(artifact.origin:offset(-5, 3, -4))
for _, m in pairs(artifact.players) do
artifact.look_at(m, ns.camera:get_pos(), artifact.origin:offset(0,0,1))
end
local time = minetest.get_us_time()
-- Pan to follow Key as he moves toward the pedestal.
local function interpolate()
local fac = (minetest.get_us_time() -time) /4000000
local offset = artifact.interpolate(1, 4, fac)
for _, m in pairs(artifact.players) do
artifact.look_at(m, ns.camera:get_pos(), artifact.origin:offset(0,0,-offset))
end
-- Do a globalstep callback the lazy way.
if fac < 1 then minetest.after(0, interpolate) end
end
minetest.after(0, interpolate)
minetest.after(4, function()
-- Dramatically move backward as Key stares at the statue.
ns.camera:set_pos(artifact.origin:offset(-0.2, -0.5, -9))
ns.camera:set_velocity(vector.new(0,0,-0.5))
for _, m in pairs(artifact.players) do
m.object:set_look_vertical(0)
m.object:set_look_horizontal(0)
end
minetest.after(6, function()
-- Cut back to where we were before, so we get a good view of Key falling in the hole.
ns.camera:set_pos(artifact.origin:offset(-5, 3, -4))
ns.camera:set_velocity(vector.new(0,0,0))
for _, m in pairs(artifact.players) do
artifact.look_at(m, ns.camera:get_pos(), artifact.origin:offset(0,0,-4))
end
minetest.after(3, function()
-- Show epic splash animation while Key finishes falling down the hole.
for _, m in pairs(artifact.players) do
artifact.hud_add(m, {
type = "image",
name = "background",
pos = {x=0.5,y=0.5},
scale = {x=1000,y=1000},
image = "[fill:16x16:0,0:#000",
opacity = 0
})
m.hud.background:animate {
opacity = {
value = 256,
duration = 0.3
}
}
end
minetest.after(0.3, function()
for _, m in pairs(artifact.players) do
minetest.show_formspec(m.name, "artifact:lock_camera", [[
formspec_version[10]
size[32,18]
padding[0,0]
allow_close[false]
bgcolor[#0000]
animated_image[0,0;32,18;;artifact_splash.png;60;100;;]
]])
end
end)
minetest.after(6.3, function()
for _, m in pairs(artifact.players) do
minetest.show_formspec(m.name, "artifact:lock_camera", [[
formspec_version[10]
size[32,18]
padding[0,0]
allow_close[false]
bgcolor[#0000]
]])
m.hud.background:animate {
opacity = {
value = 0,
duration = 0.3
}
}
m.hud.background.remove_after = 0.3
end
ns.camera:set_pos(artifact.origin:offset(-1, -73, -6))
ns.camera:set_velocity(vector.new(0,0,0))
for _, m in pairs(artifact.players) do
artifact.look_at(m, ns.camera:get_pos(), artifact.origin:offset(1, -74, -3))
end
ns.scene:remove()
ns.scene = minetest.add_entity(artifact.origin:offset(-1, -73.5, -6), "display")
ns.scene:set_properties {
visual = "mesh",
mesh = "artifact_cutscene_b.gltf",
textures = {"artifact_key.png", "artifact_blackrod.png"}
}
minetest.after(0.3, function()
artifact.push_chat_message("Ow.", "Key", "artifact_key_splash_low.png")
minetest.after(1, function()
ns.scene:set_animation({x=0,y=25}, 1, 0.1, false)
end)
minetest.after(9, function()
artifact.push_chat_message("Interesting...", "Key", "artifact_key_splash_low.png")
end)
minetest.after(13, function()
ns.scene:remove()
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")
end)
end)
end)
end)
end)
end)
end)
end)
end)
-- End mess.
end
-- Do mapgen. This isn't technically story-related, but it's here
-- anyway because we only need to do it for state == "loading"
-- and it's the only mapgen we do.
function ns.load_map()
-- Notify the player that we must mapgen first.
for _, m in pairs(artifact.players) do
artifact.hud_add(m, {
type = "image",
name = "loading_map_bg",
pos = {x=0.5,y=0.5},
scale = {x=1000,y=1000}, -- Cover the whole window without having to get the window size.
image = "[fill:16x16:0,0:#000"
})
artifact.hud_add(m, {
type = "text",
name = "loading_map",
text = "Loading map...",
pos = {x=0.5,y=0.5},
size = {x=3,y=0},
color = minetest.colorspec_to_table("#000")
})
m.hud.loading_map:animate {
color = {
value = minetest.colorspec_to_table("#888"),
duration = 0.3,
}
}
end
-- Make sure the loading HUD fades in first.
minetest.after(0.3, function()
-- Emerge the area so we have something to write to.
-- This is one of the relatively few cases where the
-- Promise API is actually more than a little helpful,
-- because we can simply 'yield' until the emerge is
-- completely finished in a semi-clean way.
Promise(function(r)
minetest.emerge_area(vector.new(-1,-1,-1) *100, vector.new(1, 1, 1) *100, function(bpos, action, remaining) if remaining == 0 then r() end end)
end).after(function()
for _, m in pairs(artifact.players) do
m.hud.loading_map:animate {
color = {
value = minetest.colorspec_to_table("#000"),
duration = 0.3,
}
}
end
-- The mapgen code is here, but the actual world schematic should live in artifact_world.
local path = minetest.get_modpath("artifact_world").."/schems/map"
local pos1 = vector.new(-5,-7,-5)
local pos2 = pos1 +artifact.get_schem_size(path)
artifact.load_schematic(pos1, path)
-- Wait a bit to make quite sure that the schematic is in place (and allow the HUD to fade out).
minetest.after(0.3, function()
local nodes = minetest.find_nodes_in_area(pos1, pos2, "start_pos")
-- If we can't find a start marker, fall back to the global origin.
local start = nodes[1] or vector.zero()
artifact.origin = start
db:set_string("origin", start:to_string())
for _, m in pairs(artifact.players) do
m.hud.loading_map:remove(m)
m.hud.loading_map_bg:animate {
opacity = {
value = 0,
duration = 0.3
}
}
m.hud.loading_map_bg.remove_after = 0.3
m.object:set_pos(start)
end
ns.enter_state(artifact.story.states.init)
end)
end)
end)
end
include "objectives.lua"
local started = false
minetest.register_on_joinplayer(function(p)
local m = artifact.players[p:get_player_name()]
-- Only add the HUD etc. if the player is actually in the game.
if state == ns.states.init then
m.object:set_attach(ns.camera)
minetest.show_formspec(m.name, "artifact:lock_camera", [[
formspec_version[10]
allow_close[false]
bgcolor[#0000]
]])
elseif state > ns.states.init then
m:add_health_bar()
m.object:hud_set_flags {
crosshair = true,
wielditem = true
}
end
-- So we only call this when the _first_ player joins.
-- Sure, we're technically a singleplayer game, but,
-- as they say, better to have it and not need it than
-- need it and not have it.
if not started then
started = true
if state == ns.states.loading then
ns.load_map()
elseif state == "init" then
ns.play_intro_cutscene()
end
end end
end) end)
if artifact.debug then
minetest.register_chatcommand("map", {
func = function()
local path = minetest.get_modpath("artifact_world").."/schems/map"
local pos1 = vector.new(-5,-7,-5)
artifact.load_schematic(pos1, path)
end
})
end

View file

@ -1,2 +1,2 @@
name = artifact_story name = artifact_story
depends = artifact_base depends = artifact_player

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
local ns = artifact
ns.objectives = {}
function ns.establish_objective()
end
function ns.complete_objective()
end
function ns.update_objective()
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

View file

@ -7,8 +7,9 @@ function artifact.register_node(name, def)
if not name:find ":" then if not name:find ":" then
name = "artifact:"..name name = "artifact:"..name
end end
-- We might need to add groups below.
if not def.groups then def.groups = {} end
if artifact.debug then if artifact.debug then
if not def.groups then def.groups = {} end
def.groups.dig_immediate = 3 def.groups.dig_immediate = 3
end end
if def._variants then if def._variants then
@ -99,6 +100,49 @@ local function rep(tx, size)
return out return out
end end
-- These nodes are only used for the intro cutscene.
artifact.register_node("stone_brown", {
tiles = {{name = "artifact_stone_brown.png", align_style = "world"}},
_variants = {"stair", "slab"}
})
artifact.register_node("stone_tile_brown", {
tiles = {{name = "artifact_stone_tile_brown.png", align_style = "world"}},
_variants = {"stair", "slab"}
})
artifact.register_node("stone_bricks_brown", {
tiles = {{name = "artifact_stone_bricks_brown.png", align_style = "world"}},
_variants = {"stair", "slab"}
})
artifact.register_node("torch", {
drawtype = "mesh",
paramtype2 = "facedir",
mesh = "artifact_torch.obj",
tiles = {"artifact_torch.png"},
use_texture_alpha = "clip",
light_source = 10,
paramtype = "light",
sunlight_propagates = true
})
artifact.register_node("torch_standing", {
drawtype = "mesh",
paramtype2 = "facedir",
mesh = "artifact_torch_standing.obj",
tiles = {"artifact_torch.png"},
use_texture_alpha = "clip",
light_source = 10,
paramtype = "light",
sunlight_propagates = true
})
-- End ad-hoc nodes.
artifact.register_node("stone", { artifact.register_node("stone", {
tiles = {{name = "artifact_stone.png", align_style = "world"}}, tiles = {{name = "artifact_stone.png", align_style = "world"}},
_variants = {"stair", "slab"} _variants = {"stair", "slab"}
@ -132,6 +176,70 @@ artifact.register_node("stone_tile_small", {
_variants = {"stair", "slab"}, _variants = {"stair", "slab"},
}) })
-- Why does making this texture a tile animation darken it!?
artifact.register_node("water", {
tiles = {{name = "artifact_water_source.png^[opacity:150", animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 6}}},
drawtype = "liquid",
use_texture_alpha = "blend",
paramtype = "light",
walkable = false,
pointable = artifact.debug,
liquid_move_physics = true,
post_effect_color = "#2d5a7c55",
liquidtype = "source",
-- Minetest pro tip: Do not try to use aliases for these.
liquid_alternative_source = "artifact:water",
liquid_alternative_flowing = "artifact:water_flowing",
liquid_viscosity = 1,
liquid_range = 5,
})
artifact.register_node("water_flowing", {
tiles = {{name = "artifact_water_flowing.png^[opacity:150", animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 0.5}}},
special_tiles = {
{name = "artifact_water_flowing.png^[opacity:150", animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 0.5}},
{name = "artifact_water_flowing.png^[opacity:150", animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 0.5}}
},
drawtype = "flowingliquid",
use_texture_alpha = "blend",
paramtype = "light",
paramtype2 = "flowingliquid",
walkable = false,
pointable = artifact.debug,
buildable_to = true,
liquid_move_physics = true,
post_effect_color = "#2d5a7c55",
drop = "",
liquidtype = "flowing",
liquid_alternative_source = "artifact:water",
liquid_alternative_flowing = "artifact:water_flowing",
liquid_viscosity = 1,
liquid_range = 5,
})
-- Minetest doesn't properly handle having a custom nodebox on a liquid source, so we do this the hacky way.
artifact.register_node("water_static", {
tiles = {{name = "artifact_water_source.png^[opacity:150", animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 6}}},
drawtype = "nodebox",
node_box = {
type = "leveled",
fixed = {
-0.5, -0.5, -0.5,
0.5, 6/16, 0.5
}
},
use_texture_alpha = "blend",
paramtype = "light",
paramtype2 = "leveled",
place_param2 = 60,
walkable = false,
pointable = artifact.debug,
liquid_move_physics = true,
post_effect_color = "#2d5a7c55",
})
artifact.register_node("vines", { artifact.register_node("vines", {
drawtype = "nodebox", drawtype = "nodebox",
@ -249,12 +357,12 @@ artifact.register_node("light", {
-- Make darkness the default. -- Make darkness the default.
minetest.override_item("air", { minetest.override_item("air", {
sunlight_propagates = false, sunlight_propagates = false,
light_source = 2 light_source = 2 -- But not _too_ much darkness...
}) })
if artifact.debug then if artifact.debug then
minetest.register_mapgen_script(minetest.get_modpath(minetest.get_current_modname()).."/mapgen.lua") minetest.register_mapgen_script(minetest.get_modpath(minetest.get_current_modname()).."/mapgen_debug.lua")
minetest.register_decoration { minetest.register_decoration {
deco_type = "simple", deco_type = "simple",
@ -262,5 +370,6 @@ if artifact.debug then
place_on = "stone", place_on = "stone",
fill_ratio = 0.02, fill_ratio = 0.02,
} }
else
minetest.register_mapgen_script(minetest.get_modpath(minetest.get_current_modname()).."/mapgen.lua")
end end

View file

@ -1,33 +1,20 @@
local vm_data = {} local vm_data = {}
local c_stone = minetest.get_content_id("artifact:stone") local c_stone = minetest.get_content_id("artifact:stone")
local c_chest = minetest.get_content_id("chest_with_everything:chest")
-- Singlenode, but the single node is stone.
-- (Note that this is just the base mapgen; the world itself will
-- be loaded from a schematic on init.)
minetest.register_on_generated(function(vm, minp, maxp) minetest.register_on_generated(function(vm, minp, maxp)
local min, max = vm:get_emerged_area() local min, max = vm:get_emerged_area()
local va = VoxelArea(min, max) local va = VoxelArea(min, max)
vm:get_data(vm_data) vm:get_data(vm_data)
if maxp.y < 0 then for i in va:iterp(minp, maxp) do
for i in va:iterp(minp, maxp) do vm_data[i] = c_stone
vm_data[i] = c_stone
end
elseif maxp.y < 50 then
for x = min.x, max.x do
for z = min.z, max.z do
for y = min.y, -1 do
vm_data[va:index(x, y, z)] = c_stone
end
if x == 0 and z == 2 then
vm_data[va:index(x, 0, z)] = c_chest
end
end
end
end end
vm:set_data(vm_data) vm:set_data(vm_data)
minetest.generate_decorations(vm)
vm:calc_lighting() vm:calc_lighting()
end) end)

View file

@ -0,0 +1,33 @@
local vm_data = {}
local c_stone = minetest.get_content_id("artifact:stone")
local c_chest = minetest.get_content_id("chest_with_everything:chest")
minetest.register_on_generated(function(vm, minp, maxp)
local min, max = vm:get_emerged_area()
local va = VoxelArea(min, max)
vm:get_data(vm_data)
if maxp.y < 0 then
for i in va:iterp(minp, maxp) do
vm_data[i] = c_stone
end
elseif maxp.y < 50 then
for x = min.x, max.x do
for z = min.z, max.z do
for y = min.y, -1 do
vm_data[va:index(x, y, z)] = c_stone
end
if x == 0 and z == 2 then
vm_data[va:index(x, 0, z)] = c_chest
end
end
end
end
vm:set_data(vm_data)
minetest.generate_decorations(vm)
vm:calc_lighting()
end)

View file

@ -0,0 +1,187 @@
# Made in Blockbench 4.12.5
mtllib artifact_torch.mtl
o cube
v 0.4111417354376907 0.1185501736953839 0.0625
v 0.4111417354376907 0.1185501736953839 -0.0625
v 0.613156753728018 -0.2695170658200881 0.0625
v 0.613156753728018 -0.2695170658200881 -0.0625
v 0.300265381290413 0.06083159704100469 -0.0625
v 0.300265381290413 0.06083159704100469 0.0625
v 0.5022803995807403 -0.32723564247446735 -0.0625
v 0.5022803995807403 -0.32723564247446735 0.0625
vt 0.25 0.6875
vt 0.3125 0.6875
vt 0.3125 0.46875
vt 0.25 0.46875
vt 0.3125 0.6875
vt 0.375 0.6875
vt 0.375 0.46875
vt 0.3125 0.46875
vt 0.375 1
vt 0.4375 1
vt 0.4375 0.78125
vt 0.375 0.78125
vt 0.375 0.78125
vt 0.4375 0.78125
vt 0.4375 0.5625
vt 0.375 0.5625
vt 0.0625 0.5
vt 0 0.5
vt 0 0.5625
vt 0.0625 0.5625
vt 0.5 1
vt 0.4375 1
vt 0.4375 0.9375
vt 0.5 0.9375
vn 0 0 -1
vn 0.8870108331782217 0.4617486132350339 0
vn 0 0 1
vn -0.8870108331782217 -0.4617486132350339 0
vn -0.4617486132350339 0.8870108331782217 0
vn 0.4617486132350339 -0.8870108331782217 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 4/4/1 7/3/1 5/2/1 2/1/1
f 3/8/2 4/7/2 2/6/2 1/5/2
f 8/12/3 3/11/3 1/10/3 6/9/3
f 7/16/4 8/15/4 6/14/4 5/13/4
f 6/20/5 1/19/5 2/18/5 5/17/5
f 7/24/6 4/23/6 3/22/6 8/21/6
o cube
v 0.43772062418414 0.2028476390962124 0.125
v 0.43772062418414 0.2028476390962124 -0.125
v 0.46657991251132963 0.14740946202257355 0.125
v 0.46657991251132963 0.14740946202257355 -0.125
v 0.21596791588958458 0.08741048578745392 -0.125
v 0.21596791588958458 0.08741048578745392 0.125
v 0.24482720421677417 0.03197230871381507 -0.125
v 0.24482720421677417 0.03197230871381507 0.125
vt 0.0625 0.5625
vt 0.1875 0.5625
vt 0.1875 0.53125
vt 0.0625 0.53125
vt 0.4375 0.9375
vt 0.5625 0.9375
vt 0.5625 0.90625
vt 0.4375 0.90625
vt 0.4375 0.90625
vt 0.5625 0.90625
vt 0.5625 0.875
vt 0.4375 0.875
vt 0.4375 0.875
vt 0.5625 0.875
vt 0.5625 0.84375
vt 0.4375 0.84375
vt 0.125 0.5625
vt 0 0.5625
vt 0 0.6875
vt 0.125 0.6875
vt 0.25 0.6875
vt 0.125 0.6875
vt 0.125 0.5625
vt 0.25 0.5625
vn 0 0 -1
vn 0.8870108331782217 0.4617486132350339 0
vn 0 0 1
vn -0.8870108331782217 -0.4617486132350339 0
vn -0.4617486132350339 0.8870108331782217 0
vn 0.4617486132350339 -0.8870108331782217 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 12/28/7 15/27/7 13/26/7 10/25/7
f 11/32/8 12/31/8 10/30/8 9/29/8
f 16/36/9 11/35/9 9/34/9 14/33/9
f 15/40/10 16/39/10 14/38/10 13/37/10
f 14/44/11 9/43/11 10/42/11 13/41/11
f 15/48/12 12/47/12 11/46/12 16/45/12
o cube
v 0.3001499612370861 0.4835397432391481 0.1325825214724777
v 0.3001499612370861 0.4835397432391481 0.1325825214724777
v 0.44444640287303405 0.20634885787095372 0.13258252147247768
v 0.44444640287303405 0.20634885787095372 0.13258252147247768
v 0.06494569556474239 0.3611001523809069 -0.13258252147247748
v 0.06494569556474239 0.3611001523809069 -0.13258252147247748
v 0.20924213720069035 0.08390926701271256 -0.1325825214724775
v 0.20924213720069035 0.08390926701271256 -0.1325825214724775
vt 0 1
vt 0.1875 1
vt 0.1875 0.84375
vt 0 0.84375
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0 0.84375
vt 0.1875 0.84375
vt 0.1875 0.6875
vt 0 0.6875
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vn 0.6272113751262501 0.32650557562197663 -0.7071067811865476
vn 0.6272113751262504 0.32650557562197663 0.7071067811865475
vn -0.6272113751262501 -0.32650557562197663 0.7071067811865476
vn -0.6272113751262504 -0.32650557562197663 -0.7071067811865475
vn -0.4617486132350336 0.887010833178222 0
vn 0.4617486132350336 -0.887010833178222 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 20/52/13 23/51/13 21/50/13 18/49/13
f 19/56/14 20/55/14 18/54/14 17/53/14
f 24/60/15 19/59/15 17/58/15 22/57/15
f 23/64/16 24/63/16 22/62/16 21/61/16
f 22/68/17 17/67/17 18/66/17 21/65/17
f 23/72/18 20/71/18 19/70/18 24/69/18
o cube
v 0.06494569556474178 0.36110015238090654 0.13258252147247745
v 0.06494569556474178 0.36110015238090654 0.13258252147247745
v 0.20924213720069024 0.08390926701271237 0.13258252147247768
v 0.20924213720069024 0.08390926701271237 0.13258252147247768
v 0.3001499612370855 0.4835397432391479 -0.13258252147247773
v 0.3001499612370855 0.4835397432391479 -0.13258252147247773
v 0.44444640287303394 0.20634885787095378 -0.1325825214724775
v 0.44444640287303394 0.20634885787095378 -0.1325825214724775
vt 0.1875 1
vt 0.375 1
vt 0.375 0.84375
vt 0.1875 0.84375
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 0.84375
vt 0.375 0.84375
vt 0.375 0.6875
vt 0.1875 0.6875
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vn 0.6272113751262494 0.3265055756219781 0.7071067811865478
vn -0.6272113751262501 -0.32650557562197735 0.7071067811865475
vn -0.6272113751262494 -0.3265055756219781 -0.7071067811865478
vn 0.6272113751262501 0.32650557562197735 -0.7071067811865475
vn -0.4617486132350349 0.8870108331782214 -8.049116928532382e-16
vn 0.4617486132350349 -0.8870108331782214 8.049116928532382e-16
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 28/76/19 31/75/19 29/74/19 26/73/19
f 27/80/20 28/79/20 26/78/20 25/77/20
f 32/84/21 27/83/21 25/82/21 30/81/21
f 31/88/22 32/87/22 30/86/22 29/85/22
f 30/92/23 25/91/23 26/90/23 29/89/23
f 31/96/24 28/95/24 27/94/24 32/93/24

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View file

@ -0,0 +1,4 @@
# Made in Blockbench 4.12.5
newmtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
map_Kd artifact_torch.png
newmtl none

View file

@ -0,0 +1,187 @@
# Made in Blockbench 4.12.5
mtllib artifact_torch_standing.mtl
o cube
v 0.13013507308001968 0.3059361621615665 0.1325825214724777
v 0.13013507308001968 0.3059361621615665 0.1325825214724777
v 0.13013507308001954 -0.006563837838433541 0.13258252147247768
v 0.13013507308001954 -0.006563837838433541 0.13258252147247768
v -0.13502996986493548 0.3059361621615666 -0.13258252147247745
v -0.13502996986493548 0.3059361621615666 -0.13258252147247745
v -0.13502996986493562 -0.006563837838433416 -0.13258252147247748
v -0.13502996986493562 -0.006563837838433416 -0.13258252147247748
vt 0 1
vt 0.1875 1
vt 0.1875 0.84375
vt 0 0.84375
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0 0.84375
vt 0.1875 0.84375
vt 0.1875 0.6875
vt 0 0.6875
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vn 0.7071067811865476 -2.355138688025663e-16 -0.7071067811865476
vn 0.7071067811865476 -3.9252311467094373e-16 0.7071067811865475
vn -0.7071067811865476 2.355138688025663e-16 0.7071067811865476
vn -0.7071067811865476 3.9252311467094373e-16 -0.7071067811865475
vn 4.710277376051325e-16 1 0
vn -4.710277376051325e-16 -1 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 4/4/1 7/3/1 5/2/1 2/1/1
f 3/8/2 4/7/2 2/6/2 1/5/2
f 8/12/3 3/11/3 1/10/3 6/9/3
f 7/16/4 8/15/4 6/14/4 5/13/4
f 6/20/5 1/19/5 2/18/5 5/17/5
f 7/24/6 4/23/6 3/22/6 8/21/6
o cube
v 0.06005255160754197 -0.0690638378384335 0.0625
v 0.06005255160754197 -0.0690638378384335 -0.0625
v 0.06005255160754197 -0.5065638378384335 0.0625
v 0.06005255160754197 -0.5065638378384335 -0.0625
v -0.06494744839245803 -0.0690638378384335 -0.0625
v -0.06494744839245803 -0.0690638378384335 0.0625
v -0.06494744839245803 -0.5065638378384335 -0.0625
v -0.06494744839245803 -0.5065638378384335 0.0625
vt 0.25 0.6875
vt 0.3125 0.6875
vt 0.3125 0.46875
vt 0.25 0.46875
vt 0.3125 0.6875
vt 0.375 0.6875
vt 0.375 0.46875
vt 0.3125 0.46875
vt 0.375 1
vt 0.4375 1
vt 0.4375 0.78125
vt 0.375 0.78125
vt 0.375 0.78125
vt 0.4375 0.78125
vt 0.4375 0.5625
vt 0.375 0.5625
vt 0.0625 0.5
vt 0 0.5
vt 0 0.5625
vt 0.0625 0.5625
vt 0.5 1
vt 0.4375 1
vt 0.4375 0.9375
vt 0.5 0.9375
vn 0 0 -1
vn 1 0 0
vn 0 0 1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 12/28/7 15/27/7 13/26/7 10/25/7
f 11/32/8 12/31/8 10/30/8 9/29/8
f 16/36/9 11/35/9 9/34/9 14/33/9
f 15/40/10 16/39/10 14/38/10 13/37/10
f 14/44/11 9/43/11 10/42/11 13/41/11
f 15/48/12 12/47/12 11/46/12 16/45/12
o cube
v 0.12255255160754197 -0.006563837838433506 0.125
v 0.12255255160754197 -0.006563837838433506 -0.125
v 0.12255255160754197 -0.0690638378384335 0.125
v 0.12255255160754197 -0.0690638378384335 -0.125
v -0.12744744839245803 -0.006563837838433506 -0.125
v -0.12744744839245803 -0.006563837838433506 0.125
v -0.12744744839245803 -0.0690638378384335 -0.125
v -0.12744744839245803 -0.0690638378384335 0.125
vt 0.0625 0.5625
vt 0.1875 0.5625
vt 0.1875 0.53125
vt 0.0625 0.53125
vt 0.4375 0.9375
vt 0.5625 0.9375
vt 0.5625 0.90625
vt 0.4375 0.90625
vt 0.4375 0.90625
vt 0.5625 0.90625
vt 0.5625 0.875
vt 0.4375 0.875
vt 0.4375 0.875
vt 0.5625 0.875
vt 0.5625 0.84375
vt 0.4375 0.84375
vt 0.125 0.5625
vt 0 0.5625
vt 0 0.6875
vt 0.125 0.6875
vt 0.25 0.6875
vt 0.125 0.6875
vt 0.125 0.5625
vt 0.25 0.5625
vn 0 0 -1
vn 1 0 0
vn 0 0 1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 20/52/13 23/51/13 21/50/13 18/49/13
f 19/56/14 20/55/14 18/54/14 17/53/14
f 24/60/15 19/59/15 17/58/15 22/57/15
f 23/64/16 24/63/16 22/62/16 21/61/16
f 22/68/17 17/67/17 18/66/17 21/65/17
f 23/72/18 20/71/18 19/70/18 24/69/18
o cube
v -0.1350299698649363 0.3059361621615665 0.13258252147247745
v -0.1350299698649363 0.3059361621615665 0.13258252147247745
v -0.1350299698649359 -0.00656383783843351 0.13258252147247768
v -0.1350299698649359 -0.00656383783843351 0.13258252147247768
v 0.13013507308001904 0.3059361621615666 -0.1325825214724777
v 0.13013507308001904 0.3059361621615666 -0.1325825214724777
v 0.13013507308001943 -0.006563837838433447 -0.13258252147247748
v 0.13013507308001943 -0.006563837838433447 -0.13258252147247748
vt 0.1875 1
vt 0.375 1
vt 0.375 0.84375
vt 0.1875 0.84375
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 0.84375
vt 0.375 0.84375
vt 0.375 0.6875
vt 0.1875 0.6875
vt 0 1
vt 0 1
vt 0 0.84375
vt 0 0.84375
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vt 0.1875 1
vt 0 1
vt 0 1
vt 0.1875 1
vn 0.7071067811865475 1.3738309013483032e-15 0.7071067811865478
vn -0.7071067811865478 -3.532708032038497e-16 0.7071067811865475
vn -0.7071067811865475 -1.3738309013483032e-15 -0.7071067811865478
vn 0.7071067811865478 3.532708032038497e-16 -0.7071067811865475
vn -1.099064721078642e-15 1 -8.635508522760762e-16
vn 1.099064721078642e-15 -1 8.635508522760762e-16
usemtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2
f 28/76/19 31/75/19 29/74/19 26/73/19
f 27/80/20 28/79/20 26/78/20 25/77/20
f 32/84/21 27/83/21 25/82/21 30/81/21
f 31/88/22 32/87/22 30/86/22 29/85/22
f 30/92/23 25/91/23 26/90/23 29/89/23
f 31/96/24 28/95/24 27/94/24 32/93/24

View file

@ -0,0 +1 @@
{"(45, 21, 52)":{"fields":null,"inventory":null}}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB