ShadowNinja
2013-10-30 be2f30a1a2f5b6c2aae7fd4cf8231aec2da0844d
commit | author | age
ee0765 1 -- Forcefield mod by ShadowNinja
S 2 -- Modified by kpoppel
3 --
4 -- Forcefields are powerful barriers but they consume huge amounts of power.
5 -- Forcefield Generator is a HV machine.
6
7 -- How expensive is the generator?
8 -- Leaves room for upgrades lowering the power drain?
9 local forcefield_power_drain   = 10
10 local forcefield_step_interval = 1
11
be2f30 12 local S = technic.getter
S 13
ee0765 14 minetest.register_craft({
S 15     output = 'technic:forcefield_emitter_off',
16     recipe = {
17             {'default:mese',         'technic:deployer_off', 'default:mese'        },
18             {'technic:deployer_off', 'technic:motor',        'technic:deployer_off'},
19             {'default:mese',         'technic:deployer_off', 'default:mese'        },
20     }
21 })
22
23
24 -- Idea: Let forcefields have different colors by upgrade slot.
25 -- Idea: Let forcefields add up by detecting if one hits another.
26 --    ___   __
27 --   /   \/   \
28 --  |          |
29 --   \___/\___/
30
31 local function update_forcefield(pos, range, active)
32     local vm = VoxelManip()
33     local p1 = {x = pos.x-range, y = pos.y-range, z = pos.z-range}
34     local p2 = {x = pos.x+range, y = pos.y+range, z = pos.z+range}
35     local MinEdge, MaxEdge = vm:read_from_map(p1, p2)
36     local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
37     local data = vm:get_data()
38
39     local c_air   = minetest.get_content_id("air")
40     local c_field = minetest.get_content_id("technic:forcefield")
41
42     for z=-range, range do
43     for y=-range, range do
44     local vi = area:index(pos.x+(-range), pos.y+y, pos.z+z)
45     for x=-range, range do
46         if x*x+y*y+z*z <= range     *  range    +  range    and
47            x*x+y*y+z*z >= (range-1) * (range-1) + (range-1) then
48             if active and data[vi] == c_air then
49                 data[vi] = c_field
50             elseif not active and data[vi] == c_field then
51                 data[vi] = c_air
52             end
53         end
54         vi = vi + 1
55     end
56     end
57     end
58
59     vm:set_data(data)
60     vm:update_liquids()
61     vm:write_to_map()
62     vm:update_map()
63 end
64
65 local get_forcefield_formspec = function(range)
66     return "size[3,1.5]"..
be2f30 67         "field[1,0.5;2,1;range;"..S("Range")..";"..range.."]"..
S 68         "button[0,1;3,1;toggle;"..S("Enable/Disable").."]"
ee0765 69 end
S 70
71 local forcefield_receive_fields = function(pos, formname, fields, sender)
72     local meta = minetest.get_meta(pos)
cee65b 73     local range = tonumber(fields.range) or 0
ee0765 74
S 75     if fields.toggle then
76         if meta:get_int("enabled") == 1 then
77            meta:set_int("enabled", 0)
78         else
79            meta:set_int("enabled", 1)
80         end
81     end
82
83     -- Smallest field is 5. Anything less is asking for trouble.
84     -- Largest is 20. It is a matter of pratical node handling.
85     -- At the maximim range updating the forcefield takes about 0.2s
86     range = math.max(range, 5)
87     range = math.min(range, 20)
88
89     if meta:get_int("range") ~= range then
90         update_forcefield(pos, meta:get_int("range"), false)
91         meta:set_int("range", range)
92         meta:set_string("formspec", get_forcefield_formspec(range))
93     end
94 end
95
96 local mesecons = {
97     effector = {
98         action_on = function(pos, node)
99             minetest.get_meta(pos):set_int("enabled", 0)
100         end,
101         action_off = function(pos, node)
102             minetest.get_meta(pos):set_int("enabled", 1)
103         end
104     }
105 }
106
107 minetest.register_node("technic:forcefield_emitter_off", {
be2f30 108     description = S("Forcefield Emitter"),
ee0765 109     tiles = {"technic_forcefield_emitter_off.png"},
S 110     groups = {cracky = 1},
111     on_receive_fields = forcefield_receive_fields,
112     on_construct = function(pos)
113         local meta = minetest.get_meta(pos)
114         meta:set_int("HV_EU_input", 0)
115         meta:set_int("HV_EU_demand", 0)
116         meta:set_int("range", 10)
117         meta:set_int("enabled", 0)
118         meta:set_string("formspec", get_forcefield_formspec(10))
be2f30 119         meta:set_string("infotext", S("Forcefield Emitter"))
ee0765 120     end,
S 121     mesecons = mesecons
122 })
123
124 minetest.register_node("technic:forcefield_emitter_on", {
be2f30 125     description = S("Forcefield Emitter"),
ee0765 126     tiles = {"technic_forcefield_emitter_on.png"},
S 127     groups = {cracky = 1, not_in_creative_inventory=1},
128     drop = "technic:forcefield_emitter_off",
129     on_receive_fields = forcefield_receive_fields,
130     on_construct = function(pos) 
131         local meta = minetest.get_meta(pos)
132         local range = meta:get_int("range")
133         meta:set_string("formspec", get_forcefield_formspec(range))
134     end,
135     on_destruct = function(pos)
136         local meta = minetest.get_meta(pos)
137         update_forcefield(pos, meta:get_int("range"), false)
138     end,
139     mesecons = mesecons
140 })
141
142 minetest.register_node("technic:forcefield", {
be2f30 143     description = S("Forcefield"),
ee0765 144     sunlight_propagates = true,
S 145     drawtype = "glasslike",
146     groups = {not_in_creative_inventory=1, unbreakable=1},
147     paramtype = "light",
148         light_source = 15,
149     drop = '',
150     tiles = {{
151         name = "technic_forcefield_animated.png",
152         animation = {
153             type = "vertical_frames",
154             aspect_w = 16,
155             aspect_h = 16,
156             length = 1.0,
157         },
158     }},
159 })
160 minetest.register_abm({
161     nodenames = {"technic:forcefield_emitter_on", "technic:forcefield_emitter_off"},
162     interval = 1,
163     chance = 1,
164     action = function(pos, node, active_object_count, active_object_count_wider)
165         local meta = minetest.get_meta(pos)
166         local eu_input   = meta:get_int("HV_EU_input")
167         local eu_demand  = meta:get_int("HV_EU_demand")
168         local enabled    = meta:get_int("enabled")
be2f30 169         local machine_name = S("Forcefield Emitter")
ee0765 170         -- Power off automatically if no longer connected to a switching station
S 171         technic.switching_station_timeout_count(pos, "HV")
172
173         local power_requirement = math.floor(
174                 4 * math.pi * math.pow(meta:get_int("range"), 2)
175             ) * forcefield_power_drain
176
177         if meta:get_int("enabled") == 0 then
178             if node.name == "technic:forcefield_emitter_on" then
179                 meta:set_int("HV_EU_demand", 0)
180                 update_forcefield(pos, meta:get_int("range"), false)
181                 hacky_swap_node(pos, "technic:forcefield_emitter_off")
be2f30 182                 meta:set_string("infotext", S("%s Disabled"):format(machine_name))
ee0765 183                 return
S 184             end
185         elseif eu_input < power_requirement then
be2f30 186             meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
ee0765 187             if node.name == "technic:forcefield_emitter_on" then
S 188                 update_forcefield(pos, meta:get_int("range"), false)
189                 hacky_swap_node(pos, "technic:forcefield_emitter_off")
190             end
191         elseif eu_input >= power_requirement then
192             if node.name == "technic:forcefield_emitter_off" then
193                 hacky_swap_node(pos, "technic:forcefield_emitter_on")
be2f30 194                 meta:set_string("infotext", S("%s Active"):format(machine_name))
ee0765 195             end
S 196             update_forcefield(pos, meta:get_int("range"), true)
197         end
198         meta:set_int("HV_EU_demand", power_requirement)
199     end
200 })
201
202 if minetest.get_modpath("mesecons_mvps") then
203     mesecon:register_mvps_stopper("technic:forcefield")
204 end
205 -- TODO: Register a stopper for frames
206
207 technic.register_machine("HV", "technic:forcefield_emitter_on",  technic.receiver)
208 technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)
209