techage/basic_machines/forceload.lua
2019-09-15 23:30:04 +02:00

215 lines
6.2 KiB
Lua

--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
GPL v3
See LICENSE.txt for more information
Forceload block
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S = techage.S
local function calc_area(pos)
local xpos = (math.floor(pos.x / 16) * 16)
local ypos = (math.floor(pos.y / 16) * 16)
local zpos = (math.floor(pos.z / 16) * 16)
local pos1 = {x=xpos, y=ypos, z=zpos}
local pos2 = {x=xpos+15, y=ypos+15, z=zpos+15}
return pos1, pos2
end
local function in_list(list, x)
local pos1 = calc_area(x)
for _,v in ipairs(list) do
local pos2 = calc_area(v)
if vector.equals(pos1, pos2) then return true end
end
return false
end
local function remove_list_elem(list, x)
local n = nil
for idx, v in ipairs(list) do
if vector.equals(v, x) then
n = idx
break
end
end
if n then
table.remove(list, n)
end
return list
end
local function chat(player, text)
minetest.chat_send_player(player:get_player_name(), "[Techage] "..text)
end
local function add_pos(pos, player)
local lPos = minetest.deserialize(player:get_attribute("techage_forceload_blocks")) or {}
if not in_list(lPos, pos) and (#lPos < techage.max_num_forceload_blocks or
creative and creative.is_enabled_for and
creative.is_enabled_for(player:get_player_name())) then
lPos[#lPos+1] = pos
player:set_attribute("techage_forceload_blocks", minetest.serialize(lPos))
return true
end
return false
end
local function del_pos(pos, player)
local lPos = minetest.deserialize(player:get_attribute("techage_forceload_blocks")) or {}
lPos = remove_list_elem(lPos, pos)
player:set_attribute("techage_forceload_blocks", minetest.serialize(lPos))
end
local function get_pos_list(player)
return minetest.deserialize(player:get_attribute("techage_forceload_blocks")) or {}
end
local function set_pos_list(player, lPos)
player:set_attribute("techage_forceload_blocks", minetest.serialize(lPos))
end
local function get_data(pos, player)
local pos1, pos2 = calc_area(pos)
local num = #minetest.deserialize(player:get_attribute("techage_forceload_blocks")) or 0
local max = techage.max_num_forceload_blocks
return pos1, pos2, num, max
end
local function formspec(player)
local lPos = get_pos_list(player)
local tRes = {}
tRes[1] = "size[7,9]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[0,0;List of your Forceload Blocks:]"
for idx,pos in ipairs(lPos) do
local pos1, pos2 = calc_area(pos)
local ypos = 0.2 + idx * 0.4
tRes[#tRes+1] = "label[0,"..ypos..";"..idx.."]"
tRes[#tRes+1] = "label[0.8,"..ypos..";"..P2S(pos1).."]"
tRes[#tRes+1] = "label[3.2,"..ypos..";to]"
tRes[#tRes+1] = "label[4,"..ypos..";"..P2S(pos2).."]"
end
return table.concat(tRes)
end
minetest.register_node("techage:forceload", {
description = "Techage Forceload Block",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta2.png^techage_frame_ta2_top.png',
'techage_filling_ta2.png^techage_frame_ta2_top.png',
{
image = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
},
after_place_node = function(pos, placer, itemstack)
if add_pos(pos, placer) then
minetest.forceload_block(pos, true)
local pos1, pos2, num, max = get_data(pos, placer)
M(pos):set_string("infotext", "Area "..P2S(pos1).." to "..P2S(pos2).." loaded!\n"..
"Punch the block to make the area visible.")
chat(placer, "Area ("..num.."/"..max..") "..P2S(pos1).." to "..P2S(pos2).." loaded!")
techage.mark_region(placer:get_player_name(), pos1, pos2)
M(pos):set_string("owner", placer:get_player_name())
else
chat(placer, "Area already loaded or max. number of Forceload Blocks reached!")
minetest.remove_node(pos)
return itemstack
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local player = minetest.get_player_by_name(oldmetadata.fields.owner)
if player then
del_pos(pos, player)
end
minetest.forceload_free_block(pos, true)
techage.unmark_region(oldmetadata.fields.owner)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if M(pos):get_string("owner") == clicker:get_player_name() or
minetest.check_player_privs(clicker:get_player_name(), "server") then
local s = formspec(clicker)
minetest.show_formspec(clicker:get_player_name(), "techage:forceload", s)
end
end,
on_punch = function(pos, node, puncher, pointed_thing)
local pos1, pos2 = calc_area(pos)
techage.switch_region(puncher:get_player_name(), pos1, pos2)
end,
paramtype = "light",
sunlight_propagates = true,
groups = {choppy=2, cracky=2, crumbly=2,
not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
if techage.max_num_forceload_blocks > 0 then
minetest.register_craft({
output = "techage:forceload",
recipe = {
{"group:wood", "", "group:wood"},
{"default:mese_crystal_fragment", "techage:usmium_nuggets", "default:mese_crystal_fragment"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
end
minetest.register_on_joinplayer(function(player)
local lPos = {}
for _,pos in ipairs(get_pos_list(player)) do
local node = techage.get_node_lvm(pos)
if node.name == "techage:forceload" then
minetest.forceload_block(pos, true)
lPos[#lPos+1] = pos
end
end
set_pos_list(player, lPos)
end)
minetest.register_on_leaveplayer(function(player)
for _,pos in ipairs(get_pos_list(player)) do
minetest.forceload_free_block(pos, true)
end
end)
techage.register_entry_page("ta", "forceload",
S("Techage Forceload Block"),
S("The Forceload Block keeps the corresponding area loaded and the machines operational "..
"as far as the player is logged in. If the player leaves the game, all areas will be unloaded.@n"..
"The maximum number of Forceload Blocks per player is configurable (default 20).@n"..
"The loaded area per block is a cube with 16 m side length (according to a Minetest area block). "..
"Punching the block makes the area visible and invisible again."),
"techage:forceload")