forked from Refactorio/RedMew
-
Notifications
You must be signed in to change notification settings - Fork 0
/
antigrief.lua
185 lines (158 loc) · 7.59 KB
/
antigrief.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
local Event = require "utils.event"
local Utils = require "utils.utils"
local Game = require 'utils.game'
global.original_last_users_by_ent_pos = {}
Event.on_init(function()
global.ag_surface=game.create_surface("antigrief",{autoplace_controls={coal={frequency="normal",richness="normal",size="none"},["copper-ore"]={frequency="normal",richness="normal",size="none"},["crude-oil"]={frequency="normal",richness="normal",size="none"},desert={frequency="normal",richness="normal",size="none"},dirt={frequency="normal",richness="normal",size="none"},["enemy-base"]={frequency="normal",richness="normal",size="none"},grass={frequency="normal",richness="normal",size="none"},["iron-ore"]={frequency="normal",richness="normal",size="none"},sand={frequency="normal",richness="normal",size="none"},stone={frequency="normal",richness="normal",size="none"},trees={frequency="normal",richness="normal",size="none"},["uranium-ore"]={frequency="normal",richness="normal",size="none"}},cliff_settings={cliff_elevation_0=1024,cliff_elevation_interval=10,name="cliff"},height=2000000,peaceful_mode=false,seed=3461559752,starting_area="very-low",starting_points={{x=0,y=0}},terrain_segmentation="normal",water="normal",width=2000000})
global.ag_surface.always_day = true
end)
local function is_mocked(entity)
return rawget(entity, 'mock')
end
local function place_entity_on_surface(entity, surface, replace, player)
local new_entity = nil
for _,e in ipairs(surface.find_entities_filtered{position = entity.position}) do
if replace or e.type == "entity-ghost" then
e.destroy()
end
end
local entities_to_be_replaced = surface.find_entities_filtered{position = entity.position}
if (replace or #entities_to_be_replaced == 0 or entities_to_be_replaced[1].type == entity.type) then
new_entity = surface.create_entity{name = entity.name, position = entity.position, force = entity.force, direction = entity.direction}
if new_entity then
if not is_mocked(entity) then
new_entity.copy_settings(entity)
end
if player then
new_entity.last_user = player
end
end
end
return new_entity
end
Event.add(defines.events.on_chunk_generated, function(event)
if event.surface.name == "antigrief" then
local tiles = {}
for x = event.area.left_top.x, event.area.right_bottom.x - 1 do
for y = event.area.left_top.y, event.area.right_bottom.y - 1 do
table.insert(tiles,{name="lab-dark-2", position = {x,y}})
end
end
event.surface.set_tiles(tiles)
end
end)
local function get_position_str(pos)
return string.format("%d|%d", pos.x, pos.y)
end
local function on_entity_changed(event)
local entity = event.entity or event.destination
local player = Game.get_player_by_index(event.player_index)
if player.admin or not entity.valid then return end --Freebees for admins
if entity.last_user ~= player and entity.force == player.force then --commented out to be able to debug
place_entity_on_surface(entity, global.ag_surface, true, event.player_index)
end
if entity.last_user then
global.original_last_users_by_ent_pos[get_position_str(entity.position)] = entity.last_user.index
end
end
Event.add(defines.events.on_robot_pre_mined, function(event)
--The bot isnt the culprit! The last user is! They marked it for deconstruction!
if event.entity.valid and event.entity.last_user then
event.player_index = event.entity.last_user.index
on_entity_changed(event)
end
end)
local function get_pre_rotate_direction(entity)
--Some entities have 8 rotation steps and some have 4. So a mathmatical reverse is not possible
entity.rotate{reverse=true}
local direction = entity.direction
entity.rotate()
return direction
end
Event.add(defines.events.on_player_rotated_entity, function(event)
local entity = event.entity
if not entity.valid then return end
local ag_entities = global.ag_surface.find_entities_filtered{position = entity.position}
--If a player has rotated twice we want to preserve the original state.
if #ag_entities == 0 or not ag_entities[1].last_user or ag_entities[1].last_user ~= entity.last_user then
--Mock entity us used because the api doesnt support pre_player_rotated entity.
--The mocked entity has the entity state before rotation
--We also dont know who rotated it and dont want the griefers name there so we set it to 1
local mock_entity = {name = entity.name, position = entity.position, mock = true,
last_user = Game.get_player_by_index(1), force = entity.force, direction = get_pre_rotate_direction(entity)}
event.entity = mock_entity
on_entity_changed(event)
end
end)
Event.add(defines.events.on_pre_entity_settings_pasted, on_entity_changed)
Event.add(defines.events.on_entity_died, function(event)
--is a player on the same force as the destroyed object
if event.entity and event.entity.valid and event.entity.force.name == "player" and event.cause and
event.cause.force == event.entity.force and event.cause.type == "player" then
local new_entity = place_entity_on_surface(event.entity, global.ag_surface, true, event.cause.player)
if new_entity and event.entity.type == "container" then
local items = event.entity.get_inventory(defines.inventory.chest).get_contents()
if items then
for item, n in pairs(items) do
new_entity.insert{name = item, count = n}
end
end
end
end
end)
Event.add(defines.events.on_player_mined_entity, on_entity_changed)
Event.add(defines.events.on_marked_for_deconstruction, function(event)
if event.entity.last_user then
global.original_last_users_by_ent_pos[get_position_str(event.entity.position)] = event.entity.last_user.index
end
end)
local Module = {}
Module.undo = function(player)
if type(player) == "nil" or type(player) == "string" then return --No support for strings!
elseif type(player) == "number" then player = Game.get_player_by_index(player) end
--Remove all items from all surfaces that player placed an entity on
for _,surface in pairs(game.surfaces) do
if surface ~= global.ag_surface then
for _,e in ipairs(surface.find_entities_filtered{force = player.force.name}) do
if e.last_user == player then
e.destroy()
end
end
end
end
for _,e in ipairs(global.ag_surface.find_entities_filtered{}) do
if e.last_user == player then
--Place removed entity IF no collision is detected
local last_user = global.original_last_users_by_ent_pos[get_position_str(e.position)]
local new_entity = place_entity_on_surface(e, game.surfaces.nauvis, false, last_user)
--Transfer items
if new_entity then
local player = Utils.ternary(new_entity.last_user, new_entity.last_user, game.player)
local event = {created_entity = new_entity, player_index = player.index, stack = {}}
script.raise_event(defines.events.on_built_entity, event)
if e.type == "container" then
local items = e.get_inventory(defines.inventory.chest).get_contents()
if items then
for item, n in pairs(items) do
new_entity.insert{name = item, count = n}
end
end
end
e.destroy() --destory entity only if a new entity was created
end
end
end
end
Module.antigrief_surface_tp = function()
if game.player then
if game.player.surface == global.ag_surface then
game.player.teleport(game.player.position, game.surfaces.nauvis)
else
game.player.teleport(game.player.position, global.ag_surface)
end
end
end
Module.count_removed_entities = function(player)
return #Utils.find_entities_by_last_user(player, global.ag_surface)
end
return Module