-
Notifications
You must be signed in to change notification settings - Fork 14
/
control.lua
297 lines (263 loc) · 10.9 KB
/
control.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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
require 'stdlib/game'
require 'stdlib/area/area'
require 'stdlib/area/position'
require 'stdlib/area/surface'
require 'stdlib/entity/entity'
require 'stdlib/event/event'
require 'stdlib/utils/string'
require 'stdlib/utils/table'
require 'scheduler'
Event.register({defines.events.on_built_entity, defines.events.on_robot_built_entity}, function(event)
local entity = event.created_entity
local type = entity.type
local name = entity.name
if name == 'radar' then
track_entity('radars', upgrade_radar_entity(entity))
elseif name == 'big-electric-pole' then
track_entity('power_poles', entity)
if entity.force.technologies['surveillance-2'].researched then
update_surveillance(entity, false)
end
elseif type == 'car' then
track_entity('vehicles', entity)
update_surveillance(entity, true)
elseif type == 'locomotive' then
track_entity('trains', entity)
update_surveillance(entity, true)
elseif name == 'big_brother-surveillance-center' then
entity.backer_name = ''
track_entity('surveillance_centers', entity)
update_all_surveillance(entity.force)
elseif type == 'entity-ghost' then
if entity.ghost_name == 'big_brother-blueprint-radar' then
entity.surface.create_entity({name = name, position = entity.position, force = entity.force, inner_name = 'radar'})
entity.destroy()
end
end
end)
Event.register({defines.events.on_entity_died, defines.events.on_robot_pre_mined, defines.events.on_player_mined_entity}, function(event)
local entity = event.entity
local type = entity.type
local name = entity.name
if name == 'big-electric-pole' then
if entity.force.technologies['surveillance-2'].researched then
remove_surveillance(entity, false)
end
elseif type == 'car' then
remove_surveillance(entity, true)
elseif type == 'locomotive' then
remove_surveillance(entity, true)
elseif name == 'big_brother-surveillance-center' then
local force = entity.force
Scheduler.add(nil, function(event)
update_all_surveillance(force)
end)
elseif type == 'radar' then
local radar_data = Entity.set_data(entity, nil)
if radar_data and radar_data.blueprint_radar and radar_data.blueprint_radar.valid then
radar_data.blueprint_radar.destroy()
end
end
end)
Event.register({defines.events.on_player_setup_blueprint, defines.events.on_player_configured_blueprint}, function(event)
local player = game.players[event.player_index]
if not player.valid then return end
local stack = player.blueprint_to_setup
if not stack.valid or not stack.valid_for_read then
stack = player.cursor_stack
if not stack.valid or not stack.valid_for_read then
return
end
end
if stack.name ~= "blueprint" then return end
local entities = stack.get_blueprint_entities()
if not entities then return end
local modified = false
for _, entity in pairs (entities) do
if entity.name == 'big_brother-blueprint-radar' then
entity.name = 'radar'
modified = true
end
end
if modified then
stack.set_blueprint_entities(entities)
end
end)
-- Scan the map once if the mod is updated
Event.register({Event.core_events.init, Event.core_events.configuration_changed}, function(event)
-- start tracking all important entities
table.each(game.surfaces, function(surface)
-- track all radars
local radars = surface.find_entities_filtered({name = 'radar'})
table.each(radars, function(entity) track_entity('radars', entity) end)
-- track all vehicles
local vehicles = surface.find_entities_filtered({type = 'car'})
table.each(vehicles, function(entity) track_entity('vehicles', entity) end)
-- track all trains
local trains = surface.find_entities_filtered({type = 'locomotive'})
table.each(trains, function(entity) track_entity('trains', entity) end)
-- track all big-electric-poles
local power_poles = surface.find_entities_filtered({name = 'big-electric-pole'})
table.each(power_poles, function(entity) track_entity('power_poles', entity) end)
end)
-- upgrade radars
table.each(game.forces, upgrade_radars)
end)
Event.register(defines.events.on_research_finished, function(event)
local tech_name = event.research.name
local force = event.research.force
if tech_name:starts_with('radar-amplifier') or tech_name:starts_with('radar-efficiency') then
Scheduler.add(force.name, function(event)
upgrade_radars(force)
end)
elseif tech_name == 'surveillance-2' then
if global.power_poles and global.surveillance_centers then
update_all_surveillance(force)
end
end
end)
Event.register(defines.events.on_sector_scanned, function(event)
if not global.following then return end
if event.radar.name == 'big_brother-surveillance-center' then
global.following = table.each(table.filter(global.following, Game.VALID_FILTER), function(entity)
if entity.type == 'locomotive' then
chart_train(entity)
else
entity.force.chart(entity.surface, Position.expand_to_area(entity.position, 1))
end
end)
end
end)
function update_all_surveillance(force)
table.each(table.filter(global.vehicles or {}, Game.VALID_FILTER), function(vehicle) update_surveillance(vehicle, true) end)
table.each(table.filter(global.trains or {}, Game.VALID_FILTER), function(train) update_surveillance(train, true) end)
if global.power_poles and force.technologies['surveillance-2'].researched then
global.power_poles = table.each(table.filter(global.power_poles, Game.VALID_FILTER), function(entity)
update_surveillance(entity, false)
end)
end
end
function chart_train(entity)
local train = entity.train
local speed = train.speed
if math.abs(speed) > 0.05 then
chart_locomotive(entity)
else
local surface = entity.surface
table.each(train.cargo_wagons, function(wagon)
entity.force.chart(surface, Position.expand_to_area(wagon.position, 1))
end)
end
end
function chart_locomotive(entity)
local pos = entity.position
local x = pos.x + 16 * math.sin(2 * math.pi * entity.orientation)
local y = pos.y - 16 * math.cos(2 * math.pi * entity.orientation)
entity.force.chart(entity.surface, Area.normalize({Position.construct(x, y), pos}))
end
function upgrade_radar_entity(radar, radar_efficiency_level, radar_amplifier_level)
if not radar.valid then return nil end
local force = radar.force
local radar_efficiency_level = radar_efficiency_level or calculate_tech_level(force, 'radar-efficiency', 9)
local radar_amplifier_level = radar_amplifier_level or calculate_tech_level(force, 'radar-amplifier', 9)
local radar_name = 'big_brother-radar_ra-' .. radar_amplifier_level .. '_re-' .. radar_efficiency_level
local pos = radar.position
local direction = radar.direction
local health = radar.health
local surface = radar.surface
local radar_data = Entity.set_data(radar, nil)
radar.destroy()
if not radar_data then
local blueprint_radar = surface.create_entity({ name = 'big_brother-blueprint-radar', position = pos, direction = direction, force = force})
Entity.set_frozen(blueprint_radar)
Entity.set_indestructible(blueprint_radar)
radar_data = { blueprint_radar = blueprint_radar }
end
local new_radar = surface.create_entity({ name = radar_name, position = pos, direction = direction, force = force})
new_radar.health = health
Entity.set_data(new_radar, radar_data)
return new_radar
end
function upgrade_radars(force)
if not global.radars then return end
local radar_efficiency_level = calculate_tech_level(force, 'radar-efficiency', 9)
local radar_amplifier_level = calculate_tech_level(force, 'radar-amplifier', 9)
local radar_name = 'big_brother-radar_ra-' .. radar_amplifier_level .. '_re-' .. radar_efficiency_level
for i = #global.radars, 1, -1 do
local radar = global.radars[i]
if not radar.valid then
table.remove(global.radars, i)
elseif radar.force == force then
global.radars[i] = upgrade_radar_entity(radar, radar_efficiency_level, radar_amplifier_level)
end
end
end
function calculate_tech_level(force, tech_name, max_levels)
local techs = force.technologies
for i = max_levels, 1, -1 do
local full_tech_name = tech_name
if i > 1 then
full_tech_name = tech_name .. '-' .. i
end
if techs[full_tech_name].researched then
return i
end
end
return 0
end
function update_surveillance(entity, follow)
local surv_center = get_nearest_surveillance_center(entity.position, entity.surface, entity.force)
if surv_center then
local data = Entity.get_data(entity)
if not data then
if not follow then
local surveillance = entity.surface.create_entity({name = 'big_brother-surveillance-small', position = entity.position, force = entity.force})
Entity.set_indestructible(surveillance)
Entity.set_data(entity, { surveillance = surveillance })
else
track_entity('following', entity)
end
end
else
remove_surveillance(entity, follow)
end
end
function remove_surveillance(entity, follow)
if follow then
global.following = table.filter(global.following or {}, function(followed) return followed ~= entity end)
else
local data = Entity.get_data(entity)
if data and data.surveillance and data.surveillance.valid then
data.surveillance.destroy()
Entity.set_data(entity, nil)
end
end
end
function get_nearest_surveillance_center(position, surface, force)
if global.surveillance_centers then
global.surveillance_centers = table.filter(global.surveillance_centers, Game.VALID_FILTER)
local list = table.filter(global.surveillance_centers, function(entity)
return entity.surface == surface and entity.force == force
end)
table.sort(list, function(a, b)
return Position.distance_squared(a.position, position) < Position.distance_squared(b.position, position)
end)
return table.first(list)
end
return nil
end
function track_entity(category, entity)
if not entity then return end
if not global[category] then global[category] = {} end
local entity_list = global[category]
for i = #entity_list, 1, -1 do
local e = entity_list[i]
if not e.valid then
table.remove(entity_list, i)
elseif e == entity then
return false
end
end
table.insert(entity_list, entity)
return true
end