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? |
ef8bb3
|
9 |
local digilines_path = minetest.get_modpath("digilines") |
D |
10 |
|
ee0765
|
11 |
local forcefield_power_drain = 10 |
S |
12 |
|
be2f30
|
13 |
local S = technic.getter |
S |
14 |
|
54004f
|
15 |
local cable_entry = "^technic_cable_connection_overlay.png" |
VE |
16 |
|
ee0765
|
17 |
minetest.register_craft({ |
30a37a
|
18 |
output = "technic:forcefield_emitter_off", |
ee0765
|
19 |
recipe = { |
44cb8d
|
20 |
{"default:mese", "basic_materials:motor", "default:mese" }, |
51f9df
|
21 |
{"technic:deployer_off", "technic:machine_casing", "technic:deployer_off"}, |
D |
22 |
{"default:mese", "technic:hv_cable", "default:mese" }, |
ee0765
|
23 |
} |
S |
24 |
}) |
30a37a
|
25 |
|
S |
26 |
|
|
27 |
local replaceable_cids = {} |
|
28 |
|
|
29 |
minetest.after(0, function() |
|
30 |
for name, ndef in pairs(minetest.registered_nodes) do |
|
31 |
if ndef.buildable_to == true and name ~= "ignore" then |
|
32 |
replaceable_cids[minetest.get_content_id(name)] = true |
|
33 |
end |
|
34 |
end |
|
35 |
end) |
ee0765
|
36 |
|
S |
37 |
|
|
38 |
-- Idea: Let forcefields have different colors by upgrade slot. |
|
39 |
-- Idea: Let forcefields add up by detecting if one hits another. |
|
40 |
-- ___ __ |
|
41 |
-- / \/ \ |
|
42 |
-- | | |
|
43 |
-- \___/\___/ |
|
44 |
|
aa82fa
|
45 |
local function update_forcefield(pos, meta, active) |
830de4
|
46 |
local shape = meta:get_int("shape") |
Z |
47 |
local range = meta:get_int("range") |
ee0765
|
48 |
local vm = VoxelManip() |
30a37a
|
49 |
local MinEdge, MaxEdge = vm:read_from_map(vector.subtract(pos, range), |
S |
50 |
vector.add(pos, range)) |
ee0765
|
51 |
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge}) |
S |
52 |
local data = vm:get_data() |
|
53 |
|
30a37a
|
54 |
local c_air = minetest.get_content_id("air") |
ee0765
|
55 |
local c_field = minetest.get_content_id("technic:forcefield") |
S |
56 |
|
30a37a
|
57 |
for z = -range, range do |
S |
58 |
for y = -range, range do |
|
59 |
local vi = area:index(pos.x + (-range), pos.y + y, pos.z + z) |
|
60 |
for x = -range, range do |
830de4
|
61 |
local relevant |
Z |
62 |
if shape == 0 then |
30a37a
|
63 |
local squared = x * x + y * y + z * z |
830de4
|
64 |
relevant = |
30a37a
|
65 |
squared <= range * range + range and |
S |
66 |
squared >= (range - 1) * (range - 1) + (range - 1) |
830de4
|
67 |
else |
Z |
68 |
relevant = |
|
69 |
x == -range or x == range or |
|
70 |
y == -range or y == range or |
|
71 |
z == -range or z == range |
|
72 |
end |
|
73 |
if relevant then |
30a37a
|
74 |
local cid = data[vi] |
S |
75 |
if active and replaceable_cids[cid] then |
ee0765
|
76 |
data[vi] = c_field |
30a37a
|
77 |
elseif not active and cid == c_field then |
ee0765
|
78 |
data[vi] = c_air |
S |
79 |
end |
|
80 |
end |
|
81 |
vi = vi + 1 |
|
82 |
end |
|
83 |
end |
|
84 |
end |
|
85 |
|
|
86 |
vm:set_data(data) |
|
87 |
vm:update_liquids() |
|
88 |
vm:write_to_map() |
|
89 |
end |
|
90 |
|
2d6f34
|
91 |
local function set_forcefield_formspec(meta) |
ef8bb3
|
92 |
local formspec |
D |
93 |
if digilines_path then |
|
94 |
formspec = "size[5,3.25]".. |
|
95 |
"field[0.3,3;5,1;channel;Digiline Channel;"..meta:get_string("channel").."]" |
|
96 |
else |
|
97 |
formspec = "size[5,2.25]" |
|
98 |
end |
|
99 |
formspec = formspec.. |
830de4
|
100 |
"field[0.3,0.5;2,1;range;"..S("Range")..";"..meta:get_int("range").."]" |
cca72f
|
101 |
-- The names for these toggle buttons are explicit about which |
Z |
102 |
-- state they'll switch to, so that multiple presses (arising |
|
103 |
-- from the ambiguity between lag and a missed press) only make |
|
104 |
-- the single change that the user expects. |
830de4
|
105 |
if meta:get_int("shape") == 0 then |
Z |
106 |
formspec = formspec.."button[3,0.2;2,1;shape1;"..S("Sphere").."]" |
|
107 |
else |
|
108 |
formspec = formspec.."button[3,0.2;2,1;shape0;"..S("Cube").."]" |
|
109 |
end |
6a4cb1
|
110 |
if meta:get_int("mesecon_mode") == 0 then |
cca72f
|
111 |
formspec = formspec.."button[0,1;5,1;mesecon_mode_1;"..S("Ignoring Mesecon Signal").."]" |
2d6f34
|
112 |
else |
cca72f
|
113 |
formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]" |
6a4cb1
|
114 |
end |
0f6bdb
|
115 |
-- TODO: String replacement with %s will stop working with client-side translations |
6a4cb1
|
116 |
if meta:get_int("enabled") == 0 then |
0f6bdb
|
117 |
formspec = formspec.."button[0,1.75;5,1;enable;".. |
S |
118 |
S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
6a4cb1
|
119 |
else |
0f6bdb
|
120 |
formspec = formspec.."button[0,1.75;5,1;disable;".. |
S |
121 |
S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
2d6f34
|
122 |
end |
Z |
123 |
meta:set_string("formspec", formspec) |
ee0765
|
124 |
end |
S |
125 |
|
|
126 |
local forcefield_receive_fields = function(pos, formname, fields, sender) |
b81d1d
|
127 |
local player_name = sender:get_player_name() |
L |
128 |
if minetest.is_protected(pos, player_name) then |
|
129 |
minetest.chat_send_player(player_name, "You are not allowed to edit this!") |
|
130 |
minetest.record_protection_violation(pos, player_name) |
|
131 |
return |
|
132 |
end |
ee0765
|
133 |
local meta = minetest.get_meta(pos) |
830de4
|
134 |
local range = nil |
2d6f34
|
135 |
if fields.range then |
830de4
|
136 |
range = tonumber(fields.range) or 0 |
2d6f34
|
137 |
-- Smallest field is 5. Anything less is asking for trouble. |
Z |
138 |
-- Largest is 20. It is a matter of pratical node handling. |
|
139 |
-- At the maximim range updating the forcefield takes about 0.2s |
|
140 |
range = math.max(range, 5) |
|
141 |
range = math.min(range, 20) |
830de4
|
142 |
if range == meta:get_int("range") then range = nil end |
ee0765
|
143 |
end |
830de4
|
144 |
if fields.shape0 or fields.shape1 or range then |
Z |
145 |
update_forcefield(pos, meta, false) |
|
146 |
end |
|
147 |
if range then meta:set_int("range", range) end |
ef8bb3
|
148 |
if fields.channel then meta:set_string("channel", fields.channel) end |
D |
149 |
if fields.shape0 then meta:set_int("shape", 0) end |
|
150 |
if fields.shape1 then meta:set_int("shape", 1) end |
|
151 |
if fields.enable then meta:set_int("enabled", 1) end |
2d6f34
|
152 |
if fields.disable then meta:set_int("enabled", 0) end |
6a4cb1
|
153 |
if fields.mesecon_mode_0 then meta:set_int("mesecon_mode", 0) end |
Z |
154 |
if fields.mesecon_mode_1 then meta:set_int("mesecon_mode", 1) end |
2d6f34
|
155 |
set_forcefield_formspec(meta) |
ee0765
|
156 |
end |
S |
157 |
|
|
158 |
local mesecons = { |
|
159 |
effector = { |
|
160 |
action_on = function(pos, node) |
6a4cb1
|
161 |
minetest.get_meta(pos):set_int("mesecon_effect", 1) |
ee0765
|
162 |
end, |
S |
163 |
action_off = function(pos, node) |
6a4cb1
|
164 |
minetest.get_meta(pos):set_int("mesecon_effect", 0) |
ee0765
|
165 |
end |
S |
166 |
} |
ef8bb3
|
167 |
} |
D |
168 |
|
|
169 |
local digiline_def = { |
|
170 |
receptor = {action = function() end}, |
|
171 |
effector = { |
|
172 |
action = function(pos, node, channel, msg) |
|
173 |
local meta = minetest.get_meta(pos) |
|
174 |
if channel ~= meta:get_string("channel") then |
|
175 |
return |
|
176 |
end |
51f9df
|
177 |
local msgt = type(msg) |
D |
178 |
if msgt == "string" then |
|
179 |
local smsg = msg:lower() |
|
180 |
msg = {} |
|
181 |
if smsg == "get" then |
|
182 |
msg.command = "get" |
|
183 |
elseif smsg == "off" then |
|
184 |
msg.command = "off" |
|
185 |
elseif smsg == "on" then |
|
186 |
msg.command = "on" |
|
187 |
elseif smsg == "toggle" then |
|
188 |
msg.command = "toggle" |
|
189 |
elseif smsg:sub(1, 5) == "range" then |
|
190 |
msg.command = "range" |
|
191 |
msg.value = tonumber(smsg:sub(7)) |
|
192 |
elseif smsg:sub(1, 5) == "shape" then |
|
193 |
msg.command = "shape" |
|
194 |
msg.value = smsg:sub(7):lower() |
|
195 |
msg.value = tonumber(msg.value) or msg.value |
|
196 |
end |
|
197 |
elseif msgt ~= "table" then |
|
198 |
return |
|
199 |
end |
|
200 |
if msg.command == "get" then |
ef8bb3
|
201 |
digilines.receptor_send(pos, digilines.rules.default, channel, { |
D |
202 |
enabled = meta:get_int("enabled"), |
|
203 |
range = meta:get_int("range"), |
|
204 |
shape = meta:get_int("shape") |
|
205 |
}) |
|
206 |
return |
51f9df
|
207 |
elseif msg.command == "off" then |
ef8bb3
|
208 |
meta:set_int("enabled", 0) |
51f9df
|
209 |
elseif msg.command == "on" then |
ef8bb3
|
210 |
meta:set_int("enabled", 1) |
51f9df
|
211 |
elseif msg.command == "toggle" then |
ef8bb3
|
212 |
local onn = meta:get_int("enabled") |
D |
213 |
onn = 1-onn -- Mirror onn with pivot 0.5, so switch between 1 and 0. |
|
214 |
meta:set_int("enabled", onn) |
51f9df
|
215 |
elseif msg.command == "range" then |
D |
216 |
if type(msg.value) ~= "number" then |
ef8bb3
|
217 |
return |
D |
218 |
end |
51f9df
|
219 |
msg.value = math.max(msg.value, 5) |
D |
220 |
msg.value = math.min(msg.value, 20) |
ef8bb3
|
221 |
update_forcefield(pos, meta, false) |
51f9df
|
222 |
meta:set_int("range", msg.value) |
D |
223 |
elseif msg.command == "shape" then |
|
224 |
local valuet = type(msg.value) |
|
225 |
if valuet == "string" then |
|
226 |
if msg.value == "sphere" then |
|
227 |
msg.value = 0 |
|
228 |
elseif msg.value == "cube" then |
|
229 |
msg.value = 1 |
|
230 |
end |
|
231 |
elseif valuet ~= "number" then |
|
232 |
return |
ef8bb3
|
233 |
end |
51f9df
|
234 |
if not msg.value then |
ef8bb3
|
235 |
return |
D |
236 |
end |
|
237 |
update_forcefield(pos, meta, false) |
51f9df
|
238 |
meta:set_int("shape", msg.value) |
ef8bb3
|
239 |
else |
D |
240 |
return |
|
241 |
end |
|
242 |
set_forcefield_formspec(meta) |
|
243 |
end |
|
244 |
}, |
ee0765
|
245 |
} |
S |
246 |
|
30a37a
|
247 |
local function run(pos, node) |
563a4c
|
248 |
local meta = minetest.get_meta(pos) |
N |
249 |
local eu_input = meta:get_int("HV_EU_input") |
51f9df
|
250 |
local enabled = meta:get_int("enabled") ~= 0 and |
D |
251 |
(meta:get_int("mesecon_mode") == 0 or meta:get_int("mesecon_effect") ~= 0) |
563a4c
|
252 |
local machine_name = S("%s Forcefield Emitter"):format("HV") |
N |
253 |
|
830de4
|
254 |
local range = meta:get_int("range") |
Z |
255 |
local power_requirement |
|
256 |
if meta:get_int("shape") == 0 then |
|
257 |
power_requirement = math.floor(4 * math.pi * range * range) |
|
258 |
else |
|
259 |
power_requirement = 24 * range * range |
|
260 |
end |
|
261 |
power_requirement = power_requirement * forcefield_power_drain |
563a4c
|
262 |
|
6a4cb1
|
263 |
if not enabled then |
563a4c
|
264 |
if node.name == "technic:forcefield_emitter_on" then |
830de4
|
265 |
update_forcefield(pos, meta, false) |
563a4c
|
266 |
technic.swap_node(pos, "technic:forcefield_emitter_off") |
N |
267 |
meta:set_string("infotext", S("%s Disabled"):format(machine_name)) |
|
268 |
end |
849526
|
269 |
meta:set_int("HV_EU_demand", 0) |
Z |
270 |
return |
|
271 |
end |
|
272 |
meta:set_int("HV_EU_demand", power_requirement) |
|
273 |
if eu_input < power_requirement then |
563a4c
|
274 |
meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) |
N |
275 |
if node.name == "technic:forcefield_emitter_on" then |
830de4
|
276 |
update_forcefield(pos, meta, false) |
563a4c
|
277 |
technic.swap_node(pos, "technic:forcefield_emitter_off") |
N |
278 |
end |
|
279 |
elseif eu_input >= power_requirement then |
|
280 |
if node.name == "technic:forcefield_emitter_off" then |
|
281 |
technic.swap_node(pos, "technic:forcefield_emitter_on") |
|
282 |
meta:set_string("infotext", S("%s Active"):format(machine_name)) |
|
283 |
end |
aa82fa
|
284 |
update_forcefield(pos, meta, true) |
563a4c
|
285 |
end |
N |
286 |
end |
|
287 |
|
ee0765
|
288 |
minetest.register_node("technic:forcefield_emitter_off", { |
7c4b70
|
289 |
description = S("%s Forcefield Emitter"):format("HV"), |
54004f
|
290 |
tiles = { |
VE |
291 |
"technic_forcefield_emitter_off.png", |
|
292 |
"technic_machine_bottom.png"..cable_entry, |
|
293 |
"technic_forcefield_emitter_off.png", |
|
294 |
"technic_forcefield_emitter_off.png", |
|
295 |
"technic_forcefield_emitter_off.png", |
|
296 |
"technic_forcefield_emitter_off.png" |
|
297 |
}, |
83c649
|
298 |
groups = {cracky = 1, technic_machine = 1, technic_hv = 1}, |
ee0765
|
299 |
on_receive_fields = forcefield_receive_fields, |
S |
300 |
on_construct = function(pos) |
|
301 |
local meta = minetest.get_meta(pos) |
|
302 |
meta:set_int("HV_EU_input", 0) |
|
303 |
meta:set_int("HV_EU_demand", 0) |
|
304 |
meta:set_int("range", 10) |
|
305 |
meta:set_int("enabled", 0) |
6a4cb1
|
306 |
meta:set_int("mesecon_mode", 0) |
Z |
307 |
meta:set_int("mesecon_effect", 0) |
ef8bb3
|
308 |
if digilines_path then |
D |
309 |
meta:set_string("channel", "forcefield"..minetest.pos_to_string(pos)) |
|
310 |
end |
7c4b70
|
311 |
meta:set_string("infotext", S("%s Forcefield Emitter"):format("HV")) |
2d6f34
|
312 |
set_forcefield_formspec(meta) |
ee0765
|
313 |
end, |
563a4c
|
314 |
mesecons = mesecons, |
ef8bb3
|
315 |
digiline = digiline_def, |
563a4c
|
316 |
technic_run = run, |
ee0765
|
317 |
}) |
S |
318 |
|
|
319 |
minetest.register_node("technic:forcefield_emitter_on", { |
7c4b70
|
320 |
description = S("%s Forcefield Emitter"):format("HV"), |
54004f
|
321 |
tiles = { |
VE |
322 |
"technic_forcefield_emitter_on.png", |
|
323 |
"technic_machine_bottom.png"..cable_entry, |
|
324 |
"technic_forcefield_emitter_on.png", |
|
325 |
"technic_forcefield_emitter_on.png", |
|
326 |
"technic_forcefield_emitter_on.png", |
|
327 |
"technic_forcefield_emitter_on.png" |
|
328 |
}, |
83c649
|
329 |
groups = {cracky = 1, technic_machine = 1, technic_hv = 1, |
S |
330 |
not_in_creative_inventory=1}, |
ee0765
|
331 |
drop = "technic:forcefield_emitter_off", |
S |
332 |
on_receive_fields = forcefield_receive_fields, |
|
333 |
on_destruct = function(pos) |
|
334 |
local meta = minetest.get_meta(pos) |
830de4
|
335 |
update_forcefield(pos, meta, false) |
ee0765
|
336 |
end, |
563a4c
|
337 |
mesecons = mesecons, |
ef8bb3
|
338 |
digiline = digiline_def, |
563a4c
|
339 |
technic_run = run, |
2a7ee1
|
340 |
technic_on_disable = function (pos, node) |
Z |
341 |
local meta = minetest.get_meta(pos) |
830de4
|
342 |
update_forcefield(pos, meta, false) |
2a7ee1
|
343 |
technic.swap_node(pos, "technic:forcefield_emitter_off") |
Z |
344 |
end, |
51f9df
|
345 |
on_blast = function(pos, intensity) |
D |
346 |
minetest.dig_node(pos) |
|
347 |
return {"technic:forcefield_emitter_off"} |
|
348 |
end, |
ee0765
|
349 |
}) |
S |
350 |
|
|
351 |
minetest.register_node("technic:forcefield", { |
7c4b70
|
352 |
description = S("%s Forcefield"):format("HV"), |
ee0765
|
353 |
sunlight_propagates = true, |
S |
354 |
drawtype = "glasslike", |
45919b
|
355 |
groups = {not_in_creative_inventory=1}, |
ee0765
|
356 |
paramtype = "light", |
51f9df
|
357 |
light_source = default.LIGHT_MAX, |
45919b
|
358 |
diggable = false, |
ee0765
|
359 |
drop = '', |
S |
360 |
tiles = {{ |
|
361 |
name = "technic_forcefield_animated.png", |
|
362 |
animation = { |
|
363 |
type = "vertical_frames", |
|
364 |
aspect_w = 16, |
|
365 |
aspect_h = 16, |
|
366 |
length = 1.0, |
|
367 |
}, |
|
368 |
}}, |
51f9df
|
369 |
on_blast = function(pos, intensity) |
D |
370 |
end, |
ee0765
|
371 |
}) |
S |
372 |
|
|
373 |
|
|
374 |
if minetest.get_modpath("mesecons_mvps") then |
8da4d0
|
375 |
mesecon.register_mvps_stopper("technic:forcefield") |
ee0765
|
376 |
end |
S |
377 |
|
|
378 |
technic.register_machine("HV", "technic:forcefield_emitter_on", technic.receiver) |
|
379 |
technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver) |
|
380 |
|