Tim
2015-03-16 137695ea67cf7096311c893de7cf139e6307b26b
commit | author | age
30a37a 1 --- Forcefield generator.
S 2 -- @author ShadowNinja
ee0765 3 --
S 4 -- Forcefields are powerful barriers but they consume huge amounts of power.
30a37a 5 -- The forcefield Generator is an HV machine.
ee0765 6
S 7 -- How expensive is the generator?
8 -- Leaves room for upgrades lowering the power drain?
9 local forcefield_power_drain   = 10
10
be2f30 11 local S = technic.getter
S 12
ee0765 13 minetest.register_craft({
30a37a 14     output = "technic:forcefield_emitter_off",
ee0765 15     recipe = {
30a37a 16             {"default:mese",         "technic:motor",          "default:mese"        },
S 17             {"technic:deployer_off", "technic:machine_casing", "technic:deployer_off"},
18             {"default:mese",         "technic:hv_cable0",      "default:mese"        },
ee0765 19     }
S 20 })
30a37a 21
S 22
23 local replaceable_cids = {}
24
25 minetest.after(0, function()
26     for name, ndef in pairs(minetest.registered_nodes) do
27         if ndef.buildable_to == true and name ~= "ignore" then
28             replaceable_cids[minetest.get_content_id(name)] = true
29         end
30     end
31 end)
ee0765 32
S 33
34 -- Idea: Let forcefields have different colors by upgrade slot.
35 -- Idea: Let forcefields add up by detecting if one hits another.
36 --    ___   __
37 --   /   \/   \
38 --  |          |
39 --   \___/\___/
40
30a37a 41 local function update_forcefield(pos, meta, active, first)
830de4 42     local shape = meta:get_int("shape")
Z 43     local range = meta:get_int("range")
ee0765 44     local vm = VoxelManip()
30a37a 45     local MinEdge, MaxEdge = vm:read_from_map(vector.subtract(pos, range),
S 46             vector.add(pos, range))
ee0765 47     local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
S 48     local data = vm:get_data()
49
30a37a 50     local c_air = minetest.get_content_id("air")
ee0765 51     local c_field = minetest.get_content_id("technic:forcefield")
S 52
30a37a 53     for z = -range, range do
S 54     for y = -range, range do
55     local vi = area:index(pos.x + (-range), pos.y + y, pos.z + z)
56     for x = -range, range do
830de4 57         local relevant
Z 58         if shape == 0 then
30a37a 59             local squared = x * x + y * y + z * z
830de4 60             relevant =
30a37a 61                 squared <= range       *  range      +  range and
S 62                 squared >= (range - 1) * (range - 1) + (range - 1)
830de4 63         else
Z 64             relevant =
65                 x == -range or x == range or
66                 y == -range or y == range or
67                 z == -range or z == range
68         end
69         if relevant then
30a37a 70             local cid = data[vi]
S 71             if active and replaceable_cids[cid] then
ee0765 72                 data[vi] = c_field
30a37a 73             elseif not active and cid == c_field then
ee0765 74                 data[vi] = c_air
S 75             end
76         end
77         vi = vi + 1
78     end
79     end
80     end
81
82     vm:set_data(data)
83     vm:update_liquids()
84     vm:write_to_map()
30a37a 85     -- update_map is very slow, but if we don't call it we'll
S 86     -- get phantom blocks on the client.
87     if not active or first then
88         vm:update_map()
89     end
ee0765 90 end
S 91
2d6f34 92 local function set_forcefield_formspec(meta)
cca72f 93     local formspec = "size[5,2.25]"..
830de4 94         "field[0.3,0.5;2,1;range;"..S("Range")..";"..meta:get_int("range").."]"
cca72f 95     -- The names for these toggle buttons are explicit about which
Z 96     -- state they'll switch to, so that multiple presses (arising
97     -- from the ambiguity between lag and a missed press) only make
98     -- the single change that the user expects.
830de4 99     if meta:get_int("shape") == 0 then
Z 100         formspec = formspec.."button[3,0.2;2,1;shape1;"..S("Sphere").."]"
101     else
102         formspec = formspec.."button[3,0.2;2,1;shape0;"..S("Cube").."]"
103     end
6a4cb1 104     if meta:get_int("mesecon_mode") == 0 then
cca72f 105         formspec = formspec.."button[0,1;5,1;mesecon_mode_1;"..S("Ignoring Mesecon Signal").."]"
2d6f34 106     else
cca72f 107         formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]"
6a4cb1 108     end
Z 109     if meta:get_int("enabled") == 0 then
cca72f 110         formspec = formspec.."button[0,1.75;5,1;enable;"..S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
6a4cb1 111     else
cca72f 112         formspec = formspec.."button[0,1.75;5,1;disable;"..S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
2d6f34 113     end
Z 114     meta:set_string("formspec", formspec)
ee0765 115 end
S 116
117 local forcefield_receive_fields = function(pos, formname, fields, sender)
118     local meta = minetest.get_meta(pos)
830de4 119     local range = nil
2d6f34 120     if fields.range then
830de4 121         range = tonumber(fields.range) or 0
2d6f34 122         -- Smallest field is 5. Anything less is asking for trouble.
Z 123         -- Largest is 20. It is a matter of pratical node handling.
124         -- At the maximim range updating the forcefield takes about 0.2s
125         range = math.max(range, 5)
126         range = math.min(range, 20)
830de4 127         if range == meta:get_int("range") then range = nil end
ee0765 128     end
830de4 129     if fields.shape0 or fields.shape1 or range then
Z 130         update_forcefield(pos, meta, false)
131     end
132     if range then meta:set_int("range", range) end
133     if fields.shape0 then meta:set_int("shape", 0) end
134     if fields.shape1 then meta:set_int("shape", 1) end
2d6f34 135     if fields.enable then meta:set_int("enabled", 1) end
Z 136     if fields.disable then meta:set_int("enabled", 0) end
6a4cb1 137     if fields.mesecon_mode_0 then meta:set_int("mesecon_mode", 0) end
Z 138     if fields.mesecon_mode_1 then meta:set_int("mesecon_mode", 1) end
2d6f34 139     set_forcefield_formspec(meta)
ee0765 140 end
S 141
142 local mesecons = {
143     effector = {
144         action_on = function(pos, node)
6a4cb1 145             minetest.get_meta(pos):set_int("mesecon_effect", 1)
ee0765 146         end,
S 147         action_off = function(pos, node)
6a4cb1 148             minetest.get_meta(pos):set_int("mesecon_effect", 0)
ee0765 149         end
S 150     }
151 }
152
30a37a 153 local function run(pos, node)
563a4c 154     local meta = minetest.get_meta(pos)
N 155     local eu_input   = meta:get_int("HV_EU_input")
cca72f 156     local enabled = meta:get_int("enabled") ~= 0 and (meta:get_int("mesecon_mode") == 0 or meta:get_int("mesecon_effect") ~= 0)
563a4c 157     local machine_name = S("%s Forcefield Emitter"):format("HV")
N 158
830de4 159     local range = meta:get_int("range")
Z 160     local power_requirement
161     if meta:get_int("shape") == 0 then
162         power_requirement = math.floor(4 * math.pi * range * range)
163     else
164         power_requirement = 24 * range * range
165     end
166     power_requirement = power_requirement * forcefield_power_drain
563a4c 167
6a4cb1 168     if not enabled then
563a4c 169         if node.name == "technic:forcefield_emitter_on" then
830de4 170             update_forcefield(pos, meta, false)
563a4c 171             technic.swap_node(pos, "technic:forcefield_emitter_off")
N 172             meta:set_string("infotext", S("%s Disabled"):format(machine_name))
173         end
849526 174         meta:set_int("HV_EU_demand", 0)
Z 175         return
176     end
177     meta:set_int("HV_EU_demand", power_requirement)
178     if eu_input < power_requirement then
563a4c 179         meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
N 180         if node.name == "technic:forcefield_emitter_on" then
830de4 181             update_forcefield(pos, meta, false)
563a4c 182             technic.swap_node(pos, "technic:forcefield_emitter_off")
N 183         end
184     elseif eu_input >= power_requirement then
30a37a 185         local first = false
563a4c 186         if node.name == "technic:forcefield_emitter_off" then
30a37a 187             first = true
563a4c 188             technic.swap_node(pos, "technic:forcefield_emitter_on")
N 189             meta:set_string("infotext", S("%s Active"):format(machine_name))
190         end
30a37a 191         update_forcefield(pos, meta, true, first)
563a4c 192     end
N 193 end
194
ee0765 195 minetest.register_node("technic:forcefield_emitter_off", {
7c4b70 196     description = S("%s Forcefield Emitter"):format("HV"),
ee0765 197     tiles = {"technic_forcefield_emitter_off.png"},
563a4c 198     groups = {cracky = 1, technic_machine = 1},
ee0765 199     on_receive_fields = forcefield_receive_fields,
S 200     on_construct = function(pos)
201         local meta = minetest.get_meta(pos)
202         meta:set_int("HV_EU_input", 0)
203         meta:set_int("HV_EU_demand", 0)
204         meta:set_int("range", 10)
205         meta:set_int("enabled", 0)
6a4cb1 206         meta:set_int("mesecon_mode", 0)
Z 207         meta:set_int("mesecon_effect", 0)
7c4b70 208         meta:set_string("infotext", S("%s Forcefield Emitter"):format("HV"))
2d6f34 209         set_forcefield_formspec(meta)
ee0765 210     end,
563a4c 211     mesecons = mesecons,
N 212     technic_run = run,
ee0765 213 })
S 214
215 minetest.register_node("technic:forcefield_emitter_on", {
7c4b70 216     description = S("%s Forcefield Emitter"):format("HV"),
ee0765 217     tiles = {"technic_forcefield_emitter_on.png"},
563a4c 218     groups = {cracky = 1, technic_machine = 1, not_in_creative_inventory=1},
ee0765 219     drop = "technic:forcefield_emitter_off",
S 220     on_receive_fields = forcefield_receive_fields,
221     on_destruct = function(pos)
222         local meta = minetest.get_meta(pos)
830de4 223         update_forcefield(pos, meta, false)
ee0765 224     end,
563a4c 225     mesecons = mesecons,
N 226     technic_run = run,
2a7ee1 227     technic_on_disable = function (pos, node)
Z 228         local meta = minetest.get_meta(pos)
830de4 229         update_forcefield(pos, meta, false)
2a7ee1 230         technic.swap_node(pos, "technic:forcefield_emitter_off")
Z 231     end,
ee0765 232 })
S 233
234 minetest.register_node("technic:forcefield", {
7c4b70 235     description = S("%s Forcefield"):format("HV"),
ee0765 236     sunlight_propagates = true,
S 237     drawtype = "glasslike",
45919b 238     groups = {not_in_creative_inventory=1},
ee0765 239     paramtype = "light",
S 240         light_source = 15,
45919b 241     diggable = false,
ee0765 242     drop = '',
S 243     tiles = {{
244         name = "technic_forcefield_animated.png",
245         animation = {
246             type = "vertical_frames",
247             aspect_w = 16,
248             aspect_h = 16,
249             length = 1.0,
250         },
251     }},
252 })
253
254
255 if minetest.get_modpath("mesecons_mvps") then
8da4d0 256     mesecon.register_mvps_stopper("technic:forcefield")
ee0765 257 end
S 258
259 technic.register_machine("HV", "technic:forcefield_emitter_on",  technic.receiver)
260 technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)
261