-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcontrol.lua
More file actions
424 lines (381 loc) · 16.1 KB
/
Copy pathcontrol.lua
File metadata and controls
424 lines (381 loc) · 16.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
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
local RecipeChange = require "__RemoteConfiguration__/recipe-change"
local blacklist_groups = {
-- exotic industries related
-- maybe add interface to extend this?
["gate-user"] = true,
["drone-user"] = true
}
-- These entity types can be opened remotely anyway
local entity_type_blacklist = {
["train-stop"] = true,
["electric-pole"] = true,
["simple-entity-with-force"] = true, -- e.g. IR3 airship-station. They don't have a native GUI so we don't want to override any mod-added GUIs
}
local function increase_range(player)
if player.character and player.character_reach_distance_bonus < 200000 then
player.character_reach_distance_bonus = player.character_reach_distance_bonus + 200000
end
end
local ranges_reset_this_tick = {}
local function reset_range(player)
if not player.character then return end
while player.character_reach_distance_bonus >= 200000 do
player.character_reach_distance_bonus = player.character_reach_distance_bonus - 200000
ranges_reset_this_tick[player.index] = game.tick
end
end
local function reset_player(player)
-- dont reset the group if its currently a blacklist group
-- game.print("trying to reset player")
if player.permission_group and blacklist_groups[player.permission_group.name] then return end
player.permission_group = game.permissions.get_group("Default")
-- game.print("resetting player")
reset_range(player)
end
local function can_reach_entity(player, entity, ignore_map_only)
-- Check if player can reach entity disregarding whatever reach bonus we have given the player
if not player.character then return true end
if not ignore_map_only and not player.mod_settings["rc-interact-in-game"].value and player.render_mode == defines.render_mode.game and not (script.active_mods["SpidertronEnhancements"] and entity.type == "spider-vehicle") then return true end
local reach_distance_bonus = player.character_reach_distance_bonus
reset_range(player)
local can_reach = player.can_reach_entity(entity)
player.character_reach_distance_bonus = reach_distance_bonus
return can_reach
end
local function is_out_of_range_gui_open(player)
local opened = player.opened
if opened and player.opened_gui_type == defines.gui_type.entity and not can_reach_entity(player, opened) then
return true
end
return false
end
local wires = {["red-wire"] = true, ["green-wire"] = true, ["copper-cable"] = true}
local function is_holding_wire(player)
local cursor_stack = player.cursor_stack
if cursor_stack and cursor_stack.valid_for_read then
return wires[cursor_stack.name]
end
end
local function open_entity(player, entity, ignore_map_only)
if entity_type_blacklist[entity.type] then return end
reset_player(player) -- Ensures that can_reach_entity is accurate, not needed any more?
local out_of_reach = not can_reach_entity(player, entity, ignore_map_only)
local map_mode = player.render_mode == defines.render_mode.chart_zoomed_in or player.render_mode == defines.render_mode.chart
if out_of_reach or map_mode then
if player.force.is_enemy(entity.force) then
if map_mode then
player.create_local_flying_text{text = {"cant-open-enemy-structures"}, create_at_cursor = true}
end
return
end
player.opened = nil -- Triggers on_gui_closed before we open the GUI we care about
if out_of_reach then
increase_range(player)
player.permission_group = game.permissions.get_group("Remote Configuration GUI opened")
end
player.opened = entity
if player.opened_gui_type == defines.gui_type.entity then
RecipeChange.on_remote_gui_opened(player)
if not map_mode then
player.create_local_flying_text{
text = {"remote-configuration.opened-gui-remotely"},
create_at_cursor = true,
}
player.play_sound{ path = "rc-warning-sound" }
end
else
-- Opening GUI failed
reset_player(player)
end
end
end
script.on_event("rc-open-gui",
function(event)
local player = game.get_player(event.player_index)
if not player.is_cursor_empty() then return end
local selected = player.selected
if not selected then
-- Try from the map for trains (and other vehicles)
if player.render_mode == defines.render_mode.chart or player.render_mode == defines.render_mode.chart_zoomed_in then
-- Don't need to check chart_zoomed_in because spidertrons have radars, so would be selectable
local position = event.cursor_position
local vehicles = player.surface.find_entities_filtered{type = {"locomotive", "spider-vehicle"}, position = position, radius = 4.5, limit = 1}
if #vehicles > 0 then
selected = vehicles[1]
end
end
end
if selected then
open_entity(player, selected)
end
end
)
remote.add_interface("RemoteConfiguration",
{
open_entity = function(player, entity) open_entity(player, entity, true) end,
can_reach_entity = can_reach_entity,
reset_this_tick = function(player) if game.tick == ranges_reset_this_tick[player.index] then return true end end,
}
)
script.on_event(defines.events.on_gui_closed,
function(event)
local player = game.get_player(event.player_index)
RecipeChange.on_gui_closed(player)
if is_holding_wire(player) then return end
reset_player(player)
end
)
-- Allows wires to be fast-transfered or placed in chests when close, but not when far away
local function recalculate_wire_permissions(event)
local player = game.get_player(event.player_index)
if not is_holding_wire(player) then return end
local opened = player.opened
if player.selected and can_reach_entity(player, player.selected) then
reset_player(player)
elseif player.opened_self or (opened and player.opened_gui_type == defines.gui_type.entity and can_reach_entity(player, opened)) then
reset_player(player)
else
increase_range(player)
player.permission_group = game.permissions.get_group("Remote Configuration GUI opened")
end
end
script.on_event(defines.events.on_player_changed_position, recalculate_wire_permissions)
script.on_event(defines.events.on_selected_entity_changed, recalculate_wire_permissions)
script.on_event(defines.events.on_gui_opened, recalculate_wire_permissions)
script.on_event(defines.events.on_player_cursor_stack_changed,
function(event)
local player = game.get_player(event.player_index)
if is_holding_wire(player) then
recalculate_wire_permissions(event)
else
if not is_out_of_range_gui_open(player) then
reset_player(player)
end
end
end
)
script.on_event("rc-paste-entity-settings",
function(event)
local player = game.get_player(event.player_index)
if not player.is_cursor_empty() then return end
local selected = player.selected
if not selected then return end
local in_reach = can_reach_entity(player, selected)
if in_reach then return end -- Let vanilla handle this
local entity_copy_source = player.entity_copy_source
if not entity_copy_source then return end
if player.force.is_enemy(selected.force) then
player.create_local_flying_text{text = {"cant-paste-enemy-structure-settings"}, create_at_cursor = true}
return
end
removed_items = selected.copy_settings(entity_copy_source, player)
local surface = selected.surface
local position = selected.position
local force = player.force
for name, count in pairs(removed_items) do
surface.spill_item_stack(
position,
{name = name, count = count},
true, -- enabled_looted
force, -- force for deconstruction
false -- allow_on_belts
)
end
end
)
function is_cheating(player)
if
player.cheat_mode
and not (player.controller_type == defines.controllers.god and script.active_mods["space-exploration"])
then
return true
end
return player.controller_type == defines.controllers.editor
end
function set_cursor(player, item)
local inventory = player.get_main_inventory()
if not inventory then
return false
end
local cursor_stack = player.cursor_stack
if not cursor_stack or not player.clear_cursor() then
return false
end
local inventory_stack, stack_index = inventory.find_item_stack(item)
if not inventory_stack or not stack_index then
local stack_size = game.item_prototypes[item].stack_size
if is_cheating(player) and inventory.can_insert({ name = item, count = stack_size }) then
inventory.insert({ name = item, count = stack_size })
inventory_stack, stack_index = inventory.find_item_stack(item)
else
player.cursor_ghost = item
return true
end
end
--- @cast inventory_stack LuaItemStack
--- @cast stack_index uint
if not cursor_stack.transfer_stack(inventory_stack) then
return false
end
local inventory_def
if player.controller_type == defines.controllers.character then
inventory_def = defines.inventory.character_main
elseif player.controller_type == defines.controllers.editor then
inventory_def = defines.inventory.editor_main
elseif player.controller_type == defines.controllers.god then
inventory_def = defines.inventory.god_main
end
player.hand_location = { inventory = inventory_def, slot = stack_index }
return true
end
local function remote_build(event)
local player = game.get_player(event.player_index)
if not player.mod_settings["rc-ghost-build-in-map"].value then return end
if player.render_mode == defines.render_mode.game then
-- Try and put the real item back in the cursor
local cursor_ghost = player.cursor_ghost
if not cursor_ghost then return end
local main_inventory = player.get_main_inventory()
if not main_inventory then
return
end
local count = main_inventory.get_item_count(cursor_ghost.name)
if count == 0 then
return
end
set_cursor(player, cursor_ghost.name)
else
local cursor_stack = player.cursor_stack
if not (cursor_stack and cursor_stack.valid_for_read) then return end
if not cursor_stack.prototype.place_result then return end
local cursor_stack_name = cursor_stack.name
if player.clear_cursor() then
player.cursor_ghost = cursor_stack_name
end
end
end
script.on_event("rc-build", remote_build)
local direction_modifiers = {
["straight-rail"] = 0, -- 0 means ignore
["curved-rail"] = 0,
["rail-signal"] = 0,
["rail-chain-signal"] = 0,
["generator"] = 0,
["burner-generator"] = 0,
["assembling-machine"] = -1, -- -1 means rotate immediately
["splitter"] = 4,
["underground-belt"] = 4,
["pipe-to-ground"] = 4,
["pump"] = 4,
}
local function remote_rotate(event, direction)
local player = game.get_player(event.player_index)
if not player.is_cursor_empty() then return end
local selected = player.selected
if not selected then return end
if can_reach_entity(player, selected) then return end -- Let vanilla handle this
if not selected.supports_direction then return end
if player.force.is_enemy(selected.force) then
return
end
local current_direction = selected.get_upgrade_direction()
if not current_direction then current_direction = selected.direction end
local direction_modifier = direction_modifiers[selected.type] or 2
if direction_modifier == 0 then return end
if direction_modifier == -1 then
local next_direction = (current_direction + 2 * direction) % 8
selected.direction = next_direction
else
local next_direction = (current_direction + direction * direction_modifier) % 8
if next_direction == selected.direction and selected.get_upgrade_target() and selected.get_upgrade_target().name == selected.name then
selected.cancel_upgrade(player.force, player)
else
selected.order_upgrade{force = player.force, target = selected, player = player, direction = next_direction}
end
end
end
script.on_event("rc-rotate", function(event) remote_rotate(event, 1) end)
script.on_event("rc-reverse-rotate", function(event) remote_rotate(event, -1) end)
local function remote_deconstruct(event)
local player = game.get_player(event.player_index)
local selected = player.selected
if not selected then return end
if player.render_mode == defines.render_mode.game and can_reach_entity(player, selected) then return end -- Let vanilla handle this
if not player.is_cursor_empty() and not (player.cursor_stack and player.cursor_stack.valid_for_read) then return end -- Player has something from blueprint library in hand
if player.cursor_stack and player.cursor_stack.valid_for_read and (player.cursor_stack.is_selection_tool or player.cursor_stack.is_blueprint or player.cursor_stack.is_blueprint_book or player.cursor_stack.is_upgrade_item or player.cursor_stack.is_deconstruction_item) then return end
if player.force ~= selected.force then
player.create_local_flying_text{text = {"remote-configuration.cant-decon-unowned-structure"}, create_at_cursor = true}
return
end
selected.order_deconstruction(player.force, player)
end
script.on_event("rc-deconstruct", remote_deconstruct)
local function remote_cancel_deconstruct(event)
local player = game.get_player(event.player_index)
local selected = player.selected
if not selected then return end
if not player.is_cursor_empty() and not (player.cursor_stack and player.cursor_stack.valid_for_read) then return end -- Player has something from blueprint library in hand
if player.cursor_stack and player.cursor_stack.valid_for_read and (player.cursor_stack.is_selection_tool or player.cursor_stack.is_blueprint or player.cursor_stack.is_blueprint_book or player.cursor_stack.is_upgrade_item or player.cursor_stack.is_deconstruction_item) then return end
if player.force ~= selected.force then
player.create_local_flying_text{text = {"remote-configuration.cant-cancel-decon-unowned-structure"}, create_at_cursor = true}
return
end
selected.cancel_deconstruction(player.force, player)
end
script.on_event("rc-cancel-deconstruct", remote_cancel_deconstruct)
local function create_permission_group(config_changed_data)
local permissions = game.permissions
if config_changed_data then
-- in on_configuration_changed
if config_changed_data.mod_changes and config_changed_data.mod_changes["RemoteConfiguration"] then
for _, player in pairs(game.players) do
reset_player(player)
player.opened = nil
end
end
if permissions.get_group("Remote Configuration GUI opened") then
permissions.get_group("Remote Configuration GUI opened").destroy()
end
end
if permissions.get_group("Remote Configuration GUI opened") then
return
end
local group = permissions.create_group("Remote Configuration GUI opened")
if not group then
log("Group not created!!!")
game.print("[Remote Configuration] Group not created, please report!")
return
end
group.set_allows_action(defines.input_action.begin_mining, false)
group.set_allows_action(defines.input_action.begin_mining_terrain, false)
group.set_allows_action(defines.input_action.build, false)
group.set_allows_action(defines.input_action.build_rail, false)
group.set_allows_action(defines.input_action.build_terrain, false)
group.set_allows_action(defines.input_action.cursor_split, false)
group.set_allows_action(defines.input_action.cursor_transfer, false)
group.set_allows_action(defines.input_action.fast_entity_split, false)
group.set_allows_action(defines.input_action.fast_entity_transfer, false)
group.set_allows_action(defines.input_action.inventory_split, false)
group.set_allows_action(defines.input_action.inventory_transfer, false)
group.set_allows_action(defines.input_action.place_equipment, false)
group.set_allows_action(defines.input_action.stack_split, false)
group.set_allows_action(defines.input_action.stack_transfer, false)
group.set_allows_action(defines.input_action.take_equipment, false)
group.set_allows_action(defines.input_action.paste_entity_settings, false)
end
script.on_init(create_permission_group)
script.on_configuration_changed(create_permission_group)
remote.add_interface("remote-configuration-informatron", {
informatron_menu = function(data)
return {}
end,
informatron_page_content = function(data)
-- data.page_name, data.player_index, data.element
if data.page_name == "remote-configuration-informatron" then
data.element.add{
type = "label",
caption = {"tips-and-tricks-item-description.rc-introduction"},
}
end
end
})