From b5bc0a34ea84f941085a0441dda7ea82c2b0e275 Mon Sep 17 00:00:00 2001 From: Signal Date: Thu, 20 Nov 2025 03:15:30 -0500 Subject: [PATCH] Add forcefields, and start building the map. --- mods/artifact_characters/key.lua | 5 +- mods/artifact_chat/init.lua | 11 + mods/artifact_mechanisms/doors.lua | 16 + mods/artifact_mechanisms/fields.lua | 0 mods/artifact_mechanisms/forcefields.lua | 346 ++++++++++++++++++ mods/artifact_mechanisms/init.lua | 4 +- mods/artifact_player/init.lua | 32 +- mods/artifact_story/init.lua | 62 +++- mods/artifact_world/init.lua | 42 ++- .../models/artifact_torch_standing.mtl | 4 - mods/artifact_world/schems/map.json | 2 +- mods/artifact_world/schems/map.mts | Bin 7933 -> 11464 bytes 12 files changed, 509 insertions(+), 15 deletions(-) delete mode 100644 mods/artifact_mechanisms/fields.lua create mode 100644 mods/artifact_mechanisms/forcefields.lua delete mode 100644 mods/artifact_world/models/artifact_torch_standing.mtl diff --git a/mods/artifact_characters/key.lua b/mods/artifact_characters/key.lua index 046c8c1..1f7c471 100644 --- a/mods/artifact_characters/key.lua +++ b/mods/artifact_characters/key.lua @@ -23,11 +23,14 @@ function ns.do_whack(m) node = {name = node.name}, time = 0.1 } + if artifact.on_whacked then + artifact.on_whacked("node", m.pointed_node) + end 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() + artifact.on_whacked("object", m.pointed_obj) end end end diff --git a/mods/artifact_chat/init.lua b/mods/artifact_chat/init.lua index 99ae760..743e73c 100644 --- a/mods/artifact_chat/init.lua +++ b/mods/artifact_chat/init.lua @@ -3,6 +3,12 @@ local ns = artifact local hud_pop_times = {} function ns.push_chat_message(msg, sender, splash, duration) + -- Special handling for the character names (and if sent by a player, colorize based on character). + if sender == "Key" or artifact.players[sender] and artifact.players[sender].character == "key" then + sender = minetest.colorize("#284", sender) + elseif sender == "Vix" or artifact.players[sender] and artifact.players[sender].character == "vix" then + sender = minetest.colorize("#f5dd66", sender) + end for name, m in pairs(artifact.players) do local box = {} local w = minetest.get_player_window_information(name).size.x @@ -146,4 +152,9 @@ if artifact.debug then end }) + minetest.register_chatcommand("color", { + func = function(name, args) + ns.push_chat_message(minetest.colorize(args, "This is a colored message"), "Server") + end + }) end diff --git a/mods/artifact_mechanisms/doors.lua b/mods/artifact_mechanisms/doors.lua index a2394eb..3d4669a 100644 --- a/mods/artifact_mechanisms/doors.lua +++ b/mods/artifact_mechanisms/doors.lua @@ -165,6 +165,22 @@ minetest.register_entity(":artifact:door", { collisionbox = box } end, + on_hover = function(e, m) + if e.type == "wood" and e._locked then + m._whack_hud = m.object:hud_add { + type = "image_waypoint", + world_pos = e.object:get_pos():offset(0, 0.5, 0), + scale = {x=3,y=3}, + text = "artifact_icon_whack.png" + } + end + end, + on_unhover = function(e, m) + if m._whack_hud then + m.object:hud_remove(m._whack_hud) + m._whack_hud = nil + end + end, on_whack = function(e) if e.type == "wood" then local pos = e.object:get_pos():round() diff --git a/mods/artifact_mechanisms/fields.lua b/mods/artifact_mechanisms/fields.lua deleted file mode 100644 index e69de29..0000000 diff --git a/mods/artifact_mechanisms/forcefields.lua b/mods/artifact_mechanisms/forcefields.lua new file mode 100644 index 0000000..439563d --- /dev/null +++ b/mods/artifact_mechanisms/forcefields.lua @@ -0,0 +1,346 @@ + + +artifact.register_node("forcefield", { + drawtype = "glasslike_framed", + use_texture_alpha = "blend", + light_source = 6, + tiles = {"artifact_forcefield_border.png", "artifact_forcefield_inner.png"}, + visual_scale = 0.75, + diggable = false +}) + +local vm_data = {} +local vm_p2_data = {} +local c_air = minetest.get_content_id("air") +local c_forcefield = minetest.get_content_id("forcefield") +function artifact.place_forcefield(pos, def) + if def.type == "cube" then + if def.offset then pos = pos:add(def.offset) end + local vm = minetest.get_voxel_manip(pos:offset(-def.radius,-def.radius,-def.radius), pos:offset(def.radius,def.radius,def.radius)) + local va = VoxelArea(vm:get_emerged_area()) + vm:get_data(vm_data) + vm:get_param2_data(vm_p2_data) + for x = pos.x -def.radius, pos.x +def.radius, def.radius *2 do + for y = pos.y -def.radius, pos.y +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + end + for y = pos.y -def.radius, pos.y +def.radius, def.radius *2 do + for x = pos.x -def.radius, pos.x +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + end + for z = pos.z -def.radius, pos.z +def.radius, def.radius *2 do + for y = pos.y -def.radius, pos.y +def.radius do + for x = pos.x -def.radius, pos.x +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + end + vm:set_data(vm_data) + vm:set_param2_data(vm_p2_data) + vm:write_to_map() + elseif def.type == "plane" then + local vm = minetest.get_voxel_manip(pos:offset(-def.radius,-def.radius,-def.radius), pos:offset(def.radius,def.radius,def.radius)) + local va = VoxelArea(vm:get_emerged_area()) + vm:get_data(vm_data) + vm:get_param2_data(vm_p2_data) + + local x + local y + local z + if def.axis == "x" then + local x = pos.x + for y = pos.y -def.radius, pos.y +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield and vm_p2_data[idx] > 0 then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + elseif def.axis == "y" then + local y = pos.y + for x = pos.x -def.radius, pos.x +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield and vm_p2_data[idx] > 0 then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + elseif def.axis == "z" then + local z = pos.z + for y = pos.y -def.radius, pos.y +def.radius do + for x = pos.x -def.radius, pos.x +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_air then + vm_data[idx] = c_forcefield + vm_p2_data[idx] = 1 + elseif vm_data[idx] == c_forcefield and vm_p2_data[idx] > 0 then + vm_p2_data[idx] = vm_p2_data[idx] +1 + end + end + end + end + + vm:set_data(vm_data) + vm:set_param2_data(vm_p2_data) + vm:write_to_map() + end +end + +function artifact.remove_forcefield(pos, def) + if def.type == "cube" then + if def.offset then pos = pos:add(def.offset) end + local vm = minetest.get_voxel_manip(pos:offset(-def.radius,-def.radius,-def.radius), pos:offset(def.radius,def.radius,def.radius)) + local va = VoxelArea(vm:get_emerged_area()) + vm:get_data(vm_data) + vm:get_param2_data(vm_p2_data) + for x = pos.x -def.radius, pos.x +def.radius, def.radius *2 do + for y = pos.y -def.radius, pos.y +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + end + for y = pos.y -def.radius, pos.y +def.radius, def.radius *2 do + for x = pos.x -def.radius, pos.x +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + end + for z = pos.z -def.radius, pos.z +def.radius, def.radius *2 do + for y = pos.y -def.radius, pos.y +def.radius do + for x = pos.x -def.radius, pos.x +def.radius do + local idx = va:index(x, y, z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + end + vm:set_data(vm_data) + vm:set_param2_data(vm_p2_data) + vm:write_to_map() + elseif def.type == "plane" then + local vm = minetest.get_voxel_manip(pos:offset(-def.radius,-def.radius,-def.radius), pos:offset(def.radius,def.radius,def.radius)) + local va = VoxelArea(vm:get_emerged_area()) + vm:get_data(vm_data) + vm:get_param2_data(vm_p2_data) + + local x + local y + local z + if def.axis == "x" then + local x = pos.x + for y = pos.y -def.radius, pos.y +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + elseif def.axis == "y" then + local y = pos.y + for x = pos.x -def.radius, pos.x +def.radius do + for z = pos.z -def.radius, pos.z +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + elseif def.axis == "z" then + local z = pos.z + for y = pos.y -def.radius, pos.y +def.radius do + for x = pos.x -def.radius, pos.x +def.radius do + local idx = va:index(x +def.offset.x, y +def.offset.y, z +def.offset.z) + if vm_data[idx] == c_forcefield then + if vm_p2_data[idx] <= 1 then + vm_data[idx] = c_air + vm_p2_data[idx] = 0 + else + vm_p2_data[idx] = vm_p2_data[idx] -1 + end + end + end + end + end + + vm:set_data(vm_data) + vm:set_param2_data(vm_p2_data) + vm:write_to_map() + end +end + + +local function onload(pos) + local m = minetest.get_meta(pos) + if not m:contains("initialized") then + local conf = minetest.deserialize(m:get("config") or "return nil") or {type = "plane", radius = 5, axis = "x", offset = vector.new(3,0,0)} + m:set_string("_config", minetest.serialize(conf)) + m:set_string("config", minetest.serialize(conf)) + artifact.place_forcefield(pos, conf) + end +end + +artifact.register_node("forcefield_generator", { + drawtype = "mesh", + mesh = "artifact_forcefield_generator.gltf", + tiles = {"artifact_forcefield_generator.png"}, + paramtype = "light", + light_source = 10, + paramtype2 = "facedir", + groups = {whackable = 1}, + collision_box = { + type = "fixed", + fixed = { + -1, -0.5, -0.5, + 1, 0.5, 0.5 + } + }, + selection_box = { + type = "fixed", + fixed = { + -1, -0.5, -0.5, + 1, 0.5, 0.5 + } + }, + on_construct = onload, + on_load = onload, + on_rightclick = artifact.debug and function(pos) + local m = minetest.get_meta(pos) + artifact.remove_forcefield(pos, minetest.deserialize(m:get("_config") or "return nil") or {type = "plane", radius = 5, axis = "x", offset = vector.new(3,0,0)}) + local conf = minetest.deserialize(m:get("config") or "return nil") or {type = "plane", radius = 5, axis = "x", offset = 3} + m:set_string("_config", minetest.serialize(conf)) + artifact.place_forcefield(pos, conf) + end or nil, + on_destruct = function(pos) + local m = minetest.get_meta(pos) + local conf = minetest.deserialize(m:get("config") or "return nil") or {type = "cube", radius = 5} + artifact.remove_forcefield(pos, conf) + local node = minetest.get_node(pos) + node.name = "forcefield_generator_off" + minetest.after(0, function() + minetest.set_node(pos, node) + end) + minetest.add_particlespawner { + pos = pos, + vel = vector.zero(), + acc = vector.new(0, -9.81, 0), + drag = vector.new(3, 0, 3), + radius = 0.1, + attract = { + kind = "point", + origin = pos, + strength = -50 + }, + texture = { + name = "artifact_light_gold.png", + alpha_tween = {1, 0} + }, + size_tween = { + { + min = 3, + max = 6 + }, + { + min = 1, + max = 2 + } + }, + time = 0.3, + amount = 100, + } + end +}) + +artifact.register_node("forcefield_generator_off", { + drawtype = "mesh", + mesh = "artifact_forcefield_generator.gltf", + tiles = {"artifact_forcefield_generator_off.png"}, + paramtype = "light", + light_source = 6, + paramtype2 = "facedir", + collision_box = { + type = "fixed", + fixed = { + -1, -0.5, -0.5, + 1, 0.5, 0.5 + } + }, + selection_box = { + type = "fixed", + fixed = { + -1, -0.5, -0.5, + 1, 0.5, 0.5 + } + }, + on_impact = artifact.debug and function(pos) + local node = minetest.get_node(pos) + node.name = "forcefield_generator" + minetest.set_node(pos, node) + end or nil, +}) diff --git a/mods/artifact_mechanisms/init.lua b/mods/artifact_mechanisms/init.lua index c5fc8f7..265620a 100644 --- a/mods/artifact_mechanisms/init.lua +++ b/mods/artifact_mechanisms/init.lua @@ -35,10 +35,12 @@ include "doors.lua" include "colors.lua" include "large_doors.lua" include "chest.lua" +include "forcefields.lua" function artifact.load_schematic(dst, path, rot) - minetest.place_schematic(dst, path..".mts", rot or "0") + -- There's not a very good way to export without the forcefields' param2, but we can _import_ without them. + minetest.place_schematic(dst, path..".mts", rot or "0", {["artifact:forcefield"] = "air"}) local f = io.open(path..".json") local meta = minetest.parse_json(f:read("a")) f:close() diff --git a/mods/artifact_player/init.lua b/mods/artifact_player/init.lua index fd3ee3b..ae1c93e 100644 --- a/mods/artifact_player/init.lua +++ b/mods/artifact_player/init.lua @@ -129,7 +129,7 @@ Player = setmetatable({ -- MARK: Pointing callbacks local pointed_found = nil - m.pointed_node = nil + local pointed_node_found = nil for x in minetest.raycast(m.pos, m.pos +(dir *5)) do -- We should ignore all objects when placing a grabbed node. if x and x.type == "object" and not m._grabbed_item then @@ -171,6 +171,24 @@ Player = setmetatable({ end end elseif x and x.type == "node" then + pointed_node_found = true + x.node_under = minetest.get_node(x.under) + + local was_whackable = m.pointed_node and minetest.registered_nodes[m.pointed_node.node_under.name].groups.whackable + local whackable = m.character == "key" and minetest.registered_nodes[x.node_under.name].groups.whackable + if whackable and not was_whackable then + m.whack_hud = m.object:hud_add { + type = "image_waypoint", + world_pos = x.under, + scale = {x=3,y=3}, + text = "artifact_icon_whack.png" + } + elseif whackable and x.under ~= (m.pointed_node and m.pointed_node.under) then + m.object:hud_change(m.whack_hud, "world_pos", x.under) + elseif not whackable and m.whack_hud then + m.object:hud_remove(m.whack_hud) + m.whack_hud = nil + end m.pointed_node = x if m.pointed_obj then if m.pointed_obj.on_unhover then @@ -197,6 +215,14 @@ Player = setmetatable({ end m.pointed_obj = nil end + if not pointed_node_found then + m.pointed_node = nil + if m.whack_hud then + m.object:hud_remove(m.whack_hud) + m.whack_hud = nil + end + end + local ctl = m.object:get_player_control() -- MARK: Animations @@ -314,6 +340,8 @@ Player = setmetatable({ -- MARK: Radial menu handling + --[[ Disabled for the present due to a dearth of usecases... + -- 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 not m.pointed_obj.on_interact or m.pointed_obj._no_interact) then artifact.show_radial_menu(m, { @@ -389,6 +417,8 @@ Player = setmetatable({ end end + --]] + -- MARK: Health regen if m.next_regen and time -m.next_regen >= 0 then diff --git a/mods/artifact_story/init.lua b/mods/artifact_story/init.lua index 87bd44f..8806708 100644 --- a/mods/artifact_story/init.lua +++ b/mods/artifact_story/init.lua @@ -25,6 +25,35 @@ function ns.enter_init_state() ns.play_intro_cutscene() end +local vix_scene +minetest.register_entity(":artifact:vix_scene", { + initial_properties = { + visual = "mesh", + mesh = "artifact_scene_vix.gltf", + textures = {"artifact_vix.png"} + }, + on_activate = function(e) + if state > ns.states.pre_vix then + e.object:remove() + end + e.object:set_armor_groups{immortal = 1} + e.object:set_animation({x=0,y=2}, 0.5, 0.1, true) + vix_scene = e + end, + on_deactivate = function(e) + vix_scene = nil + end, + on_step = function(e) + if e._can_check then + for _, m in pairs(artifact.players) do + if m.pos:distance(e.object:get_pos()) < 15 and m.dir:distance(m.pos:direction(e.object:get_pos())) < 0.2 then + artifact.push_chat_message("Hmm...", "Key", "artifact_key_splash_low.png") + e._can_check = false + end + end + end + end +}) function ns.enter_pre_vix_state() for _, m in pairs(artifact.players) do @@ -36,20 +65,49 @@ function ns.enter_pre_vix_state() 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() + minetest.add_entity(artifact.origin:offset(-16.5, -72.5, -17), "artifact:vix_scene") + local help = minetest.after(15, 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) + db:set_string("checkpoint:pre_vix", "begin") + artifact.on_whacked = function(type, target) + local checkpoint = db:get("checkpoint:pre_vix") + if checkpoint == "begin" then -- We're still in the start closet. + if type == "object" then + help:cancel() + vix_scene._can_check = true + end + db:set_string("checkpoint:pre_vix", "in_room") + elseif checkpoint == "in_room" then -- We're actually in the room. + if target.node_under.name:find "forcefield_generator" then + local num = db:get_int("checkpoint:pre_vix_fields_broken") +1 + db:set_int("checkpoint:pre_vix_fields_broken", num) + if num == 1 then -- Key breaks his first generator. + minetest.after(1, function() + artifact.push_chat_message("Hehe.", "Key", "artifact_key_splash_low.png") + end) + elseif num == 5 then -- All generators are down. + vix_scene._can_check = nil + end + end + end + end +end + +function ns.enter_main_state() + vix_scene.object:remove() end function ns.enter_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() + elseif state == ns.states.main then + ns.enter_main_state() end db:set_int("state", state) end diff --git a/mods/artifact_world/init.lua b/mods/artifact_world/init.lua index 9cff307..12fb90c 100644 --- a/mods/artifact_world/init.lua +++ b/mods/artifact_world/init.lua @@ -257,7 +257,7 @@ artifact.register_node("vines", { type = "fixed", fixed = { -0.5, -0.5, 0.5, - 0.5, 0.5, 0.45 + 0.5, 0.5, 0.35 } }, paramtype = "light", @@ -279,7 +279,7 @@ artifact.register_node("vines_dry", { type = "fixed", fixed = { -0.5, -0.5, 0.5, - 0.5, 0.5, 0.45 + 0.5, 0.5, 0.35 } }, paramtype = "light", @@ -354,7 +354,16 @@ local function register_lamp(color, brightness) 2/16, 4/16, 2/16 } } - } + }, + selection_box = { + type = "fixed", + fixed = { + { + -2/16,0,-2/16, + 2/16, 4/16, 2/16 + } + } + }, }) artifact.register_node("lamp_"..color.."_wall", { drawtype = "mesh", @@ -376,6 +385,19 @@ local function register_lamp(color, brightness) 1/16, 6/16, 8/16 }, } + }, + selection_box = { + type = "fixed", + fixed = { + { + -2/16,-1/16,-1/16, + 2/16, 3/16, 3/16 + }, + { + -1/16,4/16,-1/16, + 1/16, 6/16, 8/16 + }, + } } }) artifact.register_node("lamp_"..color.."_hanging", { @@ -393,13 +415,23 @@ local function register_lamp(color, brightness) 2/16, 4/16, 2/16 } } + }, + selection_box = { + type = "fixed", + fixed = { + { + -2/16,0,-2/16, + 2/16, 4/16, 2/16 + } + } } }) end register_lamp("red", 6) -register_lamp("gold", 8) +register_lamp("green", 8) register_lamp("blue", 10) +register_lamp("gold", 12) artifact.register_node("light", { @@ -420,7 +452,7 @@ if artifact.debug then minetest.register_decoration { deco_type = "simple", - decoration = "lamp_blue", + decoration = "lamp_gold", place_on = "stone", fill_ratio = 0.02, } diff --git a/mods/artifact_world/models/artifact_torch_standing.mtl b/mods/artifact_world/models/artifact_torch_standing.mtl deleted file mode 100644 index 189f033..0000000 --- a/mods/artifact_world/models/artifact_torch_standing.mtl +++ /dev/null @@ -1,4 +0,0 @@ -# Made in Blockbench 4.12.5 -newmtl m_e3e69eb0-b6c9-b9c2-690f-4d510df185b2 -map_Kd artifact_torch.png -newmtl none \ No newline at end of file diff --git a/mods/artifact_world/schems/map.json b/mods/artifact_world/schems/map.json index 999816f..4818480 100644 --- a/mods/artifact_world/schems/map.json +++ b/mods/artifact_world/schems/map.json @@ -1 +1 @@ -{"(45, 21, 52)":{"fields":null,"inventory":null}} \ No newline at end of file +{"(24, 24, 41)":{"fields":{"_config":"return {type=\"cube\",offset={z=1,x=4,y=0},radius=3,axis=\"x\"}","config":"return {radius=3,axis=\"x\",offset={z=1,x=4,y=0},type=\"cube\"}"},"inventory":null},"(24, 24, 43)":{"fields":{"_config":"return {type=\"cube\",offset={z=-1,x=4,y=0},radius=3,axis=\"x\"}","config":"return {radius=3,axis=\"x\",offset={z=-1,x=4,y=0},type=\"cube\"}"},"inventory":null},"(39, 33, 33)":{"fields":null,"inventory":null},"(39, 34, 52)":{"fields":{"inverted":"true"},"inventory":null},"(41, 33, 34)":{"fields":{"_config":"return {type=\"plane\",offset={z=12,x=-6,y=0},radius=15,axis=\"x\"}","config":"return {radius=15,axis=\"x\",offset={z=12,x=-6,y=0},type=\"plane\"}"},"inventory":null},"(43, 33, 33)":{"fields":{"inverted":"true"},"inventory":null},"(43, 34, 52)":{"fields":null,"inventory":null},"(44, 24, 33)":{"fields":{"open":"false"},"inventory":null},"(44, 24, 38)":{"fields":{"_config":"return {type=\"plane\",radius=15,offset={z=0,x=-8,y=0},axis=\"x\"}","config":"return {offset={z=0,x=-8,y=0},axis=\"x\",radius=15,type=\"plane\"}"},"inventory":null},"(44, 24, 47)":{"fields":{"_config":"return {type=\"plane\",radius=15,offset={z=0,x=-7,y=0},axis=\"x\"}","config":"return {offset={z=0,x=-7,y=0},axis=\"x\",radius=15,type=\"plane\"}"},"inventory":null},"(44, 24, 52)":{"fields":{"locked":"true","open":"false"},"inventory":null},"(62, 24, 42)":{"fields":null,"inventory":null},"(62, 24, 43)":{"fields":{"inverted":"true"},"inventory":null},"(62, 34, 42)":{"fields":null,"inventory":null},"(62, 34, 43)":{"fields":{"inverted":"true"},"inventory":null}} \ No newline at end of file diff --git a/mods/artifact_world/schems/map.mts b/mods/artifact_world/schems/map.mts index 02014227089ef8b28cea113b9f6995725a5a34bf..7f25169ef51db59bc5efeaa54172855504c86dd3 100644 GIT binary patch literal 11464 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