-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclaw-multi-silo.lua
More file actions
386 lines (342 loc) · 14.1 KB
/
claw-multi-silo.lua
File metadata and controls
386 lines (342 loc) · 14.1 KB
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
/sc
if storage.multi_silo then
game.player.print("Multi Silo is already running", {color = {r=0.9,g=0,b=0}})
return
end
local Event = require "utils.event"
storage.multi_silo = {}
storage.multi_silo["north"]={}
storage.multi_silo["south"]={}
storage.multi_silo_max_build = 2500
storage.multi_silo_respawn = {}
table.insert(storage.multi_silo["north"], storage.rocket_silo["north"])
table.insert(storage.multi_silo["south"], storage.rocket_silo["south"])
for i,player in pairs(game.connected_players) do
if storage.chosen_team[player.name] then
player.insert{name = "rocket-silo", count = 1}
end
end
storage.multi_silo_join_team_delay_template = 'function(event) local join_team_delay_template = nil
if storage.multi_silo then
local player_index = tonumber("__pindex__")
local player = game.players[player_index]
if player then
player.insert{name = "rocket-silo", count = 1}
end
end
local Event = require "utils.event"
Event.remove_removable_nth_tick_function(tonumber("__tick__"), "__fname__")
end'
local multi_silo_on_player_changed_force = 'function(event) local on_player_changed_force = nil
if not storage.multi_silo then return end
if storage.server_restart_timer ~= nil then return end
local player = game.get_player(event.player_index)
if player.force.name ~= "north" and player.force.name ~= "south" then return end
if storage.chosen_team[player.name] then return end
local f_name = "multi_silo_join_team_delay_" .. event.player_index
local tick = game.tick + 5
local f_str = storage.multi_silo_join_team_delay_template
f_str = string.gsub(f_str, "__pindex__", event.player_index)
f_str = string.gsub(f_str, "__tick__", tick)
f_str = string.gsub(f_str, "__fname__", f_name)
local Event = require "utils.event"
Event.add_removable_nth_tick_function(tick, f_str, f_name)
end'
Event.add_removable_function(defines.events.on_player_changed_force, multi_silo_on_player_changed_force, "multi_silo_on_player_changed_force")
local multi_silo_on_gui_click = 'function(event) local on_gui_click = nil
if not event.element.valid or event.element.name ~= "bb_spectate" then return end
local player = game.players[event.player_index]
if not player.character then return end
if player.character.position.x ^ 2 + player.character.position.y ^ 2 < 12000 then return end
local silos = player.physical_surface.find_entities_filtered{name="rocket-silo", position=player.character.position, radius=20, limit=1}
if #silos == 0 then return end
spectate(player, false, player.character.position)
end'
Event.add_removable_function(defines.events.on_gui_click, multi_silo_on_gui_click, "multi_silo_on_gui_click")
local multi_silo_on_unit_group_finished_gathering = 'function(event) local on_unit_group_finished_gathering = nil
if storage.bb_game_won_by_team then return end
if not storage.multi_silo then return end
local biter_force = event.group.force.name
local force
if biter_force == "north_biters" or biter_force == "north_biters_boss" then
force = "north"
elseif biter_force == "south_biters" or biter_force == "south_biters_boss" then
force = "south"
else
return
end
local silos = storage.multi_silo[force]
if not silos or #silos == 0 then return end
local function closest_silo(pos)
local closest_silo = silos[1]
local dist = (pos.x - closest_silo.position.x) ^ 2 + (pos.y - closest_silo.position.y) ^ 2
for i = 2, #silos do
local other_silo = silos[i]
local other_dist = (pos.x - other_silo.position.x) ^ 2 + (pos.y - other_silo.position.y) ^ 2
if other_dist < dist then
closest_silo = other_silo
dist = other_dist
end
end
return closest_silo
end
local command = event.group.command
if not command or (command.type == defines.command.attack and not command.target.valid) then
local command = {
type = defines.command.attack,
target = closest_silo(event.group.position),
distraction = defines.distraction.by_damage,
}
event.group.set_command(command)
elseif command.type == defines.command.compound then
local target_pos = nil
for _, cmd in ipairs(command.commands) do
if cmd.type == defines.command.attack_area then
target_pos = cmd.destination
break
end
end
if target_pos then
local attack_cmd = nil
for _, cmd in ipairs(command.commands) do
if cmd.type == defines.command.attack then
attack_cmd = cmd
break
end
end
local nearby_silo = closest_silo(target_pos)
if not attack_cmd then
command.commands[#command.commands + 1] = {
type = defines.command.attack,
target = nearby_silo,
distraction = defines.distraction.by_damage,
}
event.group.set_command(command)
elseif attack_cmd.target ~= nearby_silo then
attack_cmd.target = nearby_silo
event.group.set_command(command)
end
end
end
end'
Event.add_removable_function(defines.events.on_unit_group_finished_gathering, multi_silo_on_unit_group_finished_gathering, "multi_silo_on_unit_group_finished_gathering")
local multi_silo_on_player_died = 'function(event) local on_player_died = nil
local player = game.players[event.player_index]
local name = player.name
if event.cause and event.cause.position then
storage.multi_silo_respawn[name] = event.cause.position
return
end
local surface = game.surfaces[storage.bb_surface_name]
local corpses = surface.find_entities_filtered{name="character-corpse"}
local last_tick = 0
local last_corpse
for i,corpse in pairs (corpses) do
if corpse.character_corpse_player_index == event.player_index then
if corpse.character_corpse_tick_of_death > last_tick then
last_tick = corpse.character_corpse_tick_of_death
last_corpse = corpse
end
end
end
if last_corpse then
storage.multi_silo_respawn[name] = last_corpse.position
end
end'
Event.add_removable_function(defines.events.on_player_died, multi_silo_on_player_died, "multi_silo_on_player_died")
local multi_silo_on_entity_died = 'function(event) local on_entity_died = nil
if not storage.multi_silo then return end
if not event.entity.valid or event.entity.name ~= "rocket-silo" then return end
local entity = event.entity
local force = entity.force.name
if not storage.multi_silo[force] then return end
if storage.rocket_silo[force] and entity == storage.rocket_silo[force] then
storage.multi_silo[force] = {}
return
end
if storage.rocket_silo[force] and entity.position.x == storage.rocket_silo[force].position.x and entity.position.y == storage.rocket_silo[force].position.y and #storage.multi_silo[force] == 1 then
storage.multi_silo[force][1] = storage.rocket_silo[force]
return
end
for i,silo in pairs(storage.multi_silo[force]) do
if silo == entity then
if event.force == entity.force then
local surface = entity.surface
entity = surface.create_entity {
name = entity.name,
position = entity.position,
surface = surface,
force = entity.force,
create_build_effect_smoke = false,
}
entity.minable_flag = false
entity.health = 5
local AiTargets = require "maps.biter_battles_v2.ai_targets"
AiTargets.start_tracking(entity)
storage.multi_silo[force][i] = entity
return
end
table.remove(storage.multi_silo[force], i)
if #storage.multi_silo[force] == 1 then
storage.rocket_silo[force] = storage.multi_silo[force][1]
end
if event.force then
entity.surface.create_entity({
name = "atomic-rocket",
position = entity.position,
force = event.force,
source = entity.position,
target = entity.position,
max_range = 1,
speed = 0.1
})
else
entity.surface.create_entity({
name = "atomic-rocket",
position = entity.position,
force = entity.force.name .. "_biters",
source = entity.position,
target = entity.position,
max_range = 1,
speed = 0.1
})
end
return
end
end
end'
Event.add_removable_function(defines.events.on_entity_died, multi_silo_on_entity_died, "multi_silo_on_entity_died")
local multi_silo_on_built_entity = 'function(event) local on_built_entity = nil
if not storage.multi_silo then return end
if not event.entity.valid or event.entity.name ~= "rocket-silo" then return end
local entity = event.entity
local force = entity.force.name
local r = 20
local restricted_tiles = entity.surface.find_tiles_filtered{area={top_left={math.floor(entity.position.x - r), math.floor(entity.position.y - r)}, bottom_right={math.floor(entity.position.x + r), math.floor(entity.position.y + r)}}, name = {"water", "deepwater", "landfill"}}
local allowed_to_build = true
local warning = ""
if #restricted_tiles > 0 then
allowed_to_build = false
warning = "Too close to water or landfill!"
end
if math.abs(entity.position.x) > storage.multi_silo_max_build then
allowed_to_build = false
warning = "Too far from spawn by " .. math.floor(math.abs(entity.position.x) - storage.multi_silo_max_build) .. " units"
end
if not allowed_to_build then
if event.player_index then
local player = game.get_player(event.player_index)
player.insert({name = "rocket-silo", count = 1})
player.create_local_flying_text({
position = entity.position,
text = warning,
color = {r=0.98, g=0.66, b=0.22}
})
else
local inventory = event.robot.get_inventory(defines.inventory.robot_cargo)
inventory.insert({name = "rocket-silo", count = 1})
end
entity.destroy()
return
end
entity.minable_flag = false
table.insert(storage.multi_silo[force], entity)
if storage.rocket_silo[force] and #storage.multi_silo[force] > 1 then
storage.rocket_silo[force] = nil
end
end'
local multi_silo_on_built_entity_robot = multi_silo_on_built_entity
Event.add_removable_function(defines.events.on_built_entity, multi_silo_on_built_entity, "multi_silo_on_built_entity")
Event.add_removable_function(defines.events.on_robot_built_entity, multi_silo_on_built_entity_robot, "multi_silo_on_built_entity_robot")
local multi_silo_on_player_respawned = 'function(event) local on_player_respawned = nil
if not storage.multi_silo_respawn then return end
local player = game.players[event.player_index]
if not player.valid then return end
local force = player.force.name
if force ~= "north" and force ~= "south" then return end
local position = storage.multi_silo_respawn[player.name]
if not position then return end
local min_dist = 1e9
local min_silo
for _, silo in pairs(storage.multi_silo[force]) do
local silo_dist = (silo.position.x - position.x) * (silo.position.x - position.x) + (silo.position.y - position.y) * (silo.position.y - position.y)
if silo_dist < min_dist then
min_dist = silo_dist
min_silo = silo
end
end
if not min_silo then return end
teleport_pos = player.physical_surface.find_non_colliding_position("character", {x = min_silo.position.x, y = min_silo.position.y + 5}, 20, 0.1)
if teleport_pos then
player.teleport(teleport_pos)
end
storage.multi_silo_respawn[player.name]=nil
end'
Event.add_removable_function(defines.events.on_player_respawned, multi_silo_on_player_respawned, "multi_silo_on_player_respawned")
local multi_silo_chart_silos = 'function (event) local chart_silos = nil
if not storage.multi_silo then return end
local r = 48
local surface = game.surfaces[storage.bb_surface_name]
local enemy = {
["north"] = "south",
["south"] = "north",
}
for _, force in pairs({"north", "south"}) do
for _, silo in pairs(storage.multi_silo[force]) do
if silo.valid then
game.forces[force].chart(surface, {{silo.position.x - r, silo.position.y - r}, {silo.position.x + r, silo.position.y + r}})
if storage.spy_fish_timeout[enemy[force]] and storage.spy_fish_timeout[enemy[force]] > game.tick then
game.forces[enemy[force]].chart(surface, {{silo.position.x - r, silo.position.y - r}, {silo.position.x + r, silo.position.y + r}})
end
end
end
end
end'
Event.add_removable_nth_tick_function(300, multi_silo_chart_silos, "multi_silo_chart_silos")
local multi_silo_on_surface_deleted = 'function(event) local on_surface_deleted = nil
if not storage.multi_silo then return end
local Event = require "utils.event"
Event.remove_removable_function(defines.events.on_surface_deleted, "multi_silo_on_surface_deleted")
Event.remove_removable_function(defines.events.on_player_respawned, "multi_silo_on_player_respawned")
Event.remove_removable_function(defines.events.on_built_entity, "multi_silo_on_built_entity")
Event.remove_removable_function(defines.events.on_robot_built_entity, "multi_silo_on_built_entity_robot")
Event.remove_removable_function(defines.events.on_player_died, "multi_silo_on_player_died")
Event.remove_removable_function(defines.events.on_gui_click, "multi_silo_on_gui_click")
Event.remove_removable_function(defines.events.on_entity_died, "multi_silo_on_entity_died")
Event.remove_removable_function(defines.events.on_player_changed_force, "multi_silo_on_player_changed_force")
Event.remove_removable_function(defines.events.on_unit_group_finished_gathering, "multi_silo_on_unit_group_finished_gathering")
Event.remove_removable_nth_tick_function(300, "multi_silo_chart_silos")
storage.multi_silo_join_team_delay_template = nil
storage.multi_silo_max_build = nil
storage.multi_silo_respawn = nil
storage.multi_silo = nil
game.print("Special game: Multi Silo removed.")
end'
Event.add_removable_function(defines.events.on_surface_deleted, multi_silo_on_surface_deleted, "multi_silo_on_surface_deleted")
local texts = {
"Special game: Multi Silo Special",
"Your team will survive until all rocket-silos have been destroyed.",
"Players receive one silo upon joining a team.",
"Silos explode when destroyed, benefit from anti-grief, and cannot be mined.",
"Upon death, players will respawn at the closest silo.",
"Silos cannot be placed beyond " .. storage.multi_silo_max_build .. " units. Unpathable silos are not allowed (warn-jail).",
}
local surface = game.surfaces[storage.bb_surface_name]
local chest = surface.create_entity({name = "wooden-chest", position = {0.5, -25.5}})
chest.destructible = false
chest.minable_flag = false
chest.operable = false
for i, text in pairs(texts) do
local color = {255, 255, 0}
rendering.draw_text {
text = text,
surface = surface,
target = { entity = chest, offset = {0, 2 * i}},
color = color,
scale = 1.00,
font = "heading-1",
alignment = "center",
scale_with_zoom = true
}
end
game.print("Special game: Multi Silo loaded.", {color = {r=0.9,g=0.1,b=0.9}})