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