minetest-mods/basic_machines/enviro.lua
2019-12-14 17:47:31 +01:00

382 lines
No EOL
12 KiB
Lua

-- ENVIRO block: change physics and skybox for players
-- note: nonadmin players are limited in changes ( cant change skybox and have limits on other allowed changes)
-- rnd 2016:
local enviro = {};
enviro.skyboxes = {
["default"]={type = "regular", tex = {}},
["space"]={type="skybox", tex={"sky_pos_y.png","sky_neg_y.png","sky_pos_z.png","sky_neg_z.png","sky_neg_x.png","sky_pos_x.png",}}, -- need textures installed!
["caves"]={type = "cavebox", tex = {"black.png","black.png","black.png","black.png","black.png","black.png",}},
};
local space_start = 1100;
local ENABLE_SPACE_EFFECTS = false -- enable damage outside protected areas
local enviro_update_form = function (pos)
local meta = minetest.get_meta(pos);
local x0,y0,z0;
x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0");
local skybox = meta:get_string("skybox");
local skylist = "";
local sky_ind,j;
j=1;sky_ind = 3;
for i,_ in pairs(enviro.skyboxes) do
if i == skybox then sky_ind = j end
skylist = skylist .. i .. ",";
j=j+1;
end
local r = meta:get_int("r");
local speed,jump, g, sneak;
speed = meta:get_float("speed");jump = meta:get_float("jump");
g = meta:get_float("g"); sneak = meta:get_int("sneak");
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z;
local form =
"size[8,8.5]".. -- width, height
"field[0.25,0.5;1,1;x0;target;"..x0.."] field[1.25,0.5;1,1;y0;;"..y0.."] field[2.25,0.5;1,1;z0;;"..z0.."]"..
"field[3.25,0.5;1,1;r;radius;"..r.."]"..
--speed, jump, gravity,sneak
"field[0.25,1.5;1,1;speed;speed;"..speed.."]"..
"field[1.25,1.5;1,1;jump;jump;"..jump.."]"..
"field[2.25,1.5;1,1;g;gravity;"..g.."]"..
"field[3.25,1.5;1,1;sneak;sneak;"..sneak.."]"..
"label[0.,3.0;Skybox selection]"..
"dropdown[0.,3.35;3,1;skybox;"..skylist..";"..sky_ind.."]"..
"button_exit[3.25,3.25;1,1;OK;OK]"..
"list["..list_name..";fuel;3.25,2.25;1,1;]"..
"list[current_player;main;0,4.5;8,4;]"..
"listring[current_player;main]"..
"listring["..list_name..";fuel]"..
"listring[current_player;main]"
meta:set_string("formspec",form)
end
-- enviroment changer
minetest.register_node("basic_machines:enviro", {
description = "Changes enviroment for players around target location",
tiles = {"enviro.png"},
drawtype = "allfaces",
paramtype = "light",
param1=1,
groups = {cracky=3, mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.env:get_meta(pos)
meta:set_string("infotext", "Right click to set it. Activate by signal.")
meta:set_string("owner", placer:get_player_name()); meta:set_int("public",1);
meta:set_int("x0",0);meta:set_int("y0",0);meta:set_int("z0",0); -- target
meta:set_int("r",5); meta:set_string("skybox","default");
meta:set_float("speed",1);
meta:set_float("jump",1);
meta:set_float("g",1);
meta:set_int("sneak",1);
meta:set_int("admin",0);
local name = placer:get_player_name();
meta:set_string("owner",name);
local privs = minetest.get_player_privs(name);
if privs.privs then meta:set_int("admin",1) end
if privs.machines then meta:set_int("machines",1) end
local inv = meta:get_inventory();
inv:set_size("fuel",1*1);
enviro_update_form(pos);
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
local meta = minetest.get_meta(pos);
local machines = meta:get_int("machines");
if not machines == 1 then meta:set_string("infotext","Error. You need machines privs.") return end
local admin = meta:get_int("admin");
local inv = meta:get_inventory(); local stack = ItemStack("default:diamond 1");
if inv:contains_item("fuel", stack) then
inv:remove_item("fuel", stack);
else
meta:set_string("infotext","Error. Insert diamond in fuel inventory")
return
end
local x0,y0,z0,r,skybox,speed,jump,g,sneak;
x0=meta:get_int("x0"); y0=meta:get_int("y0");z0=meta:get_int("z0"); -- target
r= meta:get_int("r",5); skybox=meta:get_string("skybox");
speed=meta:get_float("speed");jump= meta:get_float("jump");
g=meta:get_float("g");sneak=meta:get_int("sneak"); if sneak~=0 then sneak = true else sneak = false end
local players = minetest.get_connected_players();
for _,player in pairs(players) do
local pos1 = player:getpos();
local dist = math.sqrt((pos1.x-pos.x)^2 + (pos1.y-pos.y)^2 + (pos1.z-pos.z)^2 );
if dist<=r then
player:set_physics_override({speed=speed,jump=jump,gravity=g,sneak=sneak})
if admin == 1 then -- only admin can change skybox
local sky = enviro.skyboxes[skybox];
player:set_sky(0,sky["type"],sky["tex"]);
end
end
end
-- attempt to set acceleration to balls, if any around
local objects = minetest.get_objects_inside_radius(pos, r)
for _,obj in pairs(objects) do
if obj:get_luaentity() then
local obj_name = obj:get_luaentity().name or ""
if obj_name == "basic_machines:ball" then
obj:setacceleration({x=0,y=-g,z=0});
end
end
end
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name();if minetest.is_protected(pos,name) then return end
if fields.OK then
local privs = minetest.get_player_privs(sender:get_player_name());
local meta = minetest.get_meta(pos);
local x0=0; local y0=0; local z0=0;
--minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
if fields.x0 then x0 = tonumber(fields.x0) or 0 end
if fields.y0 then y0 = tonumber(fields.y0) or 0 end
if fields.z0 then z0 = tonumber(fields.z0) or 0 end
if not privs.privs and (math.abs(x0)>10 or math.abs(y0)>10 or math.abs(z0) > 10) then return end
meta:set_int("x0",x0);meta:set_int("y0",y0);meta:set_int("z0",z0);
if privs.privs then -- only admin can set sky
if fields.skybox then meta:set_string("skybox", fields.skybox) end
end
if fields.r then
local r = tonumber(fields.r) or 0;
if r > 10 and not privs.privs then return end
meta:set_int("r", r)
end
if fields.g then
local g = tonumber(fields.g) or 1;
if (g<0.1 or g>40) and not privs.privs then return end
meta:set_float("g", g)
end
if fields.speed then
local speed = tonumber(fields.speed) or 1;
if (speed>1 or speed < 0) and not privs.privs then return end
meta:set_float("speed", speed)
end
if fields.jump then
local jump = tonumber(fields.jump) or 1;
if (jump<0 or jump>2) and not privs.privs then return end
meta:set_float("jump", jump)
end
if fields.sneak then
meta:set_int("sneak", tonumber(fields.sneak) or 0)
end
enviro_update_form(pos);
end
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
})
-- DEFAULT (SPAWN) PHYSICS VALUE/SKYBOX
local reset_player_physics = function(player)
if player then
player:set_physics_override({speed=1,jump=1,gravity=1}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["default"]; -- default skybox is "default"
player:set_sky(0,skybox["type"],skybox["tex"]);
end
end
-- globally available function
enviro_adjust_physics = function(player) -- adjust players physics/skybox 1 second after various events
minetest.after(1, function()
if player then
local pos = player:getpos(); if not pos then return end
if pos.y > space_start then -- is player in space or not?
player:set_physics_override({speed=1,jump=0.5,gravity=0.1}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["space"];
player:set_sky(0,skybox["type"],skybox["tex"]);
else
player:set_physics_override({speed=1,jump=1,gravity=1}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["default"];
player:set_sky(0,skybox["type"],skybox["tex"]);
end
end
end)
end
-- restore default values/skybox on respawn of player
minetest.register_on_respawnplayer(reset_player_physics)
-- when player joins, check where he is and adjust settings
minetest.register_on_joinplayer(enviro_adjust_physics)
-- SERVER GLOBAL SPACE CODE: uncomment to enable it
local round = math.floor;
local protector_position = function(pos)
local r = 20;
local ry = 2*r;
return {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry,z=round(pos.z/r+0.5)*r};
end
local stimer = 0
local enviro_space = {};
minetest.register_globalstep(function(dtime)
stimer = stimer + dtime;
if stimer >= 5 then
stimer = 0;
local players = minetest.get_connected_players();
for _,player in pairs(players) do
local name = player:get_player_name();
local pos = player:getpos();
local inspace=0; if pos.y>space_start then inspace = 1 end
local inspace0=enviro_space[name];
if inspace~=inspace0 then -- only adjust player enviroment ONLY if change occured ( earth->space or space->earth !)
enviro_space[name] = inspace;
enviro_adjust_physics(player);
end
if ENABLE_SPACE_EFFECTS and inspace==1 then -- special space code
if pos.y<1500 and pos.y>1120 then
local hp = player:get_hp();
if hp>0 then
minetest.chat_send_player(name,"WARNING: you entered DEADLY RADIATION ZONE");
local privs = minetest.get_player_privs(name)
if not privs.kick then player:set_hp(hp-15) end
end
return
else
local ppos = protector_position(pos);
local populated = (minetest.get_node(ppos).name=="basic_protect:protector");
if populated then
if minetest.get_meta(ppos):get_int("space") == 1 then populated = false end
end
if not populated then -- do damage if player found not close to protectors
local hp = player:get_hp();
local privs = minetest.get_player_privs(name);
if hp>0 and not privs.kick then
player:set_hp(hp-10); -- dead in 20/10 = 2 events
minetest.chat_send_player(name,"WARNING: in space you must stay close to spawn or protected areas");
end
end
end
end
end
end
end)
-- END OF SPACE CODE
-- AIR EXPERIMENT
-- minetest.register_node("basic_machines:air", {
-- description = "enables breathing in space",
-- drawtype = "liquid",
-- tiles = {"default_water_source_animated.png"},
-- drawtype = "glasslike",
-- paramtype = "light",
-- alpha = 150,
-- sunlight_propagates = true, -- Sunlight shines through
-- walkable = false, -- Would make the player collide with the air node
-- pointable = false, -- You can't select the node
-- diggable = false, -- You can't dig the node
-- buildable_to = true,
-- drop = "",
-- groups = {not_in_creative_inventory=1},
-- after_place_node = function(pos, placer, itemstack, pointed_thing)
-- local r = 3;
-- for i = -r,r do
-- for j = -r,r do
-- for k = -r,r do
-- local p = {x=pos.x+i,y=pos.y+j,z=pos.z+k};
-- if minetest.get_node(p).name == "air" then
-- minetest.set_node(p,{name = "basic_machines:air"})
-- end
-- end
-- end
-- end
-- end
-- })
-- minetest.register_abm({
-- nodenames = {"basic_machines:air"},
-- neighbors = {"air"},
-- interval = 10,
-- chance = 1,
-- action = function(pos, node, active_object_count, active_object_count_wider)
-- minetest.set_node(pos,{name = "air"})
-- end
-- });
minetest.register_on_punchplayer( -- bring gravity closer to normal with each punch
function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
if player:get_physics_override() == nil then return end
local pos = player:getpos(); if pos.y>= space_start then return end
local gravity = player:get_physics_override().gravity;
if gravity<1 then
gravity = 1;
player:set_physics_override({gravity=gravity})
end
end
)
-- RECIPE: extremely expensive
-- minetest.register_craft({
-- output = "basic_machines:enviro",
-- recipe = {
-- {"basic_machines:generator", "basic_machines:clockgen","basic_machines:generator"},
-- {"basic_machines:generator", "basic_machines:generator","basic_machines:generator"},
-- {"basic_machines:generator", "basic_machines:generator", "basic_machines:generator"}
-- }
-- })