forked from squidy5/cargo_ships
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathcontrol.lua
More file actions
633 lines (565 loc) · 24.5 KB
/
control.lua
File metadata and controls
633 lines (565 loc) · 24.5 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
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
require("util")
require("__cargo-ships__/logic/ship_api")
require("__cargo-ships__/logic/ship_placement")
require("__cargo-ships__/logic/rail_placement")
require("__cargo-ships__/logic/long_reach")
require("__cargo-ships__/logic/bridge_logic")
require("__cargo-ships__/logic/pump_placement")
require("__cargo-ships__/logic/blueprint_logic")
require("__cargo-ships__/logic/ship_enter")
require("__cargo-ships__/logic/oil_rig_logic")
require("__cargo-ships__/logic/mapgen")
--require("__cargo-ships__/logic/crane_logic")
is_waterway = util.list_to_map{
"waterway",
"straight-waterway",
"half-diagonal-waterway",
"curved-waterway-a",
"curved-waterway-b",
"legacy-straight-waterway",
"legacy-curved-waterway"
}
is_rail = util.list_to_map{
"rail",
"straight-rail",
"half-diagonal-rail",
"curved-rail-a",
"curved-rail-b",
"legacy-straight-rail",
"legacy-curved-rail",
"rail-ramp",
}
-- spawn additional invisible entities
local function OnEntityBuilt(event)
local entity = event.entity or event.destination
local surface = entity.surface
local quality = entity.quality
local force = entity.force
local player = (event.player_index and game.players[event.player_index]) or nil
--log("Event happened:"..serpent.block(event))
-- check ghost entities first
if entity.name == "entity-ghost" then
if is_waterway[entity.ghost_name] then
-- Attempt to revive the waterway ghost
-- If this fails, then it is waiting for a tile to be deconstructed under it.
-- A robot will come later and revive it after the tiles are removed (no item required)
if not entity.silent_revive{raise_revive = true} then
-- Waterway could not be revived, add to list to revive later
-- look for colliding entities and tile deconstruction markers
local found_entities = entity.surface.find_entities_filtered{area=entity.bounding_box, to_be_deconstructed=true}
storage.waterway_ghosts = storage.waterway_ghosts or {}
for i,e in pairs(found_entities) do
script.register_on_object_destroyed(e)
local e_num = e.unit_number or 0
storage.waterway_ghosts[e_num] = storage.waterway_ghosts[e_num] or {}
table.insert(storage.waterway_ghosts[e_num], entity)
end
end
elseif entity.ghost_name == "bridge_gate" then
-- Replace with proper bridge_base ghost
HandleBridgeGhost(entity)
elseif entity.ghost_name == "or_tank" or entity.ghost_name == "or_pole" then
-- Delete oil rig parts if placed without an oil_rig
HandleOilRigPartGhost(entity)
end
elseif storage.boat_bodies[entity.name] then
CheckBoatPlacement(entity, player)
elseif (entity.type == "cargo-wagon" or entity.type == "fluid-wagon" or
entity.type == "locomotive" or entity.type == "artillery-wagon") then
local engine = nil
if storage.ship_bodies[entity.name] then
local ship_data = storage.ship_bodies[entity.name]
if ship_data.engine then
local engine_loc = localizeEngine(entity)
--game.print("looking for engine ghost at "..util.positiontostr(engine_loc.pos).." pointing "..tostring(engine_loc.dir))
-- see if there is an engine ghost from a blueprint behind us
local ghost = surface.find_entities_filtered{ghost_name=ship_data.engine, position=engine_loc.pos, force=force, limit=1}[1]
if ghost then
--game.print("found ghost at "..util.positiontostr(ghost.position).." pointing "..tostring(ghost.orientation)..", reviving")
local dummy
dummy, engine = ghost.revive()
-- If couldn't revive engine, destroy ghost
if not engine then
--game.print("couldn't revive ghost at "..util.positiontostr(newghost.position))
ghost.destroy()
end
end
if not engine then
--game.print("Creating "..ship_data.engine.." for "..entity.name)
engine = surface.create_entity{
name = ship_data.engine,
quality = quality,
position = engine_loc.pos,
direction = engine_loc.dir,
force = force
}
end
end
end
-- check placement in next tick after wagons connect
table.insert(storage.check_placement_queue, {entity=entity, engine=engine, player=player, robot=event.robot})
RegisterPlacementOnTick()
-- add oilrig component entities
elseif entity.name == "oil_rig" then
CreateOilRig(entity, player, event.robot)
-- create bridge
elseif entity.name == "bridge_base" then
CreateBridge(entity, player, event.robot)
-- make waterway not collide with boats by replacing it with entity that does not have "ground-tile" in its collision mask
elseif is_rail[entity.type] then
CheckRailPlacement(entity, player, event.robot)
--elseif entity.name == "crane" then
-- OnCraneCreated(entity)
end
end
local function OnMarkedForDeconstruction(event)
local entity = event.entity
if is_waterway[entity.name] then
-- Instantly deconstruct waterways
entity.destroy()
elseif storage.ship_bodies[entity.name] or storage.ship_engines[entity.name] then
-- If a ship or ship engine is marked for deconstruction, make sure its coupled pair is too
if entity.train then
local otherstock
-- Find attached engine or body
otherstock = entity.get_connected_rolling_stock(defines.rail_direction.front) or
entity.get_connected_rolling_stock(defines.rail_direction.back)
if otherstock and not otherstock.to_be_deconstructed() then
-- Copy deconstruction order
local player = game.players[event.player_index]
local force = (player and player.force) or entity.force
otherstock.order_deconstruction(force, player)
end
end
end
end
local function OnCancelledDeconstruction(event)
local entity = event.entity
if storage.ship_bodies[entity.name] or storage.ship_engines[entity.name] then
-- If a ship or ship engine is cancelled for deconstruction, make sure its coupled pair is too
if entity.train then
local otherstock
-- Find attached engine or body
otherstock = entity.get_connected_rolling_stock(defines.rail_direction.front) or
entity.get_connected_rolling_stock(defines.rail_direction.back)
if otherstock and otherstock.to_be_deconstructed() then
-- Copy deconstruction order
local player = event.player_index and game.players[event.player_index]
local force = (player and player.force) or entity.force
otherstock.cancel_deconstruction(force, player)
end
end
end
end
local function OnGiveWaterway(event)
local player = game.get_player(event.player_index)
local cleared = player.clear_cursor()
if cleared then
player.cursor_ghost = {name="waterway"}
end
end
-- delete invisible entities if master entity is destroyed
local function OnEntityDeleted(event)
local entity = event.entity
if(entity and entity.valid) then
if storage.ship_bodies[entity.name] then
if entity.train then
if entity.train.back_stock then
if storage.ship_engines[entity.train.back_stock.name] then
entity.train.back_stock.destroy()
end
end
if entity.train.front_stock then
if storage.ship_engines[entity.train.front_stock.name] then
entity.train.front_stock.destroy()
end
end
end
elseif storage.ship_engines[entity.name] then
if entity.train then
if entity.train.front_stock then
if storage.ship_bodies[entity.train.front_stock.name] then
entity.train.front_stock.destroy()
end
end
if entity.train.back_stock then
if storage.ship_bodies[entity.train.back_stock.name] then
entity.train.back_stock.destroy()
end
end
end
elseif entity.name == "entity-ghost" then
if entity.ghost_name == "oil_rig" then
-- Delete any or_tank or or_pole ghosts in the area
DestroyOilRigGhost(entity)
elseif storage.ship_bodies[entity.ghost_name] then
-- Delete any ship engine ghost in the area
DestroyShipGhost(entity)
end
end
end
end
-- Perform the destroyed action for this unit_number
-- Each method checks if it applies
function OnObjectDestroyed(event)
-- on_object_destroyed can fire for non-entity targets
-- Without this check, useful_id may collide with an oil rig unit_number and trigger unintended destruction
if event.type ~= defines.target_type.entity then return end
local unit_number = event.useful_id
-- Check if this entity makes space for a waterway ghost
if storage.waterway_ghosts and storage.waterway_ghosts[unit_number] then
-- try to revive all the waterways referenced in this list
local keep_list = {}
for _,wg in pairs(storage.waterway_ghosts[unit_number]) do
if wg.valid then
-- Try to revive this waterway ghost. If it fails, that's fine, we'll try again when a different colliding entity is destroyed.
if not wg.silent_revive{raise_revive = true} then
if unit_number == 0 then
table.insert(keep_list, wg)
end
end
end
end
if unit_number == 0 then
-- tile proxies all have unit_number 0, keep any non-revived ghosts in that list, since we have to keep coming back to it
storage.waterway_ghosts[unit_number] = keep_list
else
-- delete list for entity that doesn't exist anymore, regardless of what we did about it
storage.waterway_ghosts[unit_number] = nil
end
end
-- Oil Rigs
if DestroyOilRig(unit_number) then return end
-- Bridges
if HandleBridgeDestroyed(unit_number) then return end
end
-- Robots can try to mine it, but get sent away with something else if there is still cargo
local function OnRobotPreMined(event)
if(event.entity and event.entity.valid) then
local entity = event.entity
if storage.ship_bodies[entity.name] or storage.ship_engines[entity.name] then
-- Find attached engine or body
local otherstock = entity.get_connected_rolling_stock(defines.rail_direction.front) or
entity.get_connected_rolling_stock(defines.rail_direction.back)
if otherstock then
local save_inventory
-- Get the correct inventory from the attached engine or body
-- Ignore engines with recover_fuel=false because they don't have fuel items to recover
if storage.ship_engines[otherstock.name] and storage.ship_engines[otherstock.name].recover_fuel then
save_inventory = otherstock.get_fuel_inventory()
-- If not an engine, then it must be a body because we already checked it's one or the other
elseif otherstock.type == "cargo-wagon" then
save_inventory = otherstock.get_inventory(defines.inventory.cargo_wagon)
elseif otherstock.type == "artillery-wagon" then
save_inventory = otherstock.get_inventory(defines.inventory.artillery_wagon_ammo)
end
if save_inventory and not save_inventory.is_empty() then
-- Give contents of inventory to robot
local robotInventory = event.robot.get_inventory(defines.inventory.robot_cargo)
local robotSize = 1 + event.robot.force.worker_robots_storage_bonus
if robotInventory.is_empty() then
-- Find something to give to the robot. Otherwise the robot remains empty when the event returns, and it will finish mining the entity
for index=1, #save_inventory do
local stack = save_inventory[index]
if stack.valid_for_read then
--game.print("Giving robot cargo stack: "..stack.name.." : "..stack.count)
local inserted = robotInventory.insert{name=stack.name, quality=stack.quality, count=math.min(stack.count, robotSize)}
save_inventory.remove{name=stack.name, quality=stack.quality, count=inserted}
if not robotInventory.is_empty() then
break
end
end
end
end
end
end
end
end
end
-- Robot mining the actually ship/engine (after both are empty).
-- If one half of a ship is mined, also mine the other half into the same robot. Only one of them will be the actual item.
local function OnRobotMinedEntity(event)
if event.entity and event.entity.valid then
local entity = event.entity
if storage.ship_bodies[entity.name] or storage.ship_engines[entity.name] then
-- Find attached engine or body to mine
local otherstock = entity.get_connected_rolling_stock(defines.rail_direction.front) or
entity.get_connected_rolling_stock(defines.rail_direction.back)
if otherstock then
otherstock.mine{inventory=event.robot.get_inventory(defines.inventory.robot_cargo), force=true, raise_destroyed=false, ignore_minable=true}
end
end
end
end
-- When the player mines a ship or engine, also make the player mine the coupled entity
-- Unfortunately the API won't let us combine them into one undo action yet
local function OnPlayerMinedEntity(event)
local entity = event.entity
local player = game.players[event.player_index]
if entity and entity.valid then
storage.currently_mining = storage.currently_mining or {}
if not storage.currently_mining[entity.unit_number] then
if storage.ship_bodies[entity.name] or storage.ship_engines[entity.name] then
-- Find attached engine or body to mine
local otherstock = entity.get_connected_rolling_stock(defines.rail_direction.front) or
entity.get_connected_rolling_stock(defines.rail_direction.back)
if otherstock then
storage.currently_mining[otherstock.unit_number] = entity
otherstock.set_driver(nil) -- Eject player currently in the other stock so it can be mined along with the first one.
player.mine_entity(otherstock, true)
-- This mining operation completes before returning
-- Now merge the undo actions. Most recent is entity, second-most-recent is otherstock
local item1 = player.undo_redo_stack.get_undo_item(1)
if #item1 == 1 and item1[1].type == "removed-entity" and storage.ship_engines[item1[1].target.name] then
-- otherstock was an engine that we can safely remove from the undo stack
--game.print("Removing engine from undo stack")
player.undo_redo_stack.remove_undo_item(1)
end
end
end
else
-- This mining operation was started by script, don't start another one and clear the flag
storage.currently_mining[entity.unit_number] = nil
end
end
end
-- Check if this undo created a lone ship engine ghost, because that's not allowed
local function OnUndoApplied(event)
local actions = event.actions
local action = actions[1]
--game.print(serpent.block(action))
if #actions == 1 and action.type == "removed-entity" and storage.ship_engines[action.target.name] then
-- Find the ghost at the action coordinates
local surface = game.surfaces[action.surface_index]
local found = surface and surface.find_entities_filtered{ghost_name=action.target.name, position=action.target.position, limit=1}
if found and found[1] then
found[1].destroy()
--game.print("Destroyed engine ghost from undo action")
else
--game.print("Couldn't find ghost engine from undo action")
end
end
end
local function OnModSettingsChanged(event)
if event.setting == "waterway_reach_increase" then
storage.current_distance_bonus = settings.global["waterway_reach_increase"].value
applyReachChanges()
end
end
local function OnStackChanged(event)
increaseReach(event)
PumpVisualisation(event)
end
-- Register conditional events based on mod settting
function init_events()
-- entity created, check placement and create invisible elements
local entity_filters = {
{filter="ghost", ghost_name="bridge_gate"},
{filter="ghost", ghost_name="straight-waterway"},
{filter="ghost", ghost_name="half-diagonal-waterway"},
{filter="ghost", ghost_name="curved-waterway-a"},
{filter="ghost", ghost_name="curved-waterway-b"},
{filter="ghost", ghost_name="legacy-straight-waterway"},
{filter="ghost", ghost_name="legacy-curved-waterway"},
{filter="name", name="oil_rig"},
{filter="name", name="bridge_base"},
{filter="rolling-stock"},
{filter="rail"}
}
if storage.boat_bodies then
for name,_ in pairs(storage.boat_bodies) do
table.insert(entity_filters, {filter="name", name=name})
end
end
script.on_event(defines.events.on_built_entity, OnEntityBuilt, entity_filters)
script.on_event(defines.events.on_robot_built_entity, OnEntityBuilt, entity_filters)
script.on_event(defines.events.on_entity_cloned, OnEntityBuilt, entity_filters)
script.on_event(defines.events.script_raised_built, OnEntityBuilt, entity_filters)
script.on_event(defines.events.script_raised_revive, OnEntityBuilt, entity_filters)
-- delete invisible oil rig, bridge, and ship elements
local deleted_filters = {{filter="ghost_name", name="oil_rig"}}
if storage.ship_bodies then
for name,_ in pairs(storage.ship_bodies) do
table.insert(deleted_filters, {filter="name", name=name})
table.insert(deleted_filters, {filter="ghost_name", name=name})
end
end
if storage.ship_engines then
for name,_ in pairs(storage.ship_engines) do
table.insert(deleted_filters, {filter="name", name=name})
end
end
script.on_event(defines.events.on_entity_died, OnEntityDeleted, deleted_filters)
script.on_event(defines.events.script_raised_destroy, OnEntityDeleted, deleted_filters)
-- Handle Oil Rig and Bridge components
script.on_event(defines.events.on_object_destroyed, OnObjectDestroyed)
-- recover fuel from mined ships
local mined_filters = {}
if storage.ship_bodies then
for name,_ in pairs(storage.ship_bodies) do
table.insert(mined_filters, {filter="name", name=name})
end
end
if storage.ship_engines then
for name,_ in pairs(storage.ship_engines) do
table.insert(mined_filters, {filter="name", name=name})
end
end
script.on_event(defines.events.on_robot_pre_mined, OnRobotPreMined, mined_filters)
script.on_event(defines.events.on_player_mined_entity, OnPlayerMinedEntity, mined_filters)
script.on_event(defines.events.on_robot_mined_entity , OnRobotMinedEntity, mined_filters)
script.on_event(defines.events.on_undo_applied, OnUndoApplied)
script.on_event(defines.events.on_redo_applied, OnUndoApplied)
local deconstructed_filters = {
{filter="name", name="straight-waterway"},
{filter="name", name="half-diagonal-waterway"},
{filter="name", name="curved-waterway-a"},
{filter="name", name="curved-waterway-b"},
{filter="name", name="legacy-straight-waterway"},
{filter="name", name="legacy-curved-waterway"},
}
if storage.ship_bodies then
for name,_ in pairs(storage.ship_bodies) do
table.insert(deconstructed_filters, {filter="name", name=name})
end
end
if storage.ship_engines then
for name,_ in pairs(storage.ship_engines) do
table.insert(deconstructed_filters, {filter="name", name=name})
end
end
script.on_event(defines.events.on_marked_for_deconstruction, OnMarkedForDeconstruction, deconstructed_filters)
local cancel_decon_filters = {}
if storage.ship_bodies then
for name,_ in pairs(storage.ship_bodies) do
table.insert(cancel_decon_filters, {filter="name", name=name})
end
end
if storage.ship_engines then
for name,_ in pairs(storage.ship_engines) do
table.insert(cancel_decon_filters, {filter="name", name=name})
end
end
script.on_event(defines.events.on_cancelled_deconstruction, OnCancelledDeconstruction, cancel_decon_filters)
-- update ship placement
RegisterPlacementOnTick()
-- bridge queue
RegisterBridgeNthTick()
-- update visuals
RegisterVisualsNthTick()
-- long reach
script.on_event(defines.events.on_player_cursor_stack_changed, OnStackChanged)
script.on_event(defines.events.on_pre_player_died, deadReach)
-- pipette
script.on_event(defines.events.on_player_pipette, FixPipette)
-- bridge blueprint
script.on_event({defines.events.on_player_setup_blueprint,
defines.events.on_player_configured_blueprint}, HandleBridgeBlueprint)
-- rolling stock connect (this logic was too buggy to use)
script.on_event(defines.events.on_train_created, OnTrainCreated)
script.on_event(defines.events.on_runtime_mod_setting_changed, OnModSettingsChanged)
-- custom-input and shortcut button
script.on_event({defines.events.on_lua_shortcut, "give-waterway"},
function(event)
if event.prototype_name and event.prototype_name ~= "give-waterway" then return end
OnGiveWaterway(event)
end
)
-- Compatibility with AAI Vehicles (Modify this whenever the list of boats changes)
remote.remove_interface("aai-sci-burner")
remote.add_interface("aai-sci-burner", {
hauler_types = function(data)
local types={}
if storage.boat_bodies then
for name,_ in pairs(storage.boat_bodies) do
table.insert(types, name)
end
end
return types
end,
})
end
local function init()
-- Init storage variables
storage.check_placement_queue = storage.check_placement_queue or {}
storage.oil_rigs = storage.oil_rigs or {}
storage.bridges = storage.bridges or {}
storage.bridge_destroyed_queue = storage.bridge_destroyed_queue or {}
storage.ship_pump_selected = storage.ship_pump_selected or {}
storage.pump_markers = storage.pump_markers or {}
storage.disable_this_tick = storage.disable_this_tick or {}
storage.driving_state_locks = storage.driving_state_locks or {}
storage.currently_mining = storage.currently_mining or {}
init_ship_globals() -- Init database of ship parameters
-- Initialize or migrate long reach state
storage.last_cursor_stack_name =
((type(storage.last_cursor_stack_name) == "table") and storage.last_cursor_stack_name)
or {}
storage.last_distance_bonus =
((type(storage.last_distance_bonus) == "number") and storage.last_distance_bonus)
or settings.global["waterway_reach_increase"].value
storage.current_distance_bonus = settings.global["waterway_reach_increase"].value
-- Enable oil-processing tech on migration from v1.0.12
for _, oil_rig in pairs(storage.oil_rigs) do
if oil_rig.entity and oil_rig.entity.valid then
UnlockOilProcessing(oil_rig.entity.force)
end
end
-- Add Heating Reactors to Oil Rigs on Aquilo etc if necessary (in case a mod changed the heating flag or a surface condition)
MigrateOilRigReactors()
-- Enable offshore oil generation if it has been added to a save
oil_generation_migration()
-- Register conditional events
init_events()
end
---- Register Default Events ----
-- init
script.on_load(function()
init_events()
end)
script.on_init(function()
init()
end)
script.on_configuration_changed(function()
init()
end)
---@param train LuaTrain
function CopyLocoColor(train)
local locos = train.locomotives.front_movers
local loco = locos and locos[1]
if not (loco and loco.valid) or loco.name ~= "boat_engine" then
return
end
for _, wagon in pairs(train.cargo_wagons) do
wagon.color = loco.color
end
end
---@param event EventData.on_train_schedule_changed|EventData.on_train_changed_state
function CopyLocoColorEvent(event)
CopyLocoColor(event.train)
end
script.on_event(defines.events.on_train_schedule_changed, CopyLocoColorEvent)
script.on_event(defines.events.on_train_changed_state, CopyLocoColorEvent)
script.on_event(defines.events.on_gui_closed, function(event)
local entity = event.entity
if not (entity and entity.name == "boat_engine") then return end
local train = entity.train
if not train then return end
CopyLocoColor(train)
end)
-- Console commands
commands.add_command("cargo-ships-dump", "Dump storage to log", function() log(serpent.block(storage)) end)
------------------------------------------------------------------------------------
-- FIND LOCAL VARIABLES THAT ARE USED GLOBALLY --
-- (Thanks to eradicator!) --
------------------------------------------------------------------------------------
setmetatable(_ENV,{
__newindex=function (self,key,value) --locked_global_write
error('\n\n[ER Global Lock] Forbidden global *write*:\n'
.. serpent.line{key=key or '<nil>',value=value or '<nil>'}..'\n')
end,
--[[__index =function (self,key) --locked_global_read
error('\n\n[ER Global Lock] Forbidden global *read*:\n'
.. serpent.line{key=key or '<nil>'}..'\n')
end ,]]
})