-
Notifications
You must be signed in to change notification settings - Fork 1
/
autodeconstruct.lua
278 lines (245 loc) · 11.2 KB
/
autodeconstruct.lua
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
-- Automatically deconstruct mines when no more ore is available
-- A 3Ra Gaming revision
-- Original Author: mindmix
autodeconstruct = autodeconstruct or {}
autodeconstruct.remove_target = true
-- Find ore resources in a given area
-- @param surface target surface
-- @param position center position
-- @param range range to search around center
-- @param resource_category type of resources to find
-- @return array of resources that match the category
local function find_resources(surface, position, range, resource_category)
local resource_category = resource_category or 'basic-solid'
local top_left = {x = position.x - range, y = position.y - range}
local bottom_right = {x = position.x + range, y = position.y + range}
local resources = surface.find_entities_filtered{area={top_left, bottom_right}, type='resource'}
categorized = {}
for _, resource in pairs(resources) do
if resource.prototype.resource_category == resource_category then
table.insert(categorized, resource)
end
end
return categorized
end
-- Find all entities of a certain type on the map. Called only once per map.
-- @param entity_type type of entity to find
-- @return array of matching entities
local function find_all_entities(entity_type)
local surface = game.surfaces['nauvis']
local entities = {}
for chunk in surface.get_chunks() do
local chunk_area = {lefttop = {x = chunk.x*32, y = chunk.y*32}, rightbottom = {x = chunk.x*32+32, y = chunk.y*32+32}}
local chunk_entities = surface.find_entities_filtered({area = chunk_area, type = entity_type})
for i = 1, #chunk_entities do
entities[#entities + 1] = chunk_entities[i]
end
end
return entities
end
-- Find an entity's target (output)
-- @param entity entity to find output for
-- @return LuaEntity target
local function find_target(entity)
if entity.drop_target then
return entity.drop_target
else
local entities = entity.surface.find_entities_filtered{position=entity.drop_position}
if global.debug then msg_all({"autodeconstruct-debug", "found " .. entities[1].name .. " at " .. util.positiontostr(entities[1].position)}) end
return entities[1]
end
end
-- Find all mining drills with the same target
-- @param entity the target to search for
-- @return array of mining drills
local function find_targeting(entity)
local range = global.max_radius
local position = entity.position
local top_left = {x = position.x - range, y = position.y - range}
local bottom_right = {x = position.x + range, y = position.y + range}
local surface = entity.surface
local entities = {}
local targeting = {}
local entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='mining-drill'}
for i = 1, #entities do
if find_target(entities[i]) == entity then
targeting[#targeting + 1] = entities[i]
end
end
entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='inserter'}
for i = 1, #entities do
if find_target(entities[i]) == entity then
targeting[#targeting + 1] = entities[i]
end
end
if global.debug then msg_all({"autodeconstruct-debug", "found " .. #targeting .. " targeting"}) end
return targeting
end
-- Find all mining drills that were mining a certain ore tile
-- @param entity ore entity
-- @return array of mining drills
local function find_drills(entity)
local position = entity.position
local surface = entity.surface
local top_left = {x = position.x - global.max_radius, y = position.y - global.max_radius}
local bottom_right = {x = position.x + global.max_radius, y = position.y + global.max_radius}
local entities = {}
local targeting = {}
local entities = surface.find_entities_filtered{area={top_left, bottom_right}, type='mining-drill'}
if global.debug then msg_all({"autodeconstruct-debug", "found " .. #entities .. " drills"}) end
for i = 1, #entities do
if math.abs(entities[i].position.x - position.x) < entities[i].prototype.mining_drill_radius and math.abs(entities[i].position.y - position.y) < entities[i].prototype.mining_drill_radius then
autodeconstruct.check_drill(entities[i])
end
end
end
-- Initialise globals
function autodeconstruct.init_globals()
global.max_radius = 0.99
drill_entities = find_all_entities('mining-drill')
for _, drill_entity in pairs(drill_entities) do
autodeconstruct.check_drill(drill_entity)
end
end
-- Handle resource depletion
function autodeconstruct.on_resource_depleted(event)
if event.entity.prototype.resource_category ~= 'basic-solid' or event.entity.prototype.infinite_resource ~= false then
if global.debug then msg_all({"autodeconstruct-debug", "on_resource_depleted", game.tick .. " amount " .. event.entity.amount .. " resource_category " .. event.entity.prototype.resource_category .. " infinite_resource " .. (event.entity.prototype.infinite_resource == true and "true" or "false" )}) end
return
end
drill = find_drills(event.entity)
end
-- Check a mining drill for depletion and order deconstruction if so
-- @param drill mining drill to check
function autodeconstruct.check_drill(drill)
if drill.mining_target ~= nil and drill.mining_target.valid then
if drill.mining_target.amount > 0 then return end -- this should also filter out pumpjacks and infinite resources
end
local mining_drill_radius = drill.prototype.mining_drill_radius
if mining_drill_radius > global.max_radius then
global.max_radius = mining_drill_radius
end
if mining_drill_radius == nil then return end
resources = find_resources(drill.surface, drill.position, mining_drill_radius)
for i = 1, #resources do
if resources[i].amount > 0 then return end
end
if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position) .. " found no resources, deconstructing"}) end
autodeconstruct.order_deconstruction(drill)
end
-- Handle cancelled deconstruction
function autodeconstruct.on_canceled_deconstruction(event)
if event.player_index ~= nil or event.entity.type ~= 'mining-drill' then return end
if global.debug then msg_all({"autodeconstruct-debug", "on_canceled_deconstruction", util.positiontostr(event.entity.position) .. " deconstruction timed out, checking again"}) end
autodeconstruct.check_drill(event.entity)
end
-- Handle placed entity
function autodeconstruct.on_built_entity(event)
if event.created_entity.type ~= 'mining-drill' then return end
if event.created_entity.prototype.mining_drill_radius > global.max_radius then
global.max_radius = event.created_entity.prototype.mining_drill_radius
if global.debug then msg_all({"autodeconstruct-debug", "on_built_entity", "global.max_radius updated to " .. global.max_radius}) end
end
end
-- Order drill deconstruction
-- @param drill mining drill to deconstruct
function autodeconstruct.order_deconstruction(drill)
if drill.to_be_deconstructed(drill.force) then
if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position)" already marked"}) end
return
end
local deconstruct = false
--[[ #TODO
config.lua: autodeconstruct.wait_for_robots = false
if autodeconstruct.wait_for_robots then
logistic_network = drill.surface.find_logistic_network_by_position(drill.position, drill.force.name)
if logistic_network ~= nil then
if logistic_network.available_construction_robots > 0 then
deconstruct = true
end
end
else
deconstruct = true
end
--]]
deconstruct = true
--[[ END TODO
--]]
if deconstruct == true and drill.minable then
if drill.order_deconstruction(drill.force) then
if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(drill.position) .. " " .. drill.name .. " success"}) end
else
msg_all({"autodeconstruct-err-specific", "drill.order_deconstruction", util.positiontostr(drill.position) .. "failed to order deconstruction on " .. drill.name })
end
if autodeconstruct.remove_target then
target = find_target(drill)
if target ~= nil and target.minable then
if target.type == "logistic-container" or target.type == "container" then
targeting = find_targeting(target)
if targeting ~= nil then
for i = 1, #targeting do
if not targeting[i].to_be_deconstructed(targeting[i].force) then return end
end
-- we are the only one targeting
if target.to_be_deconstructed(target.force) then
target.cancel_deconstruction(target.force)
end
if target.order_deconstruction(target.force) then
if global.debug then msg_all({"autodeconstruct-debug", util.positiontostr(target.position) .. " " .. target.name .. " success"}) end
else
msg_all({"autodeconstruct-err-specific", "target.order_deconstruction", util.positiontostr(target.position) .. "failed to order deconstruction on " .. target.name})
end
end
end
--[[ #TODO
if target.type == "transport-belt" then
-- find entities with this belt as target
end
--]]
end
end
end
end
-- Message all players
-- @param message message to sen
function msg_all(message)
if message[1] == "autodeconstruct-debug" then
table.insert(message, 2, debug.getinfo(2).name)
end
for _,p in pairs(game.players) do
p.print(message)
end
end
global.debug = false
remote.add_interface("ad", {
debug = function()
global.debug = not global.debug
end,
init = function()
autodeconstruct.init_globals()
end
})
Event.register(-1, function()
local _, err = pcall(autodeconstruct.init_globals)
if err then msg_all({"autodeconstruct-err-generic", err}) end
end)
Event.register(-3, function()
local _, err = pcall(autodeconstruct.init_globals)
if err then msg_all({"autodeconstruct-err-generic", err}) end
end)
Event.register(defines.events.on_canceled_deconstruction, function(event)
local _, err = pcall(autodeconstruct.on_canceled_deconstruction, event)
if err then msg_all({"autodeconstruct-err-specific", "on_canceled_deconstruction", err}) end
end)
Event.register(defines.events.on_resource_depleted, function(event)
local _, err = pcall(autodeconstruct.on_resource_depleted, event)
if err then msg_all({"autodeconstruct-err-specific", "on_resource_depleted", err}) end
end)
Event.register(defines.events.on_robot_built_entity, function(event)
local _, err = pcall(autodeconstruct.on_built_entity, event)
if err then msg_all({"autodeconstruct-err-specific", "on_robot_built_entity", err}) end
end)
Event.register(defines.events.on_built_entity, function(event)
local _, err = pcall(autodeconstruct.on_built_entity, event)
if err then msg_all({"autodeconstruct-err-specific", "on_built_entity", err}) end
end)