Skip to content

Commit cde93f3

Browse files
committed
Actually added it.
1 parent e8bb5cc commit cde93f3

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed

lualib/antigrief.lua

+293
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
--Grief detection
2+
--Written by Mylon, 2017-2018
3+
--MIT License
4+
5+
antigrief = {}
6+
global.antigrief_cooldown = {}
7+
global.antigrief = {warned = {}}
8+
9+
antigrief.TROLL_TIMER = 60 * 60 * 30 --30 minutes. Players must be online this long to not throw some warnings.
10+
antigrief.SPAM_TIMER = 60 * 60 * 2 --10 minutes. Limit inventory related messages to once per 10m.
11+
12+
13+
14+
--ACTIVE functions
15+
function antigrief.arty_remote_ban(event)
16+
local player = game.players[event.player_index]
17+
local area = {{event.position.x-20, event.position.y-20}, {event.position.x+20, event.position.y+20}}
18+
local count = player.surface.count_entities_filtered{force=player.force, area=area}
19+
local ghosts = player.surface.count_entities_filtered{name="entity-ghost", force=player.force, area=area}
20+
21+
--Ghosts don't count! They can't be damaged.
22+
count = count - ghosts
23+
24+
if event.item.name == "artillery-targeting-remote" and count > 50 then
25+
antigrief.banhammer(player)
26+
antigrief.alert(player.name .. " is using an artillery remote maliciously.", player.character)
27+
elseif string.find(event.item.name, "grenade") and player.surface.count_entities_filtered{force=player.force, area=area, name="steam-engine"} > 20 then --Grenading power
28+
antigrief.banhammer(player)
29+
antigrief.alert(player.name .. " is using grenading power.", player.character)
30+
end
31+
end
32+
33+
function antigrief.banhammer(player)
34+
--If player is > level 5, then warn first.
35+
--What permission group is the player in?
36+
if player.permissions_group.name == "trusted" then --Kick first.
37+
if not global.antigrief.warned[player.name] then
38+
global.antigrief.warned[player.name] = true
39+
game.kick_player(player, "griefing (automoderator)")
40+
return
41+
end
42+
else
43+
game.ban_player(player, "griefing (automoderator)")
44+
end
45+
end
46+
47+
48+
--PASSIVE functions
49+
--Common tactic is to remove pump. So if someone landfills a pump and removes it... That's a huge red flag.
50+
function antigrief.pump(event)
51+
if not event.entity and not event.entity.valid then
52+
return
53+
end
54+
--Only check for entities in a specific list.
55+
if antigrief.is_well_pump(event.entity) then
56+
local player = game.players[event.player_index]
57+
antigrief.alert(player.name .. " has mined a well-water pump.", event.entity)
58+
end
59+
end
60+
61+
--Look for players mining ghosts far away.
62+
--Spooky action at a distance!
63+
function antigrief.ghosting(event)
64+
local player = game.players[event.player_index]
65+
if not event.entity and not event.entity.valid and not player and not player.valid then
66+
return
67+
end
68+
if event.entity.type == "entity-ghost" then
69+
--Look for units mined 200 tiles away.
70+
if math.abs(event.entity.position.x - player.position.x) + math.abs(event.entity.position.y - player.position.y) > 200 then
71+
if antigrief.check_cooldown(event.player_index, "ghosting") then
72+
antigrief.alert(player.name .. " is removing blueprint ghosts.", event.entity)
73+
end
74+
end
75+
end
76+
end
77+
78+
--When someone decons > 150 entities, fire an alert
79+
function antigrief.decon(event)
80+
if event.alt then --This is a cancel order.
81+
return
82+
end
83+
if event.area.left_top.x == event.area.right_bottom.x or event.area.left_top.y == event.area.right_bottom.y then
84+
--log("Antigrief: Deconstruction area is of zero size.")
85+
return
86+
end
87+
local player = game.players[event.player_index]
88+
local count = player.surface.count_entities_filtered{area=event.area, force=player.force}
89+
if count >= 150 then
90+
--Need a proper check of entities. Most might be filtered out and not actually deconned.
91+
local ents = player.surface.find_entities_filtered{area=event.area, force=player.force}
92+
count = 0
93+
for k, v in pairs(ents) do
94+
if v.to_be_deconstructed(player.force) then
95+
count = count + 1
96+
end
97+
end
98+
if count >= 150 then
99+
antigrief.alert(player.name .. " has deconstructed ".. count .. " entities.", player.character)
100+
return
101+
end
102+
end
103+
--Check to see if a off-shore pump was targetted.
104+
local ents = player.surface.find_entities_filtered{area=event.area, force=player.force, name="offshore-pump"}
105+
for k, v in pairs(ents) do
106+
if v.to_be_deconstructed(player.force) and antigrief.is_well_pump(v) then
107+
antigrief.alert(player.name .. " has marked a well-water pump for deconstruction", v)
108+
return
109+
end
110+
end
111+
end
112+
113+
--If new players equip an atomic bomb... Throw a warning!
114+
function antigrief.da_bomb(event)
115+
local player = game.players[event.player_index]
116+
if player.online_time > antigrief.TROLL_TIMER then
117+
return
118+
end
119+
if player.get_item_count("atomic-bomb") > 0 then
120+
if antigrief.check_cooldown(event.player_index, "atomic") then
121+
antigrief.alert(player.name .. " has equipped an Atomic Bomb.", player.character)
122+
end
123+
end
124+
end
125+
126+
--If new players equip an artillery remote... Throw a warning!
127+
function antigrief.remote(event)
128+
local player = game.players[event.player_index]
129+
if player.online_time > antigrief.TROLL_TIMER then
130+
return
131+
end
132+
if player.cursor_stack.valid_for_read and player.cursor_stack.name == "artillery-targeting-remote" then
133+
if antigrief.check_cooldown(event.player_index, "artillery") then
134+
antigrief.alert(player.name .. " has equipped an artillery remote.", player.character)
135+
end
136+
end
137+
end
138+
139+
--Look for players hoarding high value items.
140+
function antigrief.hoarder(event)
141+
local player = game.players[event.player_index]
142+
if player.online_time > antigrief.TROLL_TIMER then
143+
return
144+
end
145+
if ( player.get_item_count("speed-module-3") > 10 or
146+
player.get_item_count("productivity-module-3") > 10 or
147+
player.get_item_count("effectivity-module-3") > 10 ) and
148+
antigrief.check_cooldown(event.player_index, "hoarding") then
149+
antigrief.alert(player.name .. " is hoarding T3 modules.", player.character)
150+
end
151+
if player.get_item_count("uranium-235") > 30 and antigrief.check_cooldown(event.player_index, "hoarding") then
152+
antigrief.alert(player.name .. " is hoarding ".. player.get_item_count("uranium-235") .. " U-235.", player.character)
153+
end
154+
if player.get_item_count("power-armor-mk2") >= 2 and antigrief.check_cooldown(event.player_index, "hoarding") then
155+
antigrief.alert(player.name.. " is hoarding power armor mk2s.", player.character)
156+
end
157+
end
158+
159+
--Did someone craft/request Mk2 power armor and then log out?
160+
function antigrief.armor_drop(event)
161+
local player = game.players[event.player_index]
162+
if player.online_time > antigrief.TROLL_TIMER then
163+
return
164+
end
165+
if player.get_item_count("power-armor-mk2") >= 1 then
166+
local armor = player.get_inventory(defines.inventory.player_armor).find_item_stack("power-armor-mk2") or
167+
player.get_inventory(defines.inventory.player_main).find_item_stack("power-armor-mk2") or
168+
player.get_inventory(defines.inventory.player_quickbar).find_item_stack("power-armor-mk2") or
169+
player.get_inventory(defines.inventory.player_trash).find_item_stack("power-armor-mk2")
170+
171+
if armor then
172+
local item = player.surface.spill_item_stack(player.position, armor) --This could be used to duplicate equipment if we remove the wrong PA2. But such a weird edge case...
173+
player.remove_item("power-armor-mk2")
174+
if item and item.valid then --It may have dropped on a belt
175+
item.order_deconstruction(player.force)
176+
end
177+
else --Something went wrong. We should have found the armor. God inventory?
178+
log("Antigrief: Power Armor mk2 detected but not found")
179+
end
180+
end
181+
end
182+
183+
--Look for players merging roboport networks
184+
function antigrief.check_size_loginet_size(event)
185+
if not (event.entity and event.entity.valid and event.entity.type == "roboport") then
186+
return
187+
end
188+
if not (event.entity.last_user) then
189+
--How did we get here?
190+
return
191+
end
192+
local network = event.entity.logistic_network
193+
local cells = network.cells
194+
if not (cells[1] and cells[1].valid) then
195+
return
196+
end
197+
local minx, miny, maxx, maxy = cells[1].owner.position.x, cells[1].owner.position.y, cells[1].owner.position.x, cells[1].owner.position.y
198+
for k, v in pairs(cells) do
199+
if v.owner.position.x < minx then
200+
minx = v.owner.position.x
201+
elseif v.owner.position.x > maxx then
202+
maxx = v.owner.position.x
203+
end
204+
if v.owner.position.y < miny then
205+
miny = v.owner.position.y
206+
elseif v.owner.position.y > maxy then
207+
maxy = v.owner.position.y
208+
end
209+
end
210+
211+
if math.abs(maxx-minx) > 2000 or math.abs(maxy-miny) then
212+
antigrief.alert(event.entity.last_user.name .. "has placed a roboport in a large network.", event.entity)
213+
end
214+
end
215+
216+
--Print text to online admins and write to the log.
217+
function antigrief.alert(text, cause)
218+
for n, p in pairs(game.players) do
219+
if p.admin then
220+
p.print(text)
221+
if cause then
222+
p.add_custom_alert(cause, {type="virtual", name="signal-A"}, text, true)
223+
end
224+
end
225+
end
226+
log("Antigrief: " .. text)
227+
end
228+
229+
--Check if a message has been generated about this player recently. If true, set cooldown.
230+
function antigrief.check_cooldown(player_index, type)
231+
if not global.antigrief_cooldown[player_index] then
232+
global.antigrief_cooldown[player_index] = {}
233+
end
234+
local cooldowns = global.antigrief_cooldown[player_index]
235+
--Type matches? Check CD
236+
if not cooldowns[type] then cooldowns[type] = -antigrief.SPAM_TIMER end
237+
local tick = cooldowns[type]
238+
if tick < game.tick then
239+
cooldowns[type] = game.tick + antigrief.SPAM_TIMER
240+
global.antigrief_cooldown[player_index] = cooldowns
241+
return true
242+
end
243+
return false
244+
end
245+
246+
--Is this a water-well pump?
247+
function antigrief.is_well_pump(entity)
248+
if entity.name ~= "offshore-pump" then
249+
return false
250+
end
251+
if not (entity.surface.get_tile(entity.position.x+1, entity.position.y).collides_with("water-tile") or
252+
entity.surface.get_tile(entity.position.x, entity.position.y+1).collides_with("water-tile") or
253+
entity.surface.get_tile(entity.position.x-1, entity.position.y).collides_with("water-tile") or
254+
entity.surface.get_tile(entity.position.x, entity.position.y-1).collides_with("water-tile")) then
255+
256+
return true
257+
end
258+
end
259+
260+
function antigrief.wanton_destruction(event)
261+
if not (event.entity and event.entity.valid) then
262+
return
263+
end
264+
if not (event.cause and event.cause.type == "player") then
265+
return
266+
end
267+
if event.cause.force == event.entity.force then
268+
--Friendly fire detected!
269+
if antigrief.is_well_pump(event.entity) then
270+
antigrief.alert(event.cause.player.name .. " destroyed a well-water pump", event.entity)
271+
return
272+
end
273+
if event.entity.type == "player" and event.entity.player then
274+
antigrief.alert(event.cause.player.name .. " killed " .. event.entity.player.name, event.entity)
275+
return
276+
end
277+
if antigrief.check_cooldown(event.cause.player.index, "destruction") then
278+
antigrief.alert(event.cause.player.name .. " is destroying friendly entites.", event.entity)
279+
end
280+
end
281+
end
282+
283+
Event.register(defines.events.on_player_used_capsule, antigrief.arty_remote_ban)
284+
Event.register(defines.events.on_player_ammo_inventory_changed, antigrief.da_bomb)
285+
Event.register(defines.events.on_player_cursor_stack_changed, antigrief.remote)
286+
Event.register(defines.events.on_player_main_inventory_changed, antigrief.hoarder)
287+
Event.register(defines.events.on_player_left_game, antigrief.armor_drop)
288+
Event.register(defines.events.on_player_mined_entity, antigrief.pump)
289+
Event.register(defines.events.on_player_mined_entity, antigrief.ghosting)
290+
Event.register(defines.events.on_entity_died, antigrief.wanton_destruction)
291+
Event.register(defines.events.on_built_entity, antigrief.check_size_loginet_size)
292+
Event.register(defines.events.on_robot_built_entity, antigrief.check_size_loginet_size)
293+
Event.register(defines.events.on_player_deconstructed_area, antigrief.decon)

0 commit comments

Comments
 (0)