mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Move files to exp_legacy
This commit is contained in:
112
exp_legacy/module/config/_file_loader.lua
Normal file
112
exp_legacy/module/config/_file_loader.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
--- This contains a list of all files that will be loaded and the order they are loaded in;
|
||||
-- to stop a file from loading add "--" in front of it, remove the "--" to have the file be loaded;
|
||||
-- config files should be loaded after all modules are loaded;
|
||||
-- core files should be required by modules and not be present in this list;
|
||||
-- @config File-Loader
|
||||
return {
|
||||
--'example.file_not_loaded',
|
||||
'modules.factorio-control', -- base factorio free play scenario
|
||||
'expcore.player_data', -- must be loaded first to register event handlers
|
||||
|
||||
--- Game Commands
|
||||
'modules.commands.debug',
|
||||
'modules.commands.me',
|
||||
'modules.commands.kill',
|
||||
'modules.commands.admin-chat',
|
||||
'modules.commands.admin-markers',
|
||||
'modules.commands.teleport',
|
||||
'modules.commands.cheat-mode',
|
||||
'modules.commands.ratio',
|
||||
'modules.commands.interface',
|
||||
'modules.commands.help',
|
||||
'modules.commands.roles',
|
||||
'modules.commands.rainbow',
|
||||
'modules.commands.clear-inventory',
|
||||
'modules.commands.jail',
|
||||
'modules.commands.repair',
|
||||
'modules.commands.reports',
|
||||
'modules.commands.spawn',
|
||||
'modules.commands.warnings',
|
||||
'modules.commands.find',
|
||||
'modules.commands.home',
|
||||
'modules.commands.connect',
|
||||
'modules.commands.last-location',
|
||||
'modules.commands.protection',
|
||||
'modules.commands.spectate',
|
||||
'modules.commands.search',
|
||||
'modules.commands.bot-queue',
|
||||
'modules.commands.speed',
|
||||
'modules.commands.pollution',
|
||||
'modules.commands.train',
|
||||
'modules.commands.friendly-fire',
|
||||
'modules.commands.research',
|
||||
'modules.commands.vlayer',
|
||||
'modules.commands.enemy',
|
||||
'modules.commands.waterfill',
|
||||
'modules.commands.artillery',
|
||||
'modules.commands.surface-clearing',
|
||||
|
||||
--- Addons
|
||||
'modules.addons.chat-popups',
|
||||
'modules.addons.damage-popups',
|
||||
'modules.addons.death-logger',
|
||||
'modules.addons.advanced-start',
|
||||
'modules.addons.spawn-area',
|
||||
'modules.addons.compilatron',
|
||||
'modules.addons.scorched-earth',
|
||||
'modules.addons.pollution-grading',
|
||||
'modules.addons.station-auto-name',
|
||||
'modules.addons.discord-alerts',
|
||||
'modules.addons.chat-reply',
|
||||
'modules.addons.tree-decon',
|
||||
'modules.addons.afk-kick',
|
||||
'modules.addons.report-jail',
|
||||
'modules.addons.protection-jail',
|
||||
'modules.addons.deconlog',
|
||||
'modules.addons.nukeprotect',
|
||||
'modules.addons.inserter',
|
||||
'modules.addons.miner',
|
||||
'modules.addons.lawnmower',
|
||||
'modules.addons.logging',
|
||||
|
||||
-- Control
|
||||
'modules.control.vlayer',
|
||||
|
||||
--- Data
|
||||
'modules.data.statistics',
|
||||
'modules.data.player-colours',
|
||||
'modules.data.greetings',
|
||||
'modules.data.quickbar',
|
||||
'modules.data.alt-view',
|
||||
'modules.data.tag',
|
||||
-- 'modules.data.bonus',
|
||||
'modules.data.personal-logistic',
|
||||
'modules.data.language',
|
||||
|
||||
--- GUI
|
||||
'modules.gui.readme',
|
||||
'modules.gui.rocket-info',
|
||||
'modules.gui.science-info',
|
||||
'modules.gui.autofill',
|
||||
'modules.gui.warp-list',
|
||||
'modules.gui.task-list',
|
||||
'modules.gui.player-list',
|
||||
'modules.gui.server-ups',
|
||||
'modules.gui.bonus',
|
||||
'modules.gui.vlayer',
|
||||
'modules.gui.research',
|
||||
'modules.gui.module',
|
||||
'modules.gui.landfill',
|
||||
'modules.gui.production',
|
||||
'modules.gui.playerdata',
|
||||
'modules.gui.surveillance',
|
||||
'modules.graftorio.require', -- graftorio
|
||||
'modules.gui.toolbar', -- must be loaded last to register toolbar handlers
|
||||
|
||||
--- Config Files
|
||||
'config.expcore.command_auth_admin', -- commands tagged with admin_only are blocked for non admins
|
||||
'config.expcore.command_auth_roles', -- commands must be allowed via the role config
|
||||
'config.expcore.command_runtime_disable', -- allows commands to be enabled and disabled during runtime
|
||||
'config.expcore.permission_groups', -- loads some predefined permission groups
|
||||
'config.expcore.roles', -- loads some predefined roles
|
||||
}
|
||||
130
exp_legacy/module/config/advanced_start.lua
Normal file
130
exp_legacy/module/config/advanced_start.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
--- This file is used to setup the map starting settings and the items players will start with
|
||||
-- @config Advanced-Start
|
||||
|
||||
--- These are called factories because they return another function
|
||||
-- use these as a simple methods of adding new items
|
||||
-- they will do most of the work for you
|
||||
-- ['item-name'] = factory(params)
|
||||
-- luacheck:ignore 212/amount_made 212/items_made 212/player
|
||||
|
||||
-- Use these to adjust for ticks ie game.tick < 5*minutes
|
||||
-- luacheck:ignore 211/seconds 211/minutes 211/hours
|
||||
local seconds, minutes, hours = 60, 3600, 216000
|
||||
|
||||
--- Use to make a split point for the number of items given based on time
|
||||
-- ['stone-furnace']=cutoff_time(5*minutes, 4,0) -- before 5 minutes give four items after 5 minutes give none
|
||||
local function cutoff_time(time, before, after)
|
||||
return function(amount_made, items_made, player)
|
||||
if game.tick < time then
|
||||
return before
|
||||
else
|
||||
return after
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Use to make a split point for the number of items given based on amount made
|
||||
-- ['firearm-magazine']=cutoff_amount_made(100, 10, 0) -- give 10 items until 100 items have been made
|
||||
local function cutoff_amount_made(amount, before, after)
|
||||
return function(amount_made, items_made, player)
|
||||
if amount_made < amount then
|
||||
return before
|
||||
else
|
||||
return after
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Same as above but will not give any items if x amount has been made of another item, useful for tiers
|
||||
-- ['light-armor']=cutoff_amount_made_unless(5, 0,1,'heavy-armor',5) -- give light armor once 5 have been made unless 5 heavy armor has been made
|
||||
local function cutoff_amount_made_unless(amount, before, after, second_item, second_amount)
|
||||
return function(amount_made, items_made, player)
|
||||
if items_made(second_item) < second_amount then
|
||||
if amount_made < amount then
|
||||
return before
|
||||
else
|
||||
return after
|
||||
end
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Use for mass production items where you want the amount to change based on the amount already made
|
||||
-- ['iron-plate']=scale_amount_made(5*minutes, 10, 10) -- for first 5 minutes give 10 items then after apply a factor of 10
|
||||
local function scale_amount_made(amount, before, scalar)
|
||||
return function(amount_made, items_made, player)
|
||||
if amount_made < amount then
|
||||
return before
|
||||
else
|
||||
return (amount_made * scalar) / ((game.tick / minutes) ^ 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Common values
|
||||
game.tick is the amount of time the game has been on for
|
||||
amount_made is the amount of that item which has been made
|
||||
items_made('item-name') will return the amount of any item made
|
||||
player is the player who just spawned
|
||||
hours, minutes, seconds are the number of ticks in each unit of time
|
||||
]]
|
||||
|
||||
return {
|
||||
skip_intro=true, --- @setting skip_intro skips the intro given in the default factorio free play scenario
|
||||
skip_victory=true, --- @setting skip_victory will skip the victory screen when a rocket is launched
|
||||
disable_base_game_silo_script=true, --- @setting disable_base_game_silo_script will not load the silo script at all
|
||||
research_queue_from_start=true, --- @setting research_queue_from_start when true the research queue is useable from the start
|
||||
friendly_fire=false, --- @setting friendly_fire weather players will be able to attack each other on the same force
|
||||
enemy_expansion=false, --- @setting enemy_expansion a catch all for in case the map settings file fails to load
|
||||
chart_radius=10*32, --- @setting chart_radius the number of tiles that will be charted when the map starts
|
||||
items = { --- @setting items items and there condition for being given
|
||||
-- ['item-name'] = function(amount_made, production_stats, player) return <Number> end -- 0 means no items given
|
||||
-- Plates
|
||||
['iron-plate']=scale_amount_made(100, 10, 10),
|
||||
['copper-plate']=scale_amount_made(100, 0, 8),
|
||||
['steel-plate']=scale_amount_made(100, 0, 4),
|
||||
-- Secondary Items
|
||||
['electronic-circuit']=scale_amount_made(1000, 0, 6),
|
||||
['iron-gear-wheel']=scale_amount_made(1000, 0, 6),
|
||||
-- Starting Items
|
||||
['burner-mining-drill']=cutoff_time(10*minutes, 4, 0),
|
||||
['stone-furnace']=cutoff_time(10*minutes, 4, 0),
|
||||
-- Armor
|
||||
['light-armor']=cutoff_amount_made_unless(5, 0,1,'heavy-armor',5),
|
||||
['heavy-armor']=cutoff_amount_made(5, 0,1),
|
||||
-- Weapon
|
||||
['pistol']=cutoff_amount_made_unless(0, 1, 1,'submachine-gun',5),
|
||||
['submachine-gun']=cutoff_amount_made(5, 0, 1),
|
||||
-- Ammo
|
||||
['firearm-magazine']=cutoff_amount_made_unless(100, 10, 0,'piercing-rounds-magazine', 100),
|
||||
['piercing-rounds-magazine']=cutoff_amount_made(100, 0, 10),
|
||||
--[[
|
||||
['construction-robot']=scale_amount_made(1, 10, 1)
|
||||
]]
|
||||
},
|
||||
armor = {
|
||||
enable=false,
|
||||
main = 'modular-armor',
|
||||
item = {
|
||||
{
|
||||
equipment='solar-panel-equipment',
|
||||
count=16
|
||||
},
|
||||
{
|
||||
equipment='belt-immunity-equipment',
|
||||
count=1
|
||||
},
|
||||
{
|
||||
equipment='battery-equipment',
|
||||
count=2
|
||||
},
|
||||
{
|
||||
equipment='personal-roboport-equipment',
|
||||
count=1
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
9
exp_legacy/module/config/afk_kick.lua
Normal file
9
exp_legacy/module/config/afk_kick.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
return {
|
||||
admin_as_active = true, --- @setting admin_as_active When true admins will be treated as active regardless of afk time
|
||||
trust_as_active = true, --- @setting trust_as_active When true trusted players (by playtime) will be treated as active regardless of afk time
|
||||
active_role = 'Veteran', --- @setting active_role When not nil a player with this role will be treated as active regardless of afk time
|
||||
afk_time = 3600*10, --- @setting afk_time The time in ticks that must pass for a player to be considered afk
|
||||
kick_time = 3600*30, --- @setting kick_time The time in ticks that must pass without any active players for all players to be kicked
|
||||
trust_time = 3600*60*10, --- @setting trust_time The time in ticks that a player must be online for to count as trusted
|
||||
update_time = 3600*30, --- @setting update_time How often in ticks the script checks for active players
|
||||
}
|
||||
320
exp_legacy/module/config/bonus.lua
Normal file
320
exp_legacy/module/config/bonus.lua
Normal file
@@ -0,0 +1,320 @@
|
||||
--- Lists all bonuses which can be used, name followed by min max
|
||||
-- @config Bonuses
|
||||
|
||||
return {
|
||||
--[[
|
||||
TODO
|
||||
force bonus
|
||||
quick health regeneration
|
||||
|
||||
Base point is equal to the amount of standard value in each parameter.
|
||||
|
||||
CMMS CRS CCS CISB CHB CRDB PBR
|
||||
STD 30 90 32 20 16 12 60
|
||||
= 260
|
||||
|
||||
MAX 60 180 64 40 32 24 120
|
||||
= 480
|
||||
]]
|
||||
pts = {
|
||||
base = 260
|
||||
},
|
||||
gui_display_width = {
|
||||
half = 150,
|
||||
label = 70,
|
||||
slider = 180,
|
||||
count = 50
|
||||
},
|
||||
conversion = {
|
||||
['cmms'] = 'character_mining_speed_modifier',
|
||||
['crs'] = 'character_running_speed_modifier',
|
||||
['ccs'] = 'character_crafting_speed_modifier',
|
||||
['cisb'] = 'character_inventory_slots_bonus',
|
||||
['chb'] = 'character_health_bonus',
|
||||
['crdb'] = 'character_reach_distance_bonus',
|
||||
--[[
|
||||
['cpdb'] = 'character_item_pickup_distance_bonus'
|
||||
]]
|
||||
},
|
||||
player_special_bonus_rate = 300,
|
||||
player_special_bonus = {
|
||||
['personal_battery_recharge'] = {
|
||||
-- 1 MW
|
||||
value = 6,
|
||||
max = 12,
|
||||
scale = 1,
|
||||
cost_scale = 4,
|
||||
cost = 40,
|
||||
is_percentage = false
|
||||
}
|
||||
},
|
||||
player_bonus = {
|
||||
['character_mining_speed_modifier'] = {
|
||||
value = 3,
|
||||
max = 6,
|
||||
scale = 0.5,
|
||||
cost_scale = 1,
|
||||
cost = 10,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_running_speed_modifier'] = {
|
||||
value = 1.5,
|
||||
max = 3,
|
||||
scale = 0.25,
|
||||
cost_scale = 1,
|
||||
cost = 60,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_crafting_speed_modifier'] = {
|
||||
value = 8,
|
||||
max = 16,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 4,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_inventory_slots_bonus'] = {
|
||||
value = 100,
|
||||
max = 200,
|
||||
scale = 10,
|
||||
cost_scale = 10,
|
||||
cost = 2,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_health_bonus'] = {
|
||||
value = 200,
|
||||
max = 400,
|
||||
scale = 50,
|
||||
cost_scale = 50,
|
||||
cost = 4,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_reach_distance_bonus'] = {
|
||||
value = 12,
|
||||
max = 24,
|
||||
scale = 2,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false,
|
||||
combined_bonus = {
|
||||
'character_resource_reach_distance_bonus',
|
||||
'character_build_distance_bonus'
|
||||
}
|
||||
},
|
||||
--[[
|
||||
['character_item_pickup_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_loot_pickup_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_item_drop_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
}
|
||||
]]
|
||||
},
|
||||
force_bonus = {
|
||||
--[[
|
||||
['character_mining_speed_modifier'] = {
|
||||
value = 0,
|
||||
max = 6,
|
||||
scale = 0.5,
|
||||
cost_scale = 1,
|
||||
cost = 10,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_running_speed_modifier'] = {
|
||||
value = 0,
|
||||
max = 3,
|
||||
scale = 0.25,
|
||||
cost_scale = 1,
|
||||
cost = 40,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_crafting_speed_modifier'] = {
|
||||
value = 0,
|
||||
max = 16,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 4,
|
||||
is_percentage = true
|
||||
},
|
||||
['character_inventory_slots_bonus'] = {
|
||||
value = 0,
|
||||
max = 200,
|
||||
scale = 10,
|
||||
cost_scale = 100,
|
||||
cost = 2,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_health_bonus'] = {
|
||||
value = 0,
|
||||
max = 400,
|
||||
scale = 50,
|
||||
cost = 4,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_reach_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 24,
|
||||
scale = 2,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false,
|
||||
combined_bonus = {
|
||||
'character_resource_reach_distance_bonus',
|
||||
'character_build_distance_bonus'
|
||||
}
|
||||
},
|
||||
['worker_robots_speed_modifier'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
]]
|
||||
['worker_robots_battery_modifier'] = {
|
||||
value = 1,
|
||||
max = 1,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['worker_robots_storage_bonus'] = {
|
||||
value = 1,
|
||||
max = 1,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['following_robots_lifetime_modifier'] = {
|
||||
value = 1,
|
||||
max = 1,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
--[[
|
||||
['character_item_pickup_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_loot_pickup_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_item_drop_distance_bonus'] = {
|
||||
value = 0,
|
||||
max = 20,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['character_trash_slot_count'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['mining_drill_productivity_bonus'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['train_braking_force_bonus'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['laboratory_speed_modifier'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['laboratory_productivity_bonus'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['inserter_stack_size_bonus'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['stack_inserter_capacity_bonus'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
},
|
||||
['artillery_range_modifier'] = {
|
||||
value = 0,
|
||||
max = 0,
|
||||
scale = 0,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
}
|
||||
]]
|
||||
},
|
||||
surface_bonus = {
|
||||
--[[
|
||||
['solar_power_multiplier'] = {
|
||||
value = 1,
|
||||
max = 1000,
|
||||
scale = 1,
|
||||
cost_scale = 1,
|
||||
cost = 1,
|
||||
is_percentage = false
|
||||
}
|
||||
]]
|
||||
}
|
||||
}
|
||||
119
exp_legacy/module/config/chat_reply.lua
Normal file
119
exp_legacy/module/config/chat_reply.lua
Normal file
@@ -0,0 +1,119 @@
|
||||
--- This file defines the different triggers for the chat bot
|
||||
-- @config Chat-Reply
|
||||
|
||||
local Async = require 'expcore.async'
|
||||
local format_time = _C.format_time --- @dep expcore.common
|
||||
|
||||
-- eg Async(async_message, is_command or player, message)
|
||||
local async_message = Async.register(function(player, message)
|
||||
if player == true then game.print(message) else player.print(message) end
|
||||
end)
|
||||
|
||||
-- luacheck:ignore 212/player 212/is_command
|
||||
return {
|
||||
allow_command_prefix_for_messages = true, --- @setting allow_command_prefix_for_messages when true any message trigger will print to all player when prefixed
|
||||
messages = { --- @setting messages will trigger when ever the word is said
|
||||
['discord'] = {'info.discord'},
|
||||
['expgaming'] = {'info.website'},
|
||||
['website'] = {'info.website'},
|
||||
['status'] = {'info.status'},
|
||||
['github'] = {'info.github'},
|
||||
['patreon'] = {'info.patreon'},
|
||||
['donate'] = {'info.patreon'},
|
||||
['command'] = {'info.custom-commands'},
|
||||
['commands'] = {'info.custom-commands'},
|
||||
['softmod'] = {'info.softmod'},
|
||||
['script'] = {'info.softmod'},
|
||||
['loop'] = {'chat-bot.loops'},
|
||||
['rhd'] = {'info.lhd'},
|
||||
['lhd'] = {'info.lhd'},
|
||||
['roundabout'] = {'chat-bot.loops'},
|
||||
['roundabouts'] = {'chat-bot.loops'},
|
||||
['redmew'] = {'info.redmew'},
|
||||
['afk'] = function(player, _is_command)
|
||||
local max = player
|
||||
for _, next_player in pairs(game.connected_players) do
|
||||
if max.afk_time < next_player.afk_time then
|
||||
max = next_player
|
||||
end
|
||||
end
|
||||
return {'chat-bot.afk', max.name, format_time(max.afk_time, {minutes = true, seconds = true, long = true})}
|
||||
end,
|
||||
['players'] = function(_player, _is_command)
|
||||
return {'chat-bot.players', #game.players}
|
||||
end,
|
||||
['online'] = function(_player, _is_command)
|
||||
return {'chat-bot.players-online', #game.connected_players}
|
||||
end,
|
||||
['r!verify'] = function(player, _is_command)
|
||||
return {'chat-bot.verify', player.name}
|
||||
end,
|
||||
},
|
||||
command_admin_only = false, --- @setting command_admin_only when true will only allow chat commands for admins
|
||||
command_permission = 'command/chat-bot', --- @setting command_permission the permission used to allow command prefixes
|
||||
command_prefix = '!', --- @setting command_prefix prefix used for commands below and to print to all players (if enabled above)
|
||||
commands = { --- @setting commands will trigger only when command prefix is given
|
||||
['dev'] = {'chat-bot.not-real-dev'},
|
||||
['blame'] = function(player, _is_command)
|
||||
local names = {'Cooldude2606', 'arty714', 'badgamernl', 'mark9064', 'aldldl', 'Drahc_pro', player.name}
|
||||
for _, next_player in pairs(game.connected_players) do
|
||||
names[#names + 1] = next_player.name
|
||||
end
|
||||
return {'chat-bot.blame', table.get_random_dictionary_entry(names)}
|
||||
end,
|
||||
['magic'] = {'chat-bot.magic'},
|
||||
['aids'] = {'chat-bot.aids'},
|
||||
['riot'] = {'chat-bot.riot'},
|
||||
['lenny'] = {'chat-bot.lenny'},
|
||||
['hodor'] = function(_player, _is_command)
|
||||
local options = {'?', '.', '!', '!!!'}
|
||||
return {'chat-bot.hodor', table.get_random_dictionary_entry(options)}
|
||||
end,
|
||||
['evolution'] = function(_player, _is_command)
|
||||
return {'chat-bot.current-evolution', string.format('%.2f', game.forces['enemy'].evolution_factor)}
|
||||
end,
|
||||
['makepopcorn'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.get-popcorn-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.get-popcorn-2', player.name}})
|
||||
end,
|
||||
['passsomesnaps'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, player, {'chat-bot.reply', {'chat-bot.get-snaps-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.get-snaps-2', player.name}})
|
||||
Async.wait(timeout*(math.random()+0.5), async_message, true, {'chat-bot.reply', {'chat-bot.get-snaps-3', player.name}})
|
||||
end,
|
||||
['makecocktail'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.get-cocktail-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.get-cocktail-2', player.name}})
|
||||
Async.wait(timeout*(math.random()+0.5), async_message, true, {'chat-bot.reply', {'chat-bot.get-cocktail-3', player.name}})
|
||||
end,
|
||||
['makecoffee'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.make-coffee-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.make-coffee-2', player.name}})
|
||||
end,
|
||||
['orderpizza'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.order-pizza-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.order-pizza-2', player.name}})
|
||||
Async.wait(timeout*(math.random()+0.5), async_message, true, {'chat-bot.reply', {'chat-bot.order-pizza-3', player.name}})
|
||||
end,
|
||||
['maketea'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.make-tea-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.make-tea-2', player.name}})
|
||||
end,
|
||||
['meadplease'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.get-mead-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.get-mead-2', player.name}})
|
||||
end,
|
||||
['passabeer'] = function(player, _is_command)
|
||||
local timeout = math.floor(180*(math.random()+0.5))
|
||||
Async(async_message, true, {'chat-bot.reply', {'chat-bot.get-beer-1'}})
|
||||
Async.wait(timeout, async_message, true, {'chat-bot.reply', {'chat-bot.get-beer-2', player.name}})
|
||||
end
|
||||
}
|
||||
}
|
||||
23
exp_legacy/module/config/compilatron.lua
Normal file
23
exp_legacy/module/config/compilatron.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
--- Config file for the compliatrons including where they spawn and what messages they show
|
||||
-- @config Compilatron
|
||||
|
||||
return {
|
||||
message_cycle=60*15, --- @setting message_cycle 15 seconds default, how often (in ticks) the messages will cycle
|
||||
locations={ --- @setting locations defines the spawn locations for all compilatrons
|
||||
['Spawn']={x=0,y=0}
|
||||
},
|
||||
messages={ --- @setting messages the messages that each one will say, must be same name as its location
|
||||
['Spawn']={
|
||||
{'info.website'},
|
||||
{'info.read-readme'},
|
||||
{'info.discord'},
|
||||
{'info.softmod'},
|
||||
{'info.redmew'},
|
||||
{'info.custom-commands'},
|
||||
{'info.status'},
|
||||
{'info.lhd'},
|
||||
{'info.github'},
|
||||
{'info.patreon'},
|
||||
}
|
||||
}
|
||||
}
|
||||
16
exp_legacy/module/config/death_logger.lua
Normal file
16
exp_legacy/module/config/death_logger.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
--- This config controls what happens when a player dies mostly about map markers and item collection;
|
||||
-- allow_teleport_to_body_command and allow_collect_bodies_command can be over ridden if command_auth_runtime_disable is present;
|
||||
-- if not present then the commands will not be loaded into the game
|
||||
-- @config Death-Logger
|
||||
|
||||
return {
|
||||
--WIP_allow_teleport_to_body_command=false, -- allows use of /return-to-body which teleports you to your last death
|
||||
--WIP_allow_collect_bodies_command=false, -- allows use of /collect-body which returns all your items to you and removes the body
|
||||
use_chests_as_bodies=false, --- @setting use_chests_as_bodies weather items should be moved into a chest when a player dies
|
||||
auto_collect_bodies=true, --- @setting auto_collect_bodies enables items being returned to the spawn point in chests upon corpse expiring
|
||||
show_map_markers=true, --- @setting show_map_markers shows markers on the map where bodies are
|
||||
include_time_of_death=true, --- @setting include_time_of_death weather to include the time of death on the map marker
|
||||
map_icon=nil, --- @setting map_icon the icon that the map marker shows; nil means no icon; format as a SingleID
|
||||
show_light_at_corpse=true, --- @setting show_light_at_corpse if a light should be rendered at the corpse
|
||||
show_line_to_corpse=true --- @setting show_line_to_corpse if a line should be rendered from you to your corpse
|
||||
}
|
||||
11
exp_legacy/module/config/deconlog.lua
Normal file
11
exp_legacy/module/config/deconlog.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
--- This config controls whether actions such as deconning by players without sufficient permissions is logged or not
|
||||
-- @config Deconlog
|
||||
|
||||
return {
|
||||
decon_area = true, ---@setting decon_area whether to log when an area is being deconstructed
|
||||
built_entity = true, ---@setting built_entity whether to log when an entity is built
|
||||
mined_entity = true, ---@setting mined_entity whether to log when an entity is mined
|
||||
fired_rocket = true, ---@setting fired_nuke whether to log when a rocket is fired
|
||||
fired_explosive_rocket = true, ---@setting fired_nuke whether to log when a explosive rocket is fired
|
||||
fired_nuke = true, ---@setting fired_nuke whether to log when a nuke is fired
|
||||
}
|
||||
25
exp_legacy/module/config/discord_alerts.lua
Normal file
25
exp_legacy/module/config/discord_alerts.lua
Normal file
@@ -0,0 +1,25 @@
|
||||
--- Config file used to enable and disable different push messages for discord
|
||||
-- @config Discord-Alerts
|
||||
|
||||
return {
|
||||
show_playtime=true,
|
||||
entity_protection=true,
|
||||
player_reports=true,
|
||||
player_warnings=true,
|
||||
player_bans=true,
|
||||
player_mutes=true,
|
||||
player_kicks=true,
|
||||
player_promotes=false,
|
||||
player_jail=true,
|
||||
['config']=true,
|
||||
['purge']=true,
|
||||
['c']=true,
|
||||
['command']=true,
|
||||
['silent-command']=true,
|
||||
['measured-command']=true,
|
||||
['banlist']=true,
|
||||
['permissions']=true,
|
||||
['editor']=true,
|
||||
['cheat']=true,
|
||||
['open']=false
|
||||
}
|
||||
19
exp_legacy/module/config/expcore/command_auth_admin.lua
Normal file
19
exp_legacy/module/config/expcore/command_auth_admin.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
--- This is a very simple config file which adds a admin only auth function;
|
||||
-- not much to change here its more so it can be enabled and disabled from ./config/file_loader.lua;
|
||||
-- either way you can change the requirements to be "admin" if you wanted to
|
||||
-- @config Commands-Auth-Admin
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
|
||||
-- luacheck:ignore 212/command
|
||||
Commands.add_authenticator(function(player, command, tags, reject)
|
||||
if tags.admin_only then
|
||||
if player.admin then
|
||||
return true
|
||||
else
|
||||
return reject{'command-auth.admin-only'}
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end)
|
||||
14
exp_legacy/module/config/expcore/command_auth_roles.lua
Normal file
14
exp_legacy/module/config/expcore/command_auth_roles.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
--- This will make commands only work if the role has been allowed it in the role config
|
||||
-- @config Commands-Auth-Roles
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
|
||||
-- luacheck:ignore 212/tags
|
||||
Commands.add_authenticator(function(player, command, tags, reject)
|
||||
if Roles.player_allowed(player,'command/'..command) then
|
||||
return true
|
||||
else
|
||||
return reject()
|
||||
end
|
||||
end)
|
||||
15
exp_legacy/module/config/expcore/command_color_parse.lua
Normal file
15
exp_legacy/module/config/expcore/command_color_parse.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
--- This will make commands only work when a valid color from the presets has been selected
|
||||
-- @config Commands-Color-Parse
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
local Colours = require 'utils.color_presets' --- @dep utils.color_presets
|
||||
|
||||
Commands.add_parse('color',function(input, _, reject)
|
||||
if not input then return end
|
||||
local color = Colours[input]
|
||||
if not color then
|
||||
return reject{'expcore-commands.reject-color'}
|
||||
else
|
||||
return input
|
||||
end
|
||||
end)
|
||||
142
exp_legacy/module/config/expcore/command_general_parse.lua
Normal file
142
exp_legacy/module/config/expcore/command_general_parse.lua
Normal file
@@ -0,0 +1,142 @@
|
||||
--[[-- This file contains some common command param parse functions;
|
||||
this file is less of a config and more of a requirement but you may wish to change how some behave;
|
||||
as such you need to be confident with lua but you edit this config file;
|
||||
use Commands.add_parse('name',function(input, player, reject) end) to add a parse;
|
||||
see ./expcore/commands.lua for more details
|
||||
@config Commands-Parse
|
||||
@usage Adds Parses:
|
||||
boolean
|
||||
string-options - options: array
|
||||
string-max-length - max_length: number
|
||||
number
|
||||
integer
|
||||
number-range - range_min: number, range_max: number
|
||||
integer-range - range_min: number, range_max: number
|
||||
player
|
||||
player-online
|
||||
player-alive
|
||||
force
|
||||
surface
|
||||
]]
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
|
||||
-- luacheck:ignore 212/player
|
||||
Commands.add_parse('boolean',function(input, player)
|
||||
if not input then return end -- nil check
|
||||
input = input:lower()
|
||||
if input == 'yes'
|
||||
or input == 'y'
|
||||
or input == 'true'
|
||||
or input == '1' then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('string-options',function(input, player, reject, options)
|
||||
if not input then return end -- nil check
|
||||
local option = _C.auto_complete(options, input)
|
||||
return option or reject{'expcore-commands.reject-string-options', table.concat(options, ', ')}
|
||||
end)
|
||||
|
||||
Commands.add_parse('string-max-length',function(input, player, reject, max_length)
|
||||
if not input then return end -- nil check
|
||||
local length = input:len()
|
||||
if length > max_length then
|
||||
return reject{'expcore-commands.reject-string-max-length',max_length}
|
||||
else
|
||||
return input
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('number',function(input, player, reject)
|
||||
if not input then return end -- nil check
|
||||
local number = tonumber(input)
|
||||
if not number then
|
||||
return reject{'expcore-commands.reject-number'}
|
||||
else
|
||||
return number
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('integer',function(input, player, reject)
|
||||
if not input then return end -- nil check
|
||||
local number = tonumber(input)
|
||||
if not number then
|
||||
return reject{'expcore-commands.reject-number'}
|
||||
else
|
||||
return math.floor(number)
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('number-range',function(input, player, reject, range_min, range_max)
|
||||
local number = Commands.parse('number',input, player, reject)
|
||||
if not number then return end -- nil check
|
||||
if number < range_min or number > range_max then
|
||||
return reject{'expcore-commands.reject-number-range',range_min, range_max}
|
||||
else
|
||||
return number
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('integer-range',function(input, player, reject, range_min, range_max)
|
||||
local number = Commands.parse('integer',input, player, reject)
|
||||
if not number then return end -- nil check
|
||||
if number < range_min or number > range_max then
|
||||
return reject{'expcore-commands.reject-number-range',range_min, range_max}
|
||||
else
|
||||
return number
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('player',function(input, player, reject)
|
||||
if not input then return end -- nil check
|
||||
local input_player = game.players[input]
|
||||
if not input_player then
|
||||
return reject{'expcore-commands.reject-player',input}
|
||||
else
|
||||
return input_player
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('player-online',function(input, player, reject)
|
||||
local input_player = Commands.parse('player',input, player, reject)
|
||||
if not input_player then return end -- nil check
|
||||
if not input_player.connected then
|
||||
return reject{'expcore-commands.reject-player-online'}
|
||||
else
|
||||
return input_player
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('player-alive',function(input, player, reject)
|
||||
local input_player = Commands.parse('player-online',input, player, reject)
|
||||
if not input_player then return end -- nil check
|
||||
if not input_player.character or not input_player.character.health or input_player.character.health <= 0 then
|
||||
return reject{'expcore-commands.reject-player-alive'}
|
||||
else
|
||||
return input_player
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('force',function(input, player, reject)
|
||||
if not input then return end -- nil check
|
||||
local force = game.forces[input]
|
||||
if not force then
|
||||
return reject{'expcore-commands.reject-force'}
|
||||
else
|
||||
return force
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('surface',function(input, player, reject)
|
||||
if not input then return end
|
||||
local surface = game.surfaces[input]
|
||||
if not surface then
|
||||
return reject{'expcore-commands.reject-surface'}
|
||||
else
|
||||
return surface
|
||||
end
|
||||
end)
|
||||
54
exp_legacy/module/config/expcore/command_role_parse.lua
Normal file
54
exp_legacy/module/config/expcore/command_role_parse.lua
Normal file
@@ -0,0 +1,54 @@
|
||||
--[[-- Adds some parse functions that can be used with the role system
|
||||
@config Commands-Parse-Roles
|
||||
@usage Adds Parses:
|
||||
role
|
||||
player-role
|
||||
player-role-online
|
||||
player-role-alive
|
||||
]]
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local auto_complete = _C.auto_complete --- @dep expcore.common
|
||||
require 'config.expcore.command_general_parse'
|
||||
|
||||
-- luacheck:ignore 212/player
|
||||
Commands.add_parse('role',function(input, player, reject)
|
||||
if not input then return end
|
||||
local roles = Roles.config.order
|
||||
local rev_roles = {}
|
||||
for i=#roles, 1,-1 do
|
||||
table.insert(rev_roles, roles[i])
|
||||
end
|
||||
local role = auto_complete(rev_roles, input)
|
||||
role = Roles.get_role_by_name(role)
|
||||
if not role then
|
||||
return reject{'expcore-role.reject-role'}
|
||||
else
|
||||
return role
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('player-role',function(input, player, reject)
|
||||
local input_player = Commands.parse('player',input, player, reject)
|
||||
if not input_player then return end -- nil check
|
||||
local player_highest = Roles.get_player_highest_role(player)
|
||||
local input_player_highest = Roles.get_player_highest_role(input_player)
|
||||
if player_highest.index < input_player_highest.index then
|
||||
return input_player
|
||||
else
|
||||
return reject{'expcore-roles.reject-player-role'}
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('player-role-online',function(input, player, reject)
|
||||
local input_player = Commands.parse('player-role',input, player, reject)
|
||||
if not input_player then return end -- nil check
|
||||
return Commands.parse('player-online',input_player.name, player, reject)
|
||||
end)
|
||||
|
||||
Commands.add_parse('player-role-alive',function(input, player, reject)
|
||||
local input_player = Commands.parse('player-role',input, player, reject)
|
||||
if not input_player then return end -- nil check
|
||||
return Commands.parse('player-alive',input_player.name, player, reject)
|
||||
end)
|
||||
32
exp_legacy/module/config/expcore/command_runtime_disable.lua
Normal file
32
exp_legacy/module/config/expcore/command_runtime_disable.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
--- This config for command auth allows commands to be globally enabled and disabled during runtime;
|
||||
-- this config adds Commands.disable and Commands.enable to enable and disable commands for all users
|
||||
-- @config Commands-Auth-Runtime-Disable
|
||||
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
|
||||
local disabled_commands = {}
|
||||
Global.register(disabled_commands, function(tbl)
|
||||
disabled_commands = tbl
|
||||
end)
|
||||
|
||||
--- Stops a command from be used by any one
|
||||
-- @tparam string command_name the name of the command to disable
|
||||
function Commands.disable(command_name)
|
||||
disabled_commands[command_name] = true
|
||||
end
|
||||
|
||||
--- Allows a command to be used again after disable was used
|
||||
-- @tparam string command_name the name of the command to enable
|
||||
function Commands.enable(command_name)
|
||||
disabled_commands[command_name] = nil
|
||||
end
|
||||
|
||||
-- luacheck:ignore 212/player 212/tags
|
||||
Commands.add_authenticator(function(player, command, tags, reject)
|
||||
if disabled_commands[command] then
|
||||
return reject{'command-auth.command-disabled'}
|
||||
else
|
||||
return true
|
||||
end
|
||||
end)
|
||||
141
exp_legacy/module/config/expcore/permission_groups.lua
Normal file
141
exp_legacy/module/config/expcore/permission_groups.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
--- Use this file to add new permission groups to the game;
|
||||
-- start with Permission_Groups.new_group('name');
|
||||
-- then use either :allow_all() or :disallow_all() to set the default for non specified actions;
|
||||
-- then use :allow{} and :disallow{} to specify certain actions to allow/disallow
|
||||
-- @config Permission-Groups
|
||||
|
||||
--local Event = require 'utils.event' -- @dep utils.event
|
||||
local Permission_Groups = require 'expcore.permission_groups' --- @dep expcore.permission_groups
|
||||
|
||||
Permission_Groups.new_group('Admin')
|
||||
:allow_all()
|
||||
:disallow{
|
||||
'add_permission_group', -- admin
|
||||
'delete_permission_group',
|
||||
'edit_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor',
|
||||
'change_multiplayer_config',
|
||||
'set_heat_interface_mode',
|
||||
'set_heat_interface_temperature',
|
||||
'set_infinity_container_filter_item',
|
||||
'set_infinity_container_remove_unfiltered_items',
|
||||
'set_infinity_pipe_filter'
|
||||
}
|
||||
|
||||
Permission_Groups.new_group('Trusted')
|
||||
:allow_all()
|
||||
:disallow{
|
||||
'add_permission_group', -- admin
|
||||
'delete_permission_group',
|
||||
'edit_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor',
|
||||
'change_multiplayer_config',
|
||||
'set_heat_interface_mode',
|
||||
'set_heat_interface_temperature',
|
||||
'set_infinity_container_filter_item',
|
||||
'set_infinity_container_remove_unfiltered_items',
|
||||
'set_infinity_pipe_filter',
|
||||
'admin_action' -- trusted
|
||||
}
|
||||
|
||||
Permission_Groups.new_group('Standard')
|
||||
:allow_all()
|
||||
:disallow{
|
||||
'add_permission_group', -- admin
|
||||
'delete_permission_group',
|
||||
'edit_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor',
|
||||
'change_multiplayer_config',
|
||||
'set_heat_interface_mode',
|
||||
'set_heat_interface_temperature',
|
||||
'set_infinity_container_filter_item',
|
||||
'set_infinity_container_remove_unfiltered_items',
|
||||
'set_infinity_pipe_filter',
|
||||
'admin_action', -- trusted
|
||||
'change_programmable_speaker_alert_parameters', -- standard
|
||||
'drop_item',
|
||||
'set_auto_launch_rocket'
|
||||
}
|
||||
|
||||
Permission_Groups.new_group('Guest')
|
||||
:allow_all()
|
||||
:disallow{
|
||||
'add_permission_group', -- admin
|
||||
'delete_permission_group',
|
||||
'edit_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor',
|
||||
'change_multiplayer_config',
|
||||
'set_heat_interface_mode',
|
||||
'set_heat_interface_temperature',
|
||||
'set_infinity_container_filter_item',
|
||||
'set_infinity_container_remove_unfiltered_items',
|
||||
'set_infinity_pipe_filter',
|
||||
'admin_action', -- trusted
|
||||
'change_programmable_speaker_alert_parameters', -- standard
|
||||
'drop_item',
|
||||
'set_auto_launch_rocket',
|
||||
'change_programmable_speaker_parameters', -- guest
|
||||
'change_train_stop_station',
|
||||
--'deconstruct',
|
||||
'remove_cables',
|
||||
'remove_train_station',
|
||||
'reset_assembling_machine',
|
||||
'rotate_entity',
|
||||
'use_artillery_remote',
|
||||
'launch_rocket',
|
||||
'cancel_research',
|
||||
'activate_cut',
|
||||
'flush_opened_entity_fluid',
|
||||
'flush_opened_entity_specific_fluid'
|
||||
}
|
||||
|
||||
Permission_Groups.new_group('Restricted')
|
||||
:disallow_all()
|
||||
:allow('write_to_console')
|
||||
|
||||
--[[ These events are used until a role system is added to make it easier for our admins
|
||||
|
||||
local trusted_time = 60*60*60*10 -- 10 hour
|
||||
local standard_time = 60*60*60*3 -- 3 hour
|
||||
local function assign_group(player)
|
||||
local current_group_name = player.permission_group and player.permission_group.name or 'None'
|
||||
if player.admin then
|
||||
Permission_Groups.set_player_group(player,'Admin')
|
||||
elseif player.online_time > trusted_time or current_group_name == 'Trusted' then
|
||||
Permission_Groups.set_player_group(player,'Trusted')
|
||||
elseif player.online_time > standard_time or current_group_name == 'Standard' then
|
||||
Permission_Groups.set_player_group(player,'Standard')
|
||||
else
|
||||
Permission_Groups.set_player_group(player,'Guest')
|
||||
end
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_joined_game,function(event)
|
||||
local player = game.players[event.player_index]
|
||||
assign_group(player)
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_player_promoted,function(event)
|
||||
local player = game.players[event.player_index]
|
||||
assign_group(player)
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_player_demoted,function(event)
|
||||
local player = game.players[event.player_index]
|
||||
assign_group(player)
|
||||
end)
|
||||
|
||||
local check_interval = 60*60*15 -- 15 minutes
|
||||
Event.on_nth_tick(check_interval,function(event)
|
||||
for _,player in pairs(game.connected_players) do
|
||||
assign_group(player)
|
||||
end
|
||||
end)]]
|
||||
367
exp_legacy/module/config/expcore/roles.lua
Normal file
367
exp_legacy/module/config/expcore/roles.lua
Normal file
@@ -0,0 +1,367 @@
|
||||
--- This is the main config file for the role system; file includes defines for roles and role flags and default values
|
||||
-- @config Roles
|
||||
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local PlayerData = require 'expcore.player_data' --- @dep expcore.player_data
|
||||
local Statistics = PlayerData.Statistics
|
||||
|
||||
--- Role flags that will run when a player changes roles
|
||||
Roles.define_flag_trigger('is_admin',function(player,state)
|
||||
player.admin = state
|
||||
end)
|
||||
Roles.define_flag_trigger('is_spectator',function(player,state)
|
||||
player.spectator = state
|
||||
end)
|
||||
Roles.define_flag_trigger('is_jail',function(player,state)
|
||||
if player.character then
|
||||
player.character.active = not state
|
||||
end
|
||||
end)
|
||||
|
||||
--- Admin Roles
|
||||
Roles.new_role('System','SYS')
|
||||
:set_permission_group('Default', true)
|
||||
:set_flag('is_admin')
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_allow_all()
|
||||
|
||||
Roles.new_role('Senior Administrator','SAdmin')
|
||||
:set_permission_group('Admin')
|
||||
:set_custom_color{r=233,g=63,b=233}
|
||||
:set_flag('is_admin')
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Administrator')
|
||||
:allow{
|
||||
'command/interface',
|
||||
'command/debug',
|
||||
'command/toggle-cheat-mode',
|
||||
'command/research-all'
|
||||
}
|
||||
|
||||
Roles.new_role('Administrator','Admin')
|
||||
:set_permission_group('Admin')
|
||||
:set_custom_color{r=233,g=63,b=233}
|
||||
:set_flag('is_admin')
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Moderator')
|
||||
:allow{
|
||||
'gui/warp-list/bypass-proximity',
|
||||
'gui/warp-list/bypass-cooldown',
|
||||
'command/connect-all',
|
||||
'command/collectdata'
|
||||
}
|
||||
|
||||
Roles.new_role('Moderator','Mod')
|
||||
:set_permission_group('Admin')
|
||||
:set_custom_color{r=0,g=170,b=0}
|
||||
:set_flag('is_admin')
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Trainee')
|
||||
:allow{
|
||||
'command/assign-role',
|
||||
'command/unassign-role',
|
||||
'command/repair',
|
||||
'command/kill/always',
|
||||
'command/clear-tag/always',
|
||||
'command/go-to-spawn/always',
|
||||
'command/clear-reports',
|
||||
'command/clear-warnings',
|
||||
'command/clear-inventory',
|
||||
-- 'command/bonus',
|
||||
'gui/bonus',
|
||||
'command/home',
|
||||
'command/home-set',
|
||||
'command/home-get',
|
||||
'command/return',
|
||||
'command/connect-player',
|
||||
'gui/rocket-info/toggle-active',
|
||||
'gui/rocket-info/remote_launch',
|
||||
'command/toggle-friendly-fire',
|
||||
'command/toggle-always-day',
|
||||
'fast-tree-decon'
|
||||
}
|
||||
|
||||
Roles.new_role('Trainee','TrMod')
|
||||
:set_permission_group('Admin')
|
||||
:set_custom_color{r=0,g=170,b=0}
|
||||
:set_flag('is_admin')
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_parent('Veteran')
|
||||
:allow{
|
||||
'command/admin-chat',
|
||||
'command/admin-marker',
|
||||
'command/goto',
|
||||
'command/teleport',
|
||||
'command/bring',
|
||||
'command/give-warning',
|
||||
'command/get-warnings',
|
||||
'command/get-reports',
|
||||
'command/protect-entity',
|
||||
'command/protect-area',
|
||||
'command/jail',
|
||||
'command/unjail',
|
||||
'command/kick',
|
||||
'command/ban',
|
||||
'command/spectate',
|
||||
'command/follow',
|
||||
'command/search',
|
||||
'command/search-amount',
|
||||
'command/search-recent',
|
||||
'command/search-online',
|
||||
'command/personal-battery-recharge',
|
||||
'command/pollution-off',
|
||||
'command/pollution-clear',
|
||||
'command/bot-queue-get',
|
||||
'command/bot-queue-set',
|
||||
'command/game-speed',
|
||||
'command/kill-biters',
|
||||
'command/remove-biters',
|
||||
'gui/playerdata'
|
||||
}
|
||||
|
||||
--- Trusted Roles
|
||||
Roles.new_role('Board Member','Board')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=247,g=246,b=54}
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Sponsor')
|
||||
:allow{
|
||||
'command/goto',
|
||||
'command/repair',
|
||||
'command/spectate',
|
||||
'command/follow',
|
||||
'gui/playerdata'
|
||||
}
|
||||
|
||||
Roles.new_role('Senior Backer','Backer')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=238,g=172,b=44}
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Sponsor')
|
||||
:allow{
|
||||
}
|
||||
|
||||
Roles.new_role('Sponsor','Spon')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=238,g=172,b=44}
|
||||
:set_flag('is_spectator')
|
||||
:set_flag('report-immune')
|
||||
:set_flag('instant-respawn')
|
||||
:set_parent('Supporter')
|
||||
:allow{
|
||||
'gui/rocket-info/toggle-active',
|
||||
'gui/rocket-info/remote_launch',
|
||||
-- 'command/bonus',
|
||||
'gui/bonus',
|
||||
'command/home',
|
||||
'command/home-set',
|
||||
'command/home-get',
|
||||
'command/return',
|
||||
'fast-tree-decon'
|
||||
}
|
||||
|
||||
Roles.new_role('Supporter','Sup')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=230,g=99,b=34}
|
||||
:set_flag('is_spectator')
|
||||
:set_parent('Veteran')
|
||||
:allow{
|
||||
'command/tag-color',
|
||||
'command/jail',
|
||||
'command/unjail',
|
||||
'command/join-message',
|
||||
'command/join-message-clear'
|
||||
}
|
||||
|
||||
Roles.new_role('Partner','Part')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=140,g=120,b=200}
|
||||
:set_flag('is_spectator')
|
||||
:set_parent('Veteran')
|
||||
:allow{
|
||||
'command/jail',
|
||||
'command/unjail'
|
||||
}
|
||||
|
||||
local hours10, hours250 = 10*216000, 250*60
|
||||
Roles.new_role('Veteran','Vet')
|
||||
:set_permission_group('Trusted')
|
||||
:set_custom_color{r=140,g=120,b=200}
|
||||
:set_parent('Member')
|
||||
:allow{
|
||||
'command/chat-bot',
|
||||
'command/last-location'
|
||||
}
|
||||
:set_auto_assign_condition(function(player)
|
||||
if player.online_time >= hours10 then
|
||||
return true
|
||||
else
|
||||
local stats = Statistics:get(player, {})
|
||||
local playTime, afkTime, mapCount = stats.Playtime or 0, stats.AfkTime or 0, stats.MapsPlayed or 0
|
||||
return playTime - afkTime >= hours250 and mapCount >= 25
|
||||
end
|
||||
end)
|
||||
|
||||
--- Standard User Roles
|
||||
Roles.new_role('Member','Mem')
|
||||
:set_permission_group('Standard')
|
||||
:set_custom_color{r=24,g=172,b=188}
|
||||
:set_flag('deconlog-bypass')
|
||||
:set_parent('Regular')
|
||||
:allow{
|
||||
'gui/task-list/add',
|
||||
'gui/task-list/edit',
|
||||
'gui/warp-list/add',
|
||||
'gui/warp-list/edit',
|
||||
'command/save-quickbar',
|
||||
'gui/vlayer-edit',
|
||||
'command/vlayer-info',
|
||||
'command/personal-logistic',
|
||||
'command/auto-research',
|
||||
'command/set-trains-to-automatic',
|
||||
'command/lawnmower',
|
||||
'command/waterfill',
|
||||
'command/artillery-target-remote',
|
||||
'command/clear-item-on-ground',
|
||||
'command/clear-blueprint',
|
||||
'gui/surveillance'
|
||||
}
|
||||
|
||||
local hours3, hours15 = 3*216000, 15*60
|
||||
Roles.new_role('Regular','Reg')
|
||||
:set_permission_group('Standard')
|
||||
:set_custom_color{r=79,g=155,b=163}
|
||||
:set_parent('Guest')
|
||||
:allow{
|
||||
'command/kill',
|
||||
'command/rainbow',
|
||||
'command/go-to-spawn',
|
||||
'command/me',
|
||||
'standard-decon',
|
||||
'bypass-entity-protection',
|
||||
'bypass-nukeprotect'
|
||||
}
|
||||
:set_auto_assign_condition(function(player)
|
||||
if player.online_time >= hours3 then
|
||||
return true
|
||||
else
|
||||
local stats = Statistics:get(player, {})
|
||||
local playTime, afkTime, mapCount = stats.Playtime or 0, stats.AfkTime or 0, stats.MapsPlayed or 0
|
||||
return playTime - afkTime >= hours15 and mapCount >= 5
|
||||
end
|
||||
end)
|
||||
|
||||
--- Guest/Default role
|
||||
local default = Roles.new_role('Guest','')
|
||||
:set_permission_group('Guest')
|
||||
:set_custom_color{r=185,g=187,b=160}
|
||||
:allow{
|
||||
'command/tag',
|
||||
'command/tag-clear',
|
||||
'command/search-help',
|
||||
'command/list-roles',
|
||||
'command/find-on-map',
|
||||
'command/report',
|
||||
'command/ratio',
|
||||
'command/server-ups',
|
||||
'command/save-data',
|
||||
'command/preference',
|
||||
'command/set-preference',
|
||||
'command/connect',
|
||||
'gui/player-list',
|
||||
'gui/rocket-info',
|
||||
'gui/science-info',
|
||||
'gui/task-list',
|
||||
'gui/warp-list',
|
||||
'gui/readme',
|
||||
'gui/vlayer',
|
||||
'gui/research',
|
||||
'gui/autofill',
|
||||
'gui/module',
|
||||
'gui/landfill',
|
||||
'gui/production'
|
||||
}
|
||||
|
||||
--- Jail role
|
||||
Roles.new_role('Jail')
|
||||
:set_permission_group('Restricted')
|
||||
:set_custom_color{r=50,g=50,b=50}
|
||||
:set_block_auto_assign(true)
|
||||
:set_flag('defer_role_changes')
|
||||
:disallow(default.allowed)
|
||||
|
||||
--- System defaults which are required to be set
|
||||
Roles.set_root('System')
|
||||
Roles.set_default('Guest')
|
||||
|
||||
Roles.define_role_order{
|
||||
'System', -- Best to keep root at top
|
||||
'Senior Administrator',
|
||||
'Administrator',
|
||||
'Moderator',
|
||||
'Trainee',
|
||||
'Board Member',
|
||||
'Senior Backer',
|
||||
'Sponsor',
|
||||
'Supporter',
|
||||
'Partner',
|
||||
'Veteran',
|
||||
'Member',
|
||||
'Regular',
|
||||
'Jail',
|
||||
'Guest' -- Default must be last if you want to apply restrictions to other roles
|
||||
}
|
||||
|
||||
Roles.override_player_roles{
|
||||
['PHIDIAS0303']={'Moderator', 'Board Member', 'Member'},
|
||||
['aldldl']={'Administrator', 'Moderator','Member'},
|
||||
['arty714']={'Senior Administrator', 'Moderator', 'Member'},
|
||||
['Cooldude2606']={'Senior Administrator', 'Moderator', 'Member'},
|
||||
['Drahc_pro']={'Administrator', 'Moderator', 'Member'},
|
||||
['mark9064']={'Administrator', 'Moderator','Member'},
|
||||
['7h3w1z4rd']={'Moderator','Member'},
|
||||
['FlipHalfling90']={'Moderator','Member'},
|
||||
['hamsterbryan']={'Moderator','Member'},
|
||||
['HunterOfGames']={'Moderator','Member'},
|
||||
['NextIdea']={'Moderator','Member'},
|
||||
['TheKernel32']={'Moderator','Member'},
|
||||
['TheKernel64']={'Moderator','Member'},
|
||||
['tovernaar123']={'Moderator','Member'},
|
||||
['UUBlueFire']={'Moderator','Member'},
|
||||
['AssemblyStorm']={'Moderator', 'Member'},
|
||||
['banakeg']={'Moderator','Member'},
|
||||
['connormkii']={'Moderator', 'Member'},
|
||||
['cydes']={'Moderator','Member'},
|
||||
['darklich14']={'Moderator','Member'},
|
||||
['facere']={'Moderator','Member'},
|
||||
['freek18']={'Moderator','Member'},
|
||||
['Gizan']={'Moderator','Member'},
|
||||
['LoicB']={'Moderator','Member'},
|
||||
['M74132']={'Moderator','Member'},
|
||||
['mafisch3']={'Moderator','Member'},
|
||||
['maplesyrup01']={'Moderator','Member'},
|
||||
['ookl']={'Moderator','Member'},
|
||||
['Phoenix27833']={'Moderator','Member'},
|
||||
['porelos']={'Moderator','Member'},
|
||||
['Ruuyji']={'Moderator','Member'},
|
||||
['samy115']={'Moderator','Member'},
|
||||
['SilentLog']={'Moderator','Member'},
|
||||
['Tcheko']={'Moderator','Member'},
|
||||
['thadius856']={'Moderator','Member'},
|
||||
['whoami32']={'Moderator','Member'},
|
||||
['Windbomb']={'Moderator','Member'},
|
||||
['XenoCyber']={'Moderator','Member'}
|
||||
}
|
||||
7
exp_legacy/module/config/graftorio.lua
Normal file
7
exp_legacy/module/config/graftorio.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
return {
|
||||
modules = {
|
||||
["forcestats"] = true,
|
||||
["logistorage"] = false,
|
||||
["other"] = true,
|
||||
}
|
||||
}
|
||||
130
exp_legacy/module/config/gui/autofill.lua
Normal file
130
exp_legacy/module/config/gui/autofill.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
--- This file contains all the different settings for the autofill system and gui
|
||||
-- @config Autofill
|
||||
|
||||
local table = require 'overrides.table' -- @dep overrides.table
|
||||
|
||||
local config = {
|
||||
-- General config
|
||||
icon = 'item/piercing-rounds-magazine', -- @setting icon that will be used for the toolbar
|
||||
categories = {
|
||||
ammo = 'ammo',
|
||||
fuel = 'fuel',
|
||||
shell = 'shell'
|
||||
},
|
||||
entities = {
|
||||
car = 'car',
|
||||
tank = 'tank',
|
||||
spidertron = 'spidertron',
|
||||
locomotive = 'locomotive',
|
||||
gun_turret = 'gun-turret',
|
||||
burner_mining_drill = 'burner-mining-drill',
|
||||
stone_furnace = 'stone-furnace',
|
||||
steel_furnace = 'steel-furnace'
|
||||
},
|
||||
default_entities = {}
|
||||
}
|
||||
|
||||
local default_categories = {
|
||||
{
|
||||
category = config.categories.ammo,
|
||||
entity = {config.entities.car, config.entities.tank, config.entities.gun_turret},
|
||||
inv = {defines.inventory.car_ammo, defines.inventory.turret_ammo},
|
||||
items = {
|
||||
{ name = 'uranium-rounds-magazine', amount = 10, enabled = false },
|
||||
{ name = 'piercing-rounds-magazine', amount = 10, enabled = false },
|
||||
{ name = 'firearm-magazine', amount = 10, enabled = false },
|
||||
}
|
||||
},
|
||||
{
|
||||
category = config.categories.ammo,
|
||||
entity = {config.entities.tank},
|
||||
inv = {defines.inventory.car_ammo},
|
||||
items = {
|
||||
{ name = 'flamethrower-ammo', amount = 10, enabled = false },
|
||||
}
|
||||
},
|
||||
{
|
||||
category = config.categories.shell,
|
||||
entity = {config.entities.tank},
|
||||
inv = {defines.inventory.car_ammo},
|
||||
items = {
|
||||
{ name = 'cannon-shell', amount = 10, enabled = false },
|
||||
{ name = 'explosive-cannon-shell', amount = 10, enabled = false },
|
||||
{ name = 'uranium-cannon-shell', amount = 10, enabled = false },
|
||||
{ name = 'explosive-uranium-cannon-shell', amount = 10, enabled = false },
|
||||
}
|
||||
},
|
||||
{
|
||||
category = config.categories.ammo,
|
||||
entity = {config.entities.spidertron},
|
||||
inv = {defines.inventory.car_ammo},
|
||||
items = {
|
||||
{ name = 'rocket', amount = 10, enabled = false },
|
||||
{ name = 'explosive-rocket', amount = 10, enabled = false },
|
||||
{ name = 'atomic-bomb', amount = 10, enabled = false },
|
||||
}
|
||||
},
|
||||
{
|
||||
category = config.categories.fuel,
|
||||
entity = {config.entities.car, config.entities.tank, config.entities.locomotive, config.entities.burner_mining_drill, config.entities.stone_furnace, config.entities.steel_furnace},
|
||||
inv = {defines.inventory.fuel},
|
||||
items = {
|
||||
{ name = 'nuclear-fuel', amount = 10, enabled = false },
|
||||
{ name = 'rocket-fuel', amount = 10, enabled = false },
|
||||
{ name = 'solid-fuel', amount = 10, enabled = false },
|
||||
{ name = 'coal', amount = 10, enabled = false },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local function get_items_by_inv(entity, inv)
|
||||
local items = entity.items
|
||||
for _, category in pairs(default_categories) do
|
||||
if table.contains(category.entity, entity.entity) then
|
||||
if table.contains(category.inv, inv) then
|
||||
for _, item in pairs(category.items) do
|
||||
items[item.name] = {
|
||||
entity = entity.entity,
|
||||
category = category.category,
|
||||
inv = inv,
|
||||
name = item.name,
|
||||
amount = item.amount,
|
||||
enabled = item.enabled
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
local function generate_default_setting(entity_name, inv, enabled)
|
||||
if not config.default_entities[entity_name] then
|
||||
config.default_entities[entity_name] = {
|
||||
entity = entity_name,
|
||||
enabled = enabled,
|
||||
items = {}
|
||||
}
|
||||
end
|
||||
get_items_by_inv(config.default_entities[entity_name], inv)
|
||||
end
|
||||
|
||||
generate_default_setting(config.entities.car, defines.inventory.fuel, true)
|
||||
generate_default_setting(config.entities.car, defines.inventory.car_ammo, true)
|
||||
|
||||
generate_default_setting(config.entities.locomotive, defines.inventory.fuel, true)
|
||||
|
||||
generate_default_setting(config.entities.tank, defines.inventory.fuel, true)
|
||||
generate_default_setting(config.entities.tank, defines.inventory.car_ammo, true)
|
||||
|
||||
generate_default_setting(config.entities.spidertron, defines.inventory.car_ammo, true)
|
||||
|
||||
generate_default_setting(config.entities.gun_turret, defines.inventory.turret_ammo, true)
|
||||
|
||||
generate_default_setting(config.entities.burner_mining_drill, defines.inventory.fuel, true)
|
||||
|
||||
generate_default_setting(config.entities.stone_furnace, defines.inventory.fuel, true)
|
||||
|
||||
generate_default_setting(config.entities.steel_furnace, defines.inventory.fuel, true)
|
||||
|
||||
return config
|
||||
205
exp_legacy/module/config/gui/player_list_actions.lua
Normal file
205
exp_legacy/module/config/gui/player_list_actions.lua
Normal file
@@ -0,0 +1,205 @@
|
||||
--- Config for the different action buttons that show on the player list;
|
||||
-- each button has the button define(s) given along side an auth function, and optional reason callback;
|
||||
-- if a reason callback is used then Store.set(action_name_store,player.name,'BUTTON_NAME') should be called during on_click;
|
||||
-- buttons can be removed from the gui by commenting them out of the config at the bottom of this file;
|
||||
-- the key used for the name of the button is the permission name used by the role system;
|
||||
-- @config Player-List
|
||||
|
||||
local Gui = require 'expcore.gui' --- @dep expcore.gui
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local Reports = require 'modules.control.reports' --- @dep modules.control.reports
|
||||
local Warnings = require 'modules.control.warnings' --- @dep modules.control.warnings
|
||||
local Jail = require 'modules.control.jail' --- @dep modules.control.jail
|
||||
local Colors = require 'utils.color_presets' --- @dep utils.color_presets
|
||||
local format_chat_player_name = _C.format_chat_player_name --- @dep expcore.common
|
||||
|
||||
local SelectedPlayer, SelectedAction
|
||||
local function set_datastores(player, action)
|
||||
SelectedPlayer, SelectedAction = player, action
|
||||
end
|
||||
|
||||
-- auth that will only allow when on player's of lower roles
|
||||
local function auth_lower_role(player,selected_player_name)
|
||||
local player_highest = Roles.get_player_highest_role(player)
|
||||
local action_player_highest = Roles.get_player_highest_role(selected_player_name)
|
||||
if player_highest.index < action_player_highest.index then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- gets the action player and a coloured name for the action to be used on
|
||||
local function get_action_player_name(player)
|
||||
local selected_player_name = SelectedPlayer:get(player)
|
||||
local selected_player = game.players[selected_player_name]
|
||||
local selected_player_color = format_chat_player_name(selected_player)
|
||||
return selected_player_name, selected_player_color
|
||||
end
|
||||
|
||||
-- teleports one player to another
|
||||
local function teleport(from_player,to_player)
|
||||
local surface = to_player.surface
|
||||
local position = surface.find_non_colliding_position('character',to_player.position,32,1)
|
||||
if not position then return false end -- return false if no new position
|
||||
if from_player.driving then from_player.driving = false end -- kicks a player out a vehicle if in one
|
||||
from_player.teleport(position,surface)
|
||||
return true
|
||||
end
|
||||
|
||||
local function new_button(sprite,tooltip)
|
||||
return Gui.element{
|
||||
type = 'sprite-button',
|
||||
style = 'tool_button',
|
||||
sprite = sprite,
|
||||
tooltip = tooltip
|
||||
}:style{
|
||||
padding = -1,
|
||||
height = 28,
|
||||
width = 28
|
||||
}
|
||||
end
|
||||
|
||||
--- Teleports the user to the action player
|
||||
-- @element goto_player
|
||||
local goto_player = new_button('utility/export',{'player-list.goto-player'})
|
||||
:on_click(function(player)
|
||||
local selected_player_name = get_action_player_name(player)
|
||||
local selected_player = game.players[selected_player_name]
|
||||
if not player.character or not selected_player.character then
|
||||
player.print({'expcore-commands.reject-player-alive'},Colors.orange_red)
|
||||
else
|
||||
teleport(player,selected_player)
|
||||
end
|
||||
end)
|
||||
|
||||
--- Teleports the action player to the user
|
||||
-- @element bring_player
|
||||
local bring_player = new_button('utility/import',{'player-list.bring-player'})
|
||||
:on_click(function(player)
|
||||
local selected_player_name = get_action_player_name(player)
|
||||
local selected_player = game.players[selected_player_name]
|
||||
if not player.character or not selected_player.character then
|
||||
player.print({'expcore-commands.reject-player-alive'},Colors.orange_red)
|
||||
else
|
||||
teleport(selected_player,player)
|
||||
end
|
||||
end)
|
||||
|
||||
--- Reports the action player, requires a reason to be given
|
||||
-- @element report_player
|
||||
local report_player = new_button('utility/spawn_flag',{'player-list.report-player'})
|
||||
:on_click(function(player)
|
||||
local selected_player_name = get_action_player_name(player)
|
||||
if Reports.is_reported(selected_player_name,player.name) then
|
||||
player.print({'expcom-report.already-reported'},Colors.orange_red)
|
||||
else
|
||||
SelectedAction:set(player, 'command/report')
|
||||
end
|
||||
end)
|
||||
|
||||
local function report_player_callback(player,reason)
|
||||
local selected_player_name, selected_player_color = get_action_player_name(player)
|
||||
local by_player_name_color = format_chat_player_name(player)
|
||||
game.print{'expcom-report.non-admin', selected_player_color,reason}
|
||||
Roles.print_to_roles_higher('Trainee',{'expcom-report.admin', selected_player_color,by_player_name_color,reason})
|
||||
Reports.report_player(selected_player_name,player.name,reason)
|
||||
end
|
||||
|
||||
--- Gives the action player a warning, requires a reason
|
||||
-- @element warn_player
|
||||
local warn_player = new_button('utility/spawn_flag',{'player-list.warn-player'})
|
||||
:on_click(function(player)
|
||||
SelectedAction:set(player, 'command/give-warning')
|
||||
end)
|
||||
|
||||
local function warn_player_callback(player,reason)
|
||||
local selected_player_name, selected_player_color = get_action_player_name(player)
|
||||
local by_player_name_color = format_chat_player_name(player)
|
||||
game.print{'expcom-warnings.received', selected_player_color,by_player_name_color,reason}
|
||||
Warnings.add_warning(selected_player_name,player.name,reason)
|
||||
end
|
||||
|
||||
--- Jails the action player, requires a reason
|
||||
-- @element jail_player
|
||||
local jail_player = new_button('utility/multiplayer_waiting_icon',{'player-list.jail-player'})
|
||||
:on_click(function(player)
|
||||
local selected_player_name, selected_player_color = get_action_player_name(player)
|
||||
if Jail.is_jailed(selected_player_name) then
|
||||
player.print({'expcom-jail.already-jailed', selected_player_color},Colors.orange_red)
|
||||
else
|
||||
SelectedAction:set(player, 'command/jail')
|
||||
end
|
||||
end)
|
||||
|
||||
local function jail_player_callback(player,reason)
|
||||
local selected_player_name, selected_player_color = get_action_player_name(player)
|
||||
local by_player_name_color = format_chat_player_name(player)
|
||||
game.print{'expcom-jail.give', selected_player_color,by_player_name_color,reason}
|
||||
Jail.jail_player(selected_player_name,player.name,reason)
|
||||
end
|
||||
|
||||
--- Kicks the action player, requires a reason
|
||||
-- @element kick_player
|
||||
local kick_player = new_button('utility/warning_icon',{'player-list.kick-player'})
|
||||
:on_click(function(player)
|
||||
SelectedAction:set(player, 'command/kick')
|
||||
end)
|
||||
|
||||
local function kick_player_callback(player,reason)
|
||||
local selected_player = get_action_player_name(player)
|
||||
game.kick_player(selected_player,reason)
|
||||
end
|
||||
|
||||
--- Bans the action player, requires a reason
|
||||
-- @element ban_player
|
||||
local ban_player = new_button('utility/danger_icon',{'player-list.ban-player'})
|
||||
:on_click(function(player)
|
||||
SelectedAction:set(player, 'command/ban')
|
||||
end)
|
||||
|
||||
local function ban_player_callback(player,reason)
|
||||
local selected_player = get_action_player_name(player)
|
||||
game.ban_player(selected_player,reason)
|
||||
end
|
||||
|
||||
return {
|
||||
set_datastores = set_datastores,
|
||||
buttons = {
|
||||
['command/teleport'] = {
|
||||
auth=function(player,selected_player)
|
||||
return player.name ~= selected_player.name
|
||||
end, -- cant teleport to your self
|
||||
goto_player,
|
||||
bring_player
|
||||
},
|
||||
['command/report'] = {
|
||||
auth=function(player,selected_player)
|
||||
if player == selected_player then return false end
|
||||
if not Roles.player_allowed(player,'command/give-warning') then
|
||||
return not Roles.player_has_flag(selected_player,'report-immune')
|
||||
end
|
||||
end, -- can report any player that isn't immune and you aren't able to give warnings
|
||||
reason_callback=report_player_callback,
|
||||
report_player
|
||||
},
|
||||
['command/give-warning'] = {
|
||||
auth=auth_lower_role, -- warn a lower user, replaces report
|
||||
reason_callback=warn_player_callback,
|
||||
warn_player
|
||||
},
|
||||
['command/jail'] = {
|
||||
auth=auth_lower_role,
|
||||
reason_callback=jail_player_callback,
|
||||
jail_player
|
||||
},
|
||||
['command/kick'] = {
|
||||
auth=auth_lower_role,
|
||||
reason_callback=kick_player_callback,
|
||||
kick_player
|
||||
},
|
||||
['command/ban'] = {
|
||||
auth=auth_lower_role,
|
||||
reason_callback=ban_player_callback,
|
||||
ban_player
|
||||
}
|
||||
}
|
||||
}
|
||||
35
exp_legacy/module/config/gui/rockets.lua
Normal file
35
exp_legacy/module/config/gui/rockets.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
--- This file controls what will show in each section of the rocket info gui
|
||||
-- @config Rockets
|
||||
|
||||
return {
|
||||
stats = { --- @setting stats The data that will show in the stats section
|
||||
show_stats=true, --- @setting show_stats false will hide this section all together
|
||||
show_first_rocket = true, --- @setting show_first_rocket false will not show when the first rocket was launched
|
||||
show_last_rocket = true, --- @setting show_last_rocket false will not show when the last rocket was launched
|
||||
show_fastest_rocket = true, --- @setting show_fastest_rocket false will not show the time taken for the fastest rocket
|
||||
show_total_rockets = true, --- @setting show_total_rockets false will not show the total number of rockets launched
|
||||
show_game_avg = true, --- @setting show_game_avg false will hide the avg across the entire map time
|
||||
rolling_avg = { --- @setting rolling_avg each number will be one statistic; 5 means the avg time taken for the last 5 rockets
|
||||
5,10,25
|
||||
}
|
||||
},
|
||||
milestones = { --- @setting milestones each number will be one statistic; 5 means the time that the 5th rocket was launched
|
||||
show_milestones=true, --- @setting show_milestones false will hide this section all together
|
||||
1,2,5,
|
||||
10,20,50,
|
||||
100,200,500,
|
||||
1000,1500,2000,2500,
|
||||
3000,3500,4000,4500,
|
||||
5000
|
||||
},
|
||||
progress = { --- @setting progress The data and buttons in the build progress section
|
||||
show_progress = true, --- @setting show_progress false will hide this section altogether
|
||||
allow_zoom_to_map = true, --- @setting allow_zoom_to_map false will disable the zoom to map feature
|
||||
allow_remote_launch = true, --- @setting allow_remote_launch false removes the remote launch button for all players
|
||||
remote_launch_admins_only = false, --- @setting remote_launch_admins_only true will remove the remote launch button for all non (game) admins
|
||||
remote_launch_role_permission = 'gui/rocket-info/remote_launch', --- @setting remote_launch_role_permission value used by custom permission system to allow or disallow the button
|
||||
allow_toggle_active = true, --- @setting allow_toggle_active false removes the remote toggle auto launch button for all players
|
||||
toggle_active_admins_only = false, --- @setting toggle_active_admins_only true will remove the toggle auto launch button for all non (game) admins
|
||||
toggle_active_role_permission = 'gui/rocket-info/toggle-active' --- @setting toggle_active_role_permission value used by custom permission system to allow or disallow the button
|
||||
}
|
||||
}
|
||||
16
exp_legacy/module/config/gui/science.lua
Normal file
16
exp_legacy/module/config/gui/science.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
--- Config file for the science info gui
|
||||
-- @config Science
|
||||
|
||||
return {
|
||||
-- list of all science packs to be shown in the gui
|
||||
show_eta = true, --- @setting show_eta when true the eta for research completion will be shown
|
||||
color_cutoff = 0.8, --- @setting color_cutoff the amount that production can fall before the text changes color
|
||||
color_flux = 0.1, --- @setting color_flux the amount of fluctuation allowed in production before the icon changes color
|
||||
'automation-science-pack',
|
||||
'logistic-science-pack',
|
||||
'military-science-pack',
|
||||
'chemical-science-pack',
|
||||
'production-science-pack',
|
||||
'utility-science-pack',
|
||||
'space-science-pack',
|
||||
}
|
||||
13
exp_legacy/module/config/gui/tasks.lua
Normal file
13
exp_legacy/module/config/gui/tasks.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
--- Config file for the tasks gui
|
||||
-- @config Tasks
|
||||
|
||||
return {
|
||||
-- Adding tasks
|
||||
allow_add_task = 'all', --- @setting allow_add_task dictates who is allowed to add new tasks; values: all, admin, expcore.roles, none
|
||||
expcore_roles_allow_add_task = 'gui/task-list/add', --- @setting expcore_roles_allow_add_task if expcore.roles is used then this is the required permission
|
||||
|
||||
-- Editing tasks
|
||||
allow_edit_task = 'expcore.roles', --- @setting allow_edit_task dictates who is allowed to edit existing tasks; values: all, admin, expcore.roles, none
|
||||
expcore_roles_allow_edit_task = 'gui/task-list/edit', --- @setting expcore_roles_allow_edit_task if expcore.roles is used then this is the required permission
|
||||
user_can_edit_own_tasks = true --- @settings if true then the user who made the task can edit it regardless of the allow_edit_task setting
|
||||
}
|
||||
52
exp_legacy/module/config/gui/warps.lua
Normal file
52
exp_legacy/module/config/gui/warps.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
--- This file contains all the different settings for the warp system and gui
|
||||
-- @config Warps
|
||||
|
||||
return {
|
||||
-- General config
|
||||
update_smoothing = 10, --- @setting update_smoothing the amount of smoothing applied to updates to the cooldown timer, higher is better, max is 60
|
||||
minimum_distance = 100, --- @setting minimum_distance the minimum distance that is allowed between warps on the same force
|
||||
default_icon = {type = 'item', name = 'discharge-defense-equipment'}, --- @setting default_icon the default icon that will be used for warps
|
||||
|
||||
-- Warp cooldowns
|
||||
bypass_warp_cooldown = 'expcore.roles', --- @setting bypass_warp_cooldown dictates who the warp cooldown is applied to; values: all, admin, expcore.roles, none
|
||||
expcore_roles_bypass_warp_cooldown = 'gui/warp-list/bypass-cooldown', --- @setting expcore_roles_bypass_warp_cooldown if expcore.roles is used then this is the required permission
|
||||
cooldown_duration = 60, --- @setting cooldown_duration the duration of the warp cooldown in seconds
|
||||
|
||||
-- Warp proximity
|
||||
bypass_warp_proximity = 'expcore.roles', --- @setting bypass_warp_proximity dictates who the warp proximity is applied to; values: all, admin, expcore.roles, none
|
||||
expcore_roles_bypass_warp_proximity = 'gui/warp-list/bypass-proximity', --- @setting expcore_roles_bypass_warp_proximity if expcore.roles is used then this is the required permission
|
||||
standard_proximity_radius = 4, --- @setting standard_proximity_radius the minimum distance a player is allowed to be to a warp in order to use it
|
||||
spawn_proximity_radius = 20, --- @setting spawn_proximity_radius the minimum distance a player is allowed to be from they spawn point to use warps
|
||||
|
||||
-- Adding warps
|
||||
allow_add_warp = 'expcore.roles', --- @setting allow_add_warp dictates who is allowed to add warps; values: all, admin, expcore.roles, none
|
||||
expcore_roles_allow_add_warp = 'gui/warp-list/add', --- @setting expcore_roles_allow_add_warp if expcore.roles is used then this is the required permission
|
||||
|
||||
-- Editing warps
|
||||
allow_edit_warp = 'expcore.roles', --- @setting allow_edit_warp dictates who is allowed to edit warps; values: all, admin, expcore.roles, none
|
||||
expcore_roles_allow_edit_warp = 'gui/warp-list/edit', --- @setting expcore_roles_allow_edit_warp if expcore.roles is used then this is the required permission
|
||||
user_can_edit_own_warps = false, --- @settings user_can_edit_own_warps if true then the user who made the warp can edit it regardless of the allow_edit_warp setting
|
||||
|
||||
-- Warp area generation
|
||||
entities = { --- @setting entities The entities which are created for warp areas
|
||||
{'small-lamp', -4, -2}, {'small-lamp', -2, -4}, {'medium-electric-pole',-3,-3}, -- Top left corner
|
||||
{'small-lamp', 3, -2}, {'small-lamp', 1, -4}, {'medium-electric-pole',2,-3}, -- Top right corner
|
||||
{'small-lamp', 3, 1}, {'small-lamp', 1, 3}, {'medium-electric-pole',2,2}, -- Bottom right corner
|
||||
{'small-lamp', -4, 1}, {'small-lamp', -2, 3}, {'medium-electric-pole',-3,2}, -- Bottom left corner
|
||||
},
|
||||
tiles = { --- @setting tiles The tiles which are created for warp areas
|
||||
{'black-refined-concrete',-4,-2}, {'black-refined-concrete',-4,-1}, {'black-refined-concrete',-4,0}, {'black-refined-concrete',-4,1},
|
||||
{'black-refined-concrete',-3,-3}, {'purple-refined-concrete',-3,-2}, {'purple-refined-concrete',-3,-1}, {'purple-refined-concrete',-3,0},
|
||||
{'purple-refined-concrete',-3,1}, {'black-refined-concrete',-3,2}, {'black-refined-concrete',-2,-4}, {'purple-refined-concrete',-2,-3},
|
||||
{'purple-refined-concrete',-2,-2}, {'purple-refined-concrete',-2,-1}, {'purple-refined-concrete',-2,0}, {'purple-refined-concrete',-2,1},
|
||||
{'purple-refined-concrete',-2,2}, {'black-refined-concrete',-2,3}, {'black-refined-concrete',-1,-4}, {'purple-refined-concrete',-1,-3},
|
||||
{'purple-refined-concrete',-1,-2}, {'purple-refined-concrete',-1,-1}, {'purple-refined-concrete',-1,0}, {'purple-refined-concrete',-1,1},
|
||||
{'purple-refined-concrete',-1,2}, {'black-refined-concrete',-1,3}, {'black-refined-concrete',0,-4}, {'purple-refined-concrete',0,-3},
|
||||
{'purple-refined-concrete',0,-2}, {'purple-refined-concrete',0,-1}, {'purple-refined-concrete',0,0}, {'purple-refined-concrete',0,1},
|
||||
{'purple-refined-concrete',0,2}, {'black-refined-concrete',0,3}, {'black-refined-concrete',1,-4}, {'purple-refined-concrete',1,-3},
|
||||
{'purple-refined-concrete',1,-2}, {'purple-refined-concrete',1,-1}, {'purple-refined-concrete',1,0}, {'purple-refined-concrete',1,1},
|
||||
{'purple-refined-concrete',1,2}, {'black-refined-concrete',1,3}, {'black-refined-concrete',2,-3}, {'purple-refined-concrete',2,-2},
|
||||
{'purple-refined-concrete',2,-1}, {'purple-refined-concrete',2,0}, {'purple-refined-concrete',2,1}, {'black-refined-concrete',2,2},
|
||||
{'black-refined-concrete',3,-2}, {'black-refined-concrete',3,-1}, {'black-refined-concrete',3,0}, {'black-refined-concrete',3,1}
|
||||
}
|
||||
}
|
||||
9
exp_legacy/module/config/inventory_clear.lua
Normal file
9
exp_legacy/module/config/inventory_clear.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
--- Config to control when players items are removed, this is a list of event names that will trigger inventory clear
|
||||
-- @config inventory_clear
|
||||
|
||||
local events = defines.events
|
||||
return {
|
||||
events.on_player_banned,
|
||||
events.on_player_kicked,
|
||||
--events.on_player_left_game
|
||||
}
|
||||
8
exp_legacy/module/config/join_messages.lua
Normal file
8
exp_legacy/module/config/join_messages.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
return {
|
||||
Cooldude2606 = 'Lua lets you set metatables on numbers, did you know that? Cooldude2606 knows this.',
|
||||
samy115 = 'Tremble in fear as the banhammer is now here, its owner: samy115',
|
||||
XenoCyber = '"Fire Fire Fire" oops wrong game, have no fear XenoCyber is here',
|
||||
HunterOfGames = 'Unable to support HunterOfGames. You must construct additional miners.',
|
||||
ookl = 'ookl says: "Pineapples are amazing, hello everyone!"',
|
||||
arty714 = 'Arty\'s Potato made it!'
|
||||
}
|
||||
6
exp_legacy/module/config/lawnmower.lua
Normal file
6
exp_legacy/module/config/lawnmower.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
--- Settings for lawnmower
|
||||
-- @config lawnmower
|
||||
|
||||
return {
|
||||
destroy_decoratives = false
|
||||
}
|
||||
30
exp_legacy/module/config/logging.lua
Normal file
30
exp_legacy/module/config/logging.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
--- Settings for logging
|
||||
-- @config logging
|
||||
|
||||
return {
|
||||
file_name = 'log/logging.log',
|
||||
rocket_launch_display = {
|
||||
[1] = true,
|
||||
[2] = true,
|
||||
[5] = true,
|
||||
[10] = true,
|
||||
[20] = true,
|
||||
[50] = true,
|
||||
[100] = true,
|
||||
[200] = true
|
||||
},
|
||||
rocket_launch_display_rate = 500,
|
||||
disconnect_reason = {
|
||||
[defines.disconnect_reason.quit] = ' left the game',
|
||||
[defines.disconnect_reason.dropped] = ' was dropped from the game',
|
||||
[defines.disconnect_reason.reconnect] = ' is reconnecting',
|
||||
[defines.disconnect_reason.wrong_input] = ' was having a wrong input',
|
||||
[defines.disconnect_reason.desync_limit_reached] = ' had desync limit reached',
|
||||
[defines.disconnect_reason.cannot_keep_up] = ' cannot keep up',
|
||||
[defines.disconnect_reason.afk] = ' was afk',
|
||||
[defines.disconnect_reason.kicked] = ' was kicked',
|
||||
[defines.disconnect_reason.kicked_and_deleted] = ' was kicked and deleted',
|
||||
[defines.disconnect_reason.banned] = ' was banned',
|
||||
[defines.disconnect_reason.switching_servers] = ' is switching servers'
|
||||
}
|
||||
}
|
||||
7
exp_legacy/module/config/miner.lua
Normal file
7
exp_legacy/module/config/miner.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
--- Settings for miner
|
||||
-- @config miner
|
||||
|
||||
return {
|
||||
fluid = true, --- @setting fluid When true, checks for for fluid pipes when removing miners
|
||||
chest = true --- @setting chest When true, checks for for chest when removing miners
|
||||
}
|
||||
98
exp_legacy/module/config/module.lua
Normal file
98
exp_legacy/module/config/module.lua
Normal file
@@ -0,0 +1,98 @@
|
||||
return {
|
||||
-- type of machine to handle together
|
||||
default_module_row_count = 9,
|
||||
module_slot_max = 4,
|
||||
copy_paste_module = true,
|
||||
copy_paste_rotation = false,
|
||||
machine = {
|
||||
['electric-mining-drill'] = {
|
||||
['module'] = 'effectivity-module',
|
||||
['prod'] = true
|
||||
},
|
||||
['pumpjack'] = {
|
||||
['module'] = 'effectivity-module',
|
||||
['prod'] = true
|
||||
},
|
||||
['assembling-machine-2'] = {
|
||||
['module'] = 'productivity-module',
|
||||
['prod'] = true
|
||||
},
|
||||
['assembling-machine-3'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['electric-furnace'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['beacon'] = {
|
||||
['module'] = 'speed-module-3',
|
||||
['prod'] = false
|
||||
},
|
||||
['oil-refinery'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['chemical-plant'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['centrifuge'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['lab'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
},
|
||||
['rocket-silo'] = {
|
||||
['module'] = 'productivity-module-3',
|
||||
['prod'] = true
|
||||
}
|
||||
},
|
||||
module_allowed = {
|
||||
['advanced-circuit'] = true,
|
||||
['automation-science-pack'] = true,
|
||||
['battery'] = true,
|
||||
['chemical-science-pack'] = true,
|
||||
['copper-cable'] = true,
|
||||
['copper-plate'] = true,
|
||||
['electric-engine-unit'] = true,
|
||||
['electronic-circuit'] = true,
|
||||
['empty-barrel'] = true,
|
||||
['engine-unit'] = true,
|
||||
['explosives'] = true,
|
||||
['flying-robot-frame'] = true,
|
||||
['iron-gear-wheel'] = true,
|
||||
['iron-plate'] = true,
|
||||
['iron-stick'] = true,
|
||||
['logistic-science-pack'] = true,
|
||||
['low-density-structure'] = true,
|
||||
['lubricant'] = true,
|
||||
['military-science-pack'] = true,
|
||||
['nuclear-fuel'] = true,
|
||||
['plastic-bar'] = true,
|
||||
['processing-unit'] = true,
|
||||
['production-science-pack'] = true,
|
||||
['rocket-control-unit'] = true,
|
||||
['rocket-fuel'] = true,
|
||||
['rocket-part'] = true,
|
||||
['steel-plate'] = true,
|
||||
['stone-brick'] = true,
|
||||
['sulfur'] = true,
|
||||
['sulfuric-acid'] = true,
|
||||
['uranium-fuel-cell'] = true,
|
||||
['utility-science-pack'] = true,
|
||||
['basic-oil-processing'] = true,
|
||||
['advanced-oil-processing'] = true,
|
||||
['coal-liquefaction'] = true,
|
||||
['heavy-oil-cracking'] = true,
|
||||
['light-oil-cracking'] = true,
|
||||
['solid-fuel-from-light-oil'] = true,
|
||||
['solid-fuel-from-petroleum-gas'] = true,
|
||||
['solid-fuel-from-heavy-oil'] = true,
|
||||
['uranium-processing'] = true,
|
||||
['nuclear-fuel-reprocessing'] = true,
|
||||
['kovarex-enrichment-process'] = true
|
||||
}
|
||||
}
|
||||
34
exp_legacy/module/config/nukeprotect.lua
Normal file
34
exp_legacy/module/config/nukeprotect.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
return {
|
||||
inventories = {
|
||||
{
|
||||
inventory = defines.inventory.character_ammo,
|
||||
event = defines.events.on_player_ammo_inventory_changed,
|
||||
items = {
|
||||
["atomic-bomb"] = true
|
||||
},
|
||||
},
|
||||
{
|
||||
inventory = defines.inventory.character_armor,
|
||||
event = defines.events.on_player_armor_inventory_changed,
|
||||
items = {},
|
||||
},
|
||||
{
|
||||
inventory = defines.inventory.character_guns,
|
||||
event = defines.events.on_player_gun_inventory_changed,
|
||||
items = {},
|
||||
},
|
||||
{
|
||||
inventory = defines.inventory.character_main,
|
||||
event = defines.events.on_player_main_inventory_changed,
|
||||
items = {
|
||||
["atomic-bomb"] = true
|
||||
},
|
||||
},
|
||||
},
|
||||
ignore_permisison = "bypass-nukeprotect", -- @setting ignore_permisison The permission that nukeprotect will ignore
|
||||
ignore_admins = true, -- @setting ignore_admins Ignore admins, true by default. Allows usage outside of the roles module
|
||||
disable_nuke_research = false, -- @setting disable_nuke_research Disable the nuke research, true by default
|
||||
disable_nuke_research_names = {
|
||||
["atomic-bomb"] = true
|
||||
} -- @setting disable_nuke_research_names The names of the researches to disabled
|
||||
}
|
||||
1640
exp_legacy/module/config/personal_logistic.lua
Normal file
1640
exp_legacy/module/config/personal_logistic.lua
Normal file
File diff suppressed because it is too large
Load Diff
9
exp_legacy/module/config/pollution_grading.lua
Normal file
9
exp_legacy/module/config/pollution_grading.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
--- This controls how pollution is viewed on the map
|
||||
-- @config Pollution-Grading
|
||||
|
||||
return {
|
||||
reference_point = {x=0,y=0}, --- @setting reference_point where pollution is read from
|
||||
max_scalar = 0.5, --- @setting max_scalar the scale between true max and max
|
||||
min_scalar = 0.17, --- @setting min_scalar the scale between the lowest max and min
|
||||
update_delay = 15 --- @setting update_delay time in minutes between view updates
|
||||
}
|
||||
10
exp_legacy/module/config/popup_messages.lua
Normal file
10
exp_legacy/module/config/popup_messages.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
--- A combination of config settings for different popup values like chat and damage
|
||||
-- @config Popup-Messages
|
||||
|
||||
return {
|
||||
show_player_messages=true, --- @setting show_player_messages weather a message in chat will make a popup above them
|
||||
show_player_mentions=true, --- @setting show_player_mentions weather a mentioned player will have a popup when mentioned in chat
|
||||
show_player_damage=true, --- @setting show_player_damage weather to show damage done by players
|
||||
show_player_health=true, --- @setting show_player_health weather to show player health when attacked
|
||||
damage_location_variance=0.8 --- @setting damage_location_variance how close to the eade of an entity the popups will appear
|
||||
}
|
||||
33
exp_legacy/module/config/preset_player_colours.lua
Normal file
33
exp_legacy/module/config/preset_player_colours.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
--- Preset colours that players get when they join the server, if not in the list then will be given a random colour (which isnt disallowed)
|
||||
-- @config Preset-Player-Colours
|
||||
|
||||
return {
|
||||
players={ --- @setting players list of all players and the colour in rgb256 that they will recive upon joining
|
||||
PHIDIAS0303={r=255,g=255,b=255},
|
||||
BADgamerNL={r=255,g=20,b=147},
|
||||
arty714={r=150,g=68,b=161},
|
||||
Cooldude2606={r=57,g=192,b=207},
|
||||
mark9064={r=99,g=0,b=255},
|
||||
eissturm={r=25,g=25,b=112},
|
||||
Sakama={r=20,g=213,b=80},
|
||||
freek18={r=50,g=0,b=255},
|
||||
aldldl={r=0,g=131,b=255},
|
||||
NAD4X4={r=135,g=206,b=250},
|
||||
cydes={r=82,g=249,b=155},
|
||||
UUBlueFire={r=0,g=204,b=255},
|
||||
CmonMate497={r=103,g=224,b=194},
|
||||
s4sh={r=255,g=120,b=0},
|
||||
ArPiiX={r=0,g=255,b=0},
|
||||
NextIdea={r=255,g=255,b=255},
|
||||
hamsterbryan={r=0,g=255,b=0},
|
||||
XenoCyber={r=0,g=128,b=255}
|
||||
},
|
||||
disallow = { --- @setting disallow colours which will not given to players; the value does not matter it is only the key which is checked
|
||||
black = {r = 0, g = 0, b = 0},
|
||||
white = {r = 255, g = 255, b = 255},
|
||||
success = {r = 0, g = 255, b = 0},
|
||||
warning = {r = 255, g = 255, b = 0},
|
||||
fail = {r = 255, g = 0, b = 0},
|
||||
info = {r = 255, g = 255, b = 255}
|
||||
}
|
||||
}
|
||||
6
exp_legacy/module/config/preset_player_quickbar.lua
Normal file
6
exp_legacy/module/config/preset_player_quickbar.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
--- Preset quickbar items that players can load
|
||||
-- @config Preset-Player-Quickbar
|
||||
|
||||
return {
|
||||
dangerarea = {"transport-belt", "underground-belt", "splitter", "pipe", "pipe-to-ground", "inserter", "fast-inserter", "long-handed-inserter", "stack-inserter", "roboport", "small-electric-pole", "medium-electric-pole", "big-electric-pole", "substation", nil, "rail", "rail-signal", "rail-chain-signal", "landfill", "cliff-explosives", "fast-transport-belt", "fast-underground-belt", "fast-splitter", "pipe", "pipe-to-ground", "fast-inserter", "long-handed-inserter", "stack-inserter", "stack-filter-inserter", "roboport", [81] = "red-wire", [82] = "green-wire", [83] = "arithmetic-combinator", [84] = "decider-combinator", [85] = "constant-combinator", [86] = "power-switch", [91] = "logistic-chest-active-provider", [92] = "logistic-chest-passive-provider", [93] = "logistic-chest-storage", [94] = "logistic-chest-buffer", [95] = "logistic-chest-requester", [96] = "roboport"}
|
||||
}
|
||||
19
exp_legacy/module/config/protection.lua
Normal file
19
exp_legacy/module/config/protection.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
return {
|
||||
ignore_admins = true, --- @setting ignore_admins If admins are ignored by the protection filter
|
||||
ignore_permission = 'bypass-entity-protection', --- @setting ignore_permission Players with this permission will be ignored by the protection filter, leave nil if expcore.roles is not used
|
||||
repeat_count = 5, --- @setting repeat_count Number of protected entities that must be removed within repeat_lifetime in order to trigger repeated removal protection
|
||||
repeat_lifetime = 3600*20, --- @setting repeat_lifetime The length of time, in ticks, that protected removals will be remembered for
|
||||
refresh_rate = 3600*5, --- @setting refresh_rate How often the age of protected removals are checked against repeat_lifetime
|
||||
always_protected_names = { --- @setting always_protected_names Names of entities which are always protected
|
||||
|
||||
},
|
||||
always_protected_types = { --- @setting always_protected_types Types of entities which are always protected
|
||||
'boiler', 'generator', 'offshore-pump', 'power-switch', 'reactor', 'rocket-silo'
|
||||
},
|
||||
always_trigger_repeat_names = { --- @setting always_trigger_repeat_names Names of entities which always trigger repeated removal protection
|
||||
|
||||
},
|
||||
always_trigger_repeat_types = { --- @setting always_trigger_repeat_types Types of entities which always trigger repeated removal protection
|
||||
'reactor', 'rocket-silo'
|
||||
}
|
||||
}
|
||||
16
exp_legacy/module/config/repair.lua
Normal file
16
exp_legacy/module/config/repair.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
--- Config file for the repair command
|
||||
-- @config Repair
|
||||
|
||||
return {
|
||||
disallow = { --- @setting disallow items in this list will never be repaired
|
||||
['loader']=true,
|
||||
['fast-loader']=true,
|
||||
['express-loader']=true,
|
||||
['electric-energy-interface']=true,
|
||||
['infinity-chest']=true
|
||||
},
|
||||
max_range=50, --- @setting max_range the max range that can be used with the repair command
|
||||
allow_blueprint_repair=false, --- @setting allow_blueprint_repair when true will allow blueprints (things not destroyed by biters) to be build instantly using the repair command
|
||||
allow_ghost_revive=true, --- @setting allow_ghost_revive when true will allow ghosts (things destroyed by biters) to be build instantly using the repair command
|
||||
allow_heal_entities=true --- @setting allow_heal_entities when true will heal entities to full health that are within range
|
||||
}
|
||||
81
exp_legacy/module/config/research.lua
Normal file
81
exp_legacy/module/config/research.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
--- Res Settings
|
||||
-- @config Research
|
||||
|
||||
return {
|
||||
enabled = true,
|
||||
pollution_ageing_by_research = false,
|
||||
queue_amount = 3,
|
||||
-- this enable 20 more inventory for each mining productivity level up to 4
|
||||
bonus_inventory = {
|
||||
enabled = true,
|
||||
name = 'character_inventory_slots_bonus',
|
||||
rate = 5,
|
||||
limit = 20
|
||||
},
|
||||
file_name = 'log/research.log',
|
||||
milestone = {
|
||||
['automation'] = 600,
|
||||
['logistics'] = 300,
|
||||
['steel-processing'] = 300,
|
||||
['logistic-science-pack'] = 300,
|
||||
['electronics'] = 300,
|
||||
['fast-inserter'] = 300,
|
||||
['steel-axe'] = 300,
|
||||
['automation-2'] = 300,
|
||||
['advanced-material-processing'] = 300,
|
||||
['engine'] = 300,
|
||||
['fluid-handling'] = 300,
|
||||
['oil-processing'] = 300,
|
||||
['sulfur-processing'] = 300,
|
||||
['plastics'] = 300,
|
||||
['advanced-electronics'] = 300,
|
||||
['chemical-science-pack'] = 300,
|
||||
['modules'] = 300,
|
||||
['logistics-2'] = 300,
|
||||
['railway'] = 300,
|
||||
['research-speed-1'] = 300,
|
||||
['research-speed-2'] = 300,
|
||||
['battery'] = 300,
|
||||
['concrete'] = 300,
|
||||
['flammables'] = 300,
|
||||
['low-density-structure'] = 300,
|
||||
['advanced-material-processing-2'] = 300,
|
||||
['productivity-module'] = 300,
|
||||
['production-science-pack'] = 300,
|
||||
['advanced-electronics-2'] = 300,
|
||||
['advanced-oil-processing'] = 300,
|
||||
['electric-engine'] = 300,
|
||||
['robotics'] = 300,
|
||||
['construction-robotics'] = 300,
|
||||
['worker-robots-speed-1'] = 300,
|
||||
['worker-robots-speed-2'] = 300,
|
||||
['utility-science-pack'] = 300,
|
||||
['productivity-module-2'] = 300,
|
||||
['speed-module-2'] = 300,
|
||||
['rocket-fuel'] = 300,
|
||||
['effect-transmission'] = 300,
|
||||
['productivity-module-3'] = 300,
|
||||
['rocket-control-unit'] = 300,
|
||||
['speed-module-3'] = 300,
|
||||
['rocket-silo'] = 300,
|
||||
['space-science-pack'] = 300,
|
||||
},
|
||||
inf_res = {
|
||||
-- Mining Productivity
|
||||
['mining-productivity-4'] = 4,
|
||||
-- Robot Speed
|
||||
['worker-robots-speed-6'] = 6,
|
||||
-- Laser Damage
|
||||
['energy-weapons-damage-7'] = 7,
|
||||
-- Explosive Damage
|
||||
['stronger-explosives-7'] = 7,
|
||||
-- Bullet Damage
|
||||
['physical-projectile-damage-7'] = 7,
|
||||
-- Flame Damage
|
||||
['refined-flammables-7'] = 7,
|
||||
-- Artillery Range
|
||||
['artillery-shell-range-1'] = 1,
|
||||
-- Artillery Speed
|
||||
['artillery-shell-speed-1'] = 1
|
||||
}
|
||||
}
|
||||
116
exp_legacy/module/config/scorched_earth.lua
Normal file
116
exp_legacy/module/config/scorched_earth.lua
Normal file
@@ -0,0 +1,116 @@
|
||||
--- This file controls the placement/degrading of tiles as players build and walk
|
||||
-- @config Scorched-Earth
|
||||
|
||||
return {
|
||||
weakness_value=70, --- @setting weakness_value lower value will make tiles more likely to degrade
|
||||
strengths={ --- @setting strengths this decides how "strong" a tile is, bigger number means less likely to degrade
|
||||
-- debug: /interface require('modules.addons.worn-paths')(player.name,true)
|
||||
-- note: tiles are effected by the tiles around them, so player paths will not degrade as fast when made wider
|
||||
-- note: values are relative to the tile with the highest value, recommended to keep highest tile as a "nice" number
|
||||
-- note: tiles not in list will never degrade under any conditions (which is why some are omitted such as water)
|
||||
["refined-concrete"]=100,
|
||||
["refined-hazard-concrete-left"]=100,
|
||||
["refined-hazard-concrete-right"]=100,
|
||||
["concrete"]=90,
|
||||
["hazard-concrete-left"]=90,
|
||||
["hazard-concrete-right"]=90,
|
||||
["stone-path"]=80,
|
||||
["red-desert-0"]=80,
|
||||
["dry-dirt"]=50,
|
||||
-- grass four (main grass tiles)
|
||||
["grass-1"]=50,
|
||||
["grass-2"]=40,
|
||||
["grass-3"]=30,
|
||||
["grass-4"]=25,
|
||||
-- red three (main red tiles)
|
||||
["red-desert-1"]=40,
|
||||
["red-desert-2"]=30,
|
||||
["red-desert-3"]=25,
|
||||
-- sand three (main sand tiles)
|
||||
["sand-1"]=40,
|
||||
["sand-2"]=30,
|
||||
["sand-3"]=25,
|
||||
-- dirt 3 (main dirt tiles)
|
||||
["dirt-1"]=40,
|
||||
["dirt-2"]=30,
|
||||
["dirt-3"]=25,
|
||||
-- last three/four (all sets of three merge here)
|
||||
["dirt-4"]=25,
|
||||
["dirt-5"]=30,
|
||||
["dirt-6"]=40,
|
||||
--["dirt-7"]=0, -- last tile, nothing to degrade to
|
||||
-- land fill chain
|
||||
-- ["landfill"]=50,
|
||||
--["water-shallow"]=90,
|
||||
--["water-mud"]=0, -- last tile, nothing to degrade to
|
||||
},
|
||||
degrade_order={ --- @setting degrade_order when a tile degrades it will turn into the next tile given here
|
||||
["refined-concrete"]='concrete',
|
||||
["refined-hazard-concrete-left"]='hazard-concrete-left',
|
||||
["refined-hazard-concrete-right"]='hazard-concrete-right',
|
||||
["concrete"]='stone-path',
|
||||
["hazard-concrete-left"]='stone-path',
|
||||
["hazard-concrete-right"]='stone-path',
|
||||
["stone-path"]='dry-dirt',
|
||||
["red-desert-0"]='dry-dirt',
|
||||
["dry-dirt"]='dirt-4',
|
||||
-- grass four (main grass tiles)
|
||||
["grass-1"]='grass-2',
|
||||
["grass-2"]='grass-3',
|
||||
["grass-3"]='grass-4',
|
||||
["grass-4"]='dirt-4',
|
||||
-- red three (main red tiles)
|
||||
["red-desert-1"]='red-desert-2',
|
||||
["red-desert-2"]='red-desert-3',
|
||||
["red-desert-3"]='dirt-4',
|
||||
-- sand three (main sand tiles)
|
||||
["sand-1"]='sand-2',
|
||||
["sand-2"]='sand-3',
|
||||
["sand-3"]='dirt-4',
|
||||
-- dirt 3 (main dirt tiles)
|
||||
["dirt-1"]='dirt-2',
|
||||
["dirt-2"]='dirt-3',
|
||||
["dirt-3"]='dirt-4',
|
||||
-- last three/four (all sets of three merge here)
|
||||
["dirt-4"]='dirt-5',
|
||||
["dirt-5"]='dirt-6',
|
||||
["dirt-6"]='dirt-7',
|
||||
--["dirt-7"]=0, -- last tile, nothing to degrade to
|
||||
-- land fill chain
|
||||
-- ["landfill"]='grass-2', -- 'water-shallow'
|
||||
--["water-shallow"]='water-mud',
|
||||
--["water-mud"]=0, -- last tile, nothing to degrade to
|
||||
},
|
||||
entities={ --- @setting entities entities in this list will degrade the tiles under them when they are placed
|
||||
['stone-furnace']=true,
|
||||
['steel-furnace']=true,
|
||||
['electric-furnace']=true,
|
||||
['assembling-machine-1']=true,
|
||||
['assembling-machine-2']=true,
|
||||
['assembling-machine-3']=true,
|
||||
['beacon']=true,
|
||||
['centrifuge']=true,
|
||||
['chemical-plant']=true,
|
||||
['oil-refinery']=true,
|
||||
['storage-tank']=true,
|
||||
['nuclear-reactor']=true,
|
||||
['steam-engine']=true,
|
||||
['steam-turbine']=true,
|
||||
['boiler']=true,
|
||||
['heat-exchanger']=true,
|
||||
['stone-wall']=true,
|
||||
['gate']=true,
|
||||
['gun-turret']=true,
|
||||
['laser-turret']=true,
|
||||
['flamethrower-turret']=true,
|
||||
['radar']=true,
|
||||
['lab']=true,
|
||||
['big-electric-pole']=true,
|
||||
['substation']=true,
|
||||
['rocket-silo']=true,
|
||||
['pumpjack']=true,
|
||||
['electric-mining-drill']=true,
|
||||
['roboport']=true,
|
||||
['accumulator']=true
|
||||
}
|
||||
}
|
||||
254
exp_legacy/module/config/spawn_area.lua
Normal file
254
exp_legacy/module/config/spawn_area.lua
Normal file
@@ -0,0 +1,254 @@
|
||||
--- Used to config the spawn generation settings yes there is alot here i know just ignore the long tables at the end (they were generated with a command)
|
||||
-- @config Spawn-Area
|
||||
|
||||
return {
|
||||
spawn_area = { --- @setting spawn_area Settings relating to the whole spawn area
|
||||
-- Enable predefined patches: 128, else: 32
|
||||
deconstruction_radius = 20, -- @setting deconstruction_radius All entities within this radius will be removed
|
||||
tile_radius = 20,
|
||||
deconstruction_tile = 'concrete', --- @setting deconstruction_tile Tile to be placed in the deconstruction radius, use nil for map gen
|
||||
landfill_radius = 50, --- @setting pattern_radius All water within this radius will be land filled
|
||||
},
|
||||
turrets = { --- @setting turrets Settings relating to adding turrets to spawn
|
||||
enabled = true, --- @setting enabled Whether turrets will be added to spawn
|
||||
ammo_type = 'uranium-rounds-magazine', --- @setting ammo_type The ammo type that will be used during refills
|
||||
refill_time = 60*60*5, --- @setting refill_time The time in ticks between each refill of the turrets, only change if having lag issues
|
||||
offset = {x=0, y=0}, --- @setting offset The position offset to apply to turrets
|
||||
locations = { --- @setting locations The locations of all turrets, this list can change during runtime
|
||||
{surface=1,position={x=-3,y=-3}},
|
||||
{surface=1,position={x=3,y=-3}},
|
||||
{surface=1,position={x=-3,y=3}},
|
||||
{surface=1,position={x=3,y=3}}
|
||||
}
|
||||
},
|
||||
afk_belts = { --- @setting afk_belts Settings relating to adding afk belts to spawn
|
||||
enabled = true, --- @setting enabled Whether afk belts will be added to spawn
|
||||
belt_type = 'transport-belt', --- @setting belt_type The belt to be used as afk belts
|
||||
protected = true, --- @setting protected Whether belts will be protected from player interaction
|
||||
offset = {x=0, y=0}, --- @setting offset The position offset to apply to afk belts
|
||||
locations={ --- @setting locations The locations to spawn afk belts at, given as the top left position
|
||||
{-5,-5}, {5,-5},
|
||||
{-5,5}, {5,5}
|
||||
}
|
||||
},
|
||||
water = { --- @setting water Settings relating to adding water to spawn
|
||||
enabled = true, --- @setting enabled Whether water tiles will be added to spawn
|
||||
water_tile = 'water-mud', --- @setting water_tile The tile to be used as the water tile
|
||||
offset = {x=0, y=0}, --- @setting offset The position offset to apply to water tiles
|
||||
locations = { --- @setting locations The location of the water tiles {x,y}
|
||||
-- Each is a 3x3 with the closest tile to 0,0 removed
|
||||
{7,8}, {7,9}, {8,7}, {8,8}, {8,9}, {9,7}, {9,8}, {9,9}, -- Bottom Right
|
||||
{7,-9}, {7,-10}, {8,-8}, {8,-9}, {8,-10}, {9,-8}, { 9,-9}, {9,-10}, -- Top Right
|
||||
{-8,-9}, {-8,-10}, {-9,-8}, {-9,-9}, {-9,-10}, {-10,-8}, {-10,-9}, {-10,-10}, -- Top Left
|
||||
{-8,8}, {-8,9}, {-9,7}, {-9,8}, {-9,9}, {-10,7}, {-10,8}, {-10,9}, -- Bottom Left
|
||||
}
|
||||
},
|
||||
entities = { --- @setting entities Settings relating to adding entities to spawn
|
||||
enabled = true, --- @setting enabled Whether entities will be added to spawn
|
||||
protected = true, --- @setting protected Whether entities will be protected from player interaction
|
||||
operable = true, --- @setting operable Whether entities can be opened by players, must be true if chests are used
|
||||
offset = {x=0, y=-2}, --- @setting offset The position offset to apply to entities
|
||||
locations = { --- @setting locations The location and names of entities {name,x,y}
|
||||
{'stone-wall',-10,-5},{'stone-wall',-10,-4},{'stone-wall',-10,-3},{'stone-wall',-10,-2},{'stone-wall',-10,-1},{'stone-wall',-10,0},{'stone-wall',-10,3},{'stone-wall',-10,4},{'stone-wall',-10,5},
|
||||
{'stone-wall',-10,6},{'stone-wall',-10,7},{'stone-wall',-10,8},{'small-lamp',-8,-4},{'small-lamp',-8,-1},{'iron-chest',-8,0},{'iron-chest',-8,3},{'small-lamp',-8,4},
|
||||
{'small-lamp',-8,7},{'stone-wall',-7,-8},{'small-electric-pole',-7,-2},{'iron-chest',-7,0},{'iron-chest',-7,3},{'small-electric-pole',-7,5},{'stone-wall',-7,11},{'stone-wall',-6,-8},{'small-lamp',-6,-6},
|
||||
{'iron-chest',-6,0},{'iron-chest',-6,3},{'small-lamp',-6,9},{'stone-wall',-6,11},{'stone-wall',-5,-8},{'small-lamp',-5,-1},{'iron-chest',-5,0},{'iron-chest',-5,3},{'small-lamp',-5,4},{'stone-wall',-5,11},
|
||||
{'stone-wall',-4,-8},{'small-electric-pole',-4,-5},{'iron-chest',-4,0},{'iron-chest',-4,3},{'small-electric-pole',-4,8},{'stone-wall',-4,11},{'stone-wall',-3,-8},{'small-lamp',-3,-6},{'small-lamp',-3,-3},{'small-lamp',-3,6},
|
||||
{'small-lamp',-3,9},{'stone-wall',-3,11},{'stone-wall',-2,-8},{'iron-chest',-2,-6},{'iron-chest',-2,-5},{'iron-chest',-2,-4},{'iron-chest',-2,-3},{'iron-chest',-2,-2},{'iron-chest',-2,5},{'iron-chest',-2,6},
|
||||
{'iron-chest',-2,7},{'iron-chest',-2,8},{'iron-chest',-2,9},{'stone-wall',-2,11},{'stone-wall',1,-8},{'iron-chest',1,-6},
|
||||
{'iron-chest',1,-5},{'iron-chest',1,-4},{'iron-chest',1,-3},{'iron-chest',1,-2},{'iron-chest',1,5},{'iron-chest',1,6},{'iron-chest',1,7},{'iron-chest',1,8},{'iron-chest',1,9},{'stone-wall',1,11},
|
||||
{'stone-wall',2,-8},{'small-lamp',2,-6},{'small-lamp',2,-3},{'small-lamp',2,6},{'small-lamp',2,9},{'stone-wall',2,11},{'stone-wall',3,-8},{'small-electric-pole',3,-5},{'iron-chest',3,0},{'iron-chest',3,3},
|
||||
{'small-electric-pole',3,8},{'stone-wall',3,11},{'stone-wall',4,-8},{'small-lamp',4,-1},{'iron-chest',4,0},{'iron-chest',4,3},{'small-lamp',4,4},{'stone-wall',4,11},{'stone-wall',5,-8},{'small-lamp',5,-6},
|
||||
{'iron-chest',5,0},{'iron-chest',5,3},{'small-lamp',5,9},{'stone-wall',5,11},{'stone-wall',6,-8},{'small-electric-pole',6,-2},{'iron-chest',6,0},{'iron-chest',6,3},{'small-electric-pole',6,5},{'stone-wall',6,11},
|
||||
{'small-lamp',7,-4},{'small-lamp',7,-1},{'iron-chest',7,0},{'iron-chest',7,3},{'small-lamp',7,4},{'small-lamp',7,7},{'stone-wall',9,-5},
|
||||
{'stone-wall',9,-4},{'stone-wall',9,-3},{'stone-wall',9,-2},{'stone-wall',9,-1},{'stone-wall',9,0},{'stone-wall',9,3},{'stone-wall',9,4},{'stone-wall',9,5},{'stone-wall',9,6},{'stone-wall',9,7},
|
||||
{'stone-wall',9,8}
|
||||
}
|
||||
},
|
||||
pattern = {
|
||||
enabled = true, --- @setting enabled Whether pattern tiles will be added to spawn
|
||||
pattern_tile = 'stone-path', --- @setting pattern_tile The tile to be used for the pattern
|
||||
offset = {x=0, y=-2}, --- @setting offset The position offset to apply to pattern tiles
|
||||
locations = { --- @setting locations The location of the pattern tiles {x,y}
|
||||
{-49,-3},{-49,-2},{-49,1},{-49,2},{-49,5},{-49,6},{-48,-4},{-48,-3},{-48,-2},{-48,1},{-48,2},{-48,5},{-48,6},{-48,7},{-47,-7},{-47,-6},{-47,-5},{-47,-4},{-47,-3},{-47,-2},{-47,5},{-47,6},{-47,7},{-47,8},{-47,9},{-47,10},{-46,-8},{-46,-7},{-46,-6},{-46,-5},
|
||||
{-46,-4},{-46,-3},{-46,-2},{-46,-1},{-46,4},{-46,5},{-46,6},{-46,7},{-46,8},{-46,9},{-46,10},{-46,11},{-45,-17},{-45,-16},{-45,-15},{-45,-14},{-45,-13},{-45,-12},{-45,-9},{-45,-8},{-45,-7},{-45,-2},{-45,-1},{-45,0},{-45,1},{-45,2},{-45,3},{-45,4},{-45,5},{-45,10},
|
||||
{-45,11},{-45,12},{-45,15},{-45,16},{-45,17},{-45,18},{-45,19},{-45,20},{-44,-18},{-44,-17},{-44,-16},{-44,-15},{-44,-14},{-44,-13},{-44,-12},{-44,-9},{-44,-8},{-44,-1},{-44,0},{-44,1},{-44,2},{-44,3},{-44,4},{-44,11},{-44,12},{-44,15},{-44,16},{-44,17},{-44,18},{-44,19},
|
||||
{-44,20},{-44,21},{-43,-19},{-43,-18},{-43,-17},{-43,-1},{-43,0},{-43,1},{-43,2},{-43,3},{-43,4},{-43,20},{-43,21},{-43,22},{-42,-19},{-42,-18},{-42,-1},{-42,0},{-42,1},{-42,2},{-42,3},{-42,4},{-42,21},{-42,22},{-41,-25},{-41,-24},{-41,-19},{-41,-18},{-41,-13},{-41,-12},
|
||||
{-41,-11},{-41,-10},{-41,-5},{-41,-4},{-41,7},{-41,8},{-41,13},{-41,14},{-41,15},{-41,16},{-41,21},{-41,22},{-41,27},{-41,28},{-40,-26},{-40,-25},{-40,-24},{-40,-20},{-40,-19},{-40,-18},{-40,-13},{-40,-12},{-40,-11},{-40,-10},{-40,-5},{-40,-4},{-40,7},{-40,8},{-40,13},{-40,14},
|
||||
{-40,15},{-40,16},{-40,21},{-40,22},{-40,23},{-40,27},{-40,28},{-40,29},{-39,-27},{-39,-26},{-39,-25},{-39,-24},{-39,-21},{-39,-20},{-39,-19},{-39,-13},{-39,-12},{-39,-5},{-39,-4},{-39,-3},{-39,-2},{-39,-1},{-39,0},{-39,1},{-39,2},{-39,3},{-39,4},{-39,5},{-39,6},{-39,7},
|
||||
{-39,8},{-39,15},{-39,16},{-39,22},{-39,23},{-39,24},{-39,27},{-39,28},{-39,29},{-39,30},{-38,-27},{-38,-26},{-38,-25},{-38,-24},{-38,-21},{-38,-20},{-38,-13},{-38,-12},{-38,-5},{-38,-4},{-38,-3},{-38,-2},{-38,-1},{-38,0},{-38,1},{-38,2},{-38,3},{-38,4},{-38,5},{-38,6},
|
||||
{-38,7},{-38,8},{-38,15},{-38,16},{-38,23},{-38,24},{-38,27},{-38,28},{-38,29},{-38,30},{-37,-17},{-37,-16},{-37,-13},{-37,-12},{-37,-11},{-37,-10},{-37,-4},{-37,-3},{-37,-2},{-37,-1},{-37,0},{-37,3},{-37,4},{-37,5},{-37,6},{-37,7},{-37,13},{-37,14},{-37,15},{-37,16},
|
||||
{-37,19},{-37,20},{-36,-17},{-36,-16},{-36,-13},{-36,-12},{-36,-11},{-36,-10},{-36,-9},{-36,-3},{-36,-2},{-36,-1},{-36,0},{-36,3},{-36,4},{-36,5},{-36,6},{-36,12},{-36,13},{-36,14},{-36,15},{-36,16},{-36,19},{-36,20},{-35,-29},{-35,-28},{-35,-23},{-35,-22},{-35,-17},{-35,-16},
|
||||
{-35,-12},{-35,-11},{-35,-10},{-35,-9},{-35,-8},{-35,11},{-35,12},{-35,13},{-35,14},{-35,15},{-35,19},{-35,20},{-35,25},{-35,26},{-35,31},{-35,32},{-34,-30},{-34,-29},{-34,-28},{-34,-23},{-34,-22},{-34,-17},{-34,-16},{-34,-15},{-34,-11},{-34,-10},{-34,-9},{-34,-8},{-34,11},{-34,12},
|
||||
{-34,13},{-34,14},{-34,18},{-34,19},{-34,20},{-34,25},{-34,26},{-34,31},{-34,32},{-34,33},{-33,-31},{-33,-30},{-33,-29},{-33,-28},{-33,-23},{-33,-22},{-33,-16},{-33,-15},{-33,-14},{-33,-5},{-33,-4},{-33,-1},{-33,0},{-33,3},{-33,4},{-33,7},{-33,8},{-33,17},{-33,18},{-33,19},
|
||||
{-33,25},{-33,26},{-33,31},{-33,32},{-33,33},{-33,34},{-32,-32},{-32,-31},{-32,-30},{-32,-29},{-32,-28},{-32,-27},{-32,-23},{-32,-22},{-32,-21},{-32,-15},{-32,-14},{-32,-6},{-32,-5},{-32,-4},{-32,-1},{-32,0},{-32,3},{-32,4},{-32,7},{-32,8},{-32,9},{-32,17},{-32,18},{-32,24},
|
||||
{-32,25},{-32,26},{-32,30},{-32,31},{-32,32},{-32,33},{-32,34},{-32,35},{-31,-33},{-31,-32},{-31,-31},{-31,-30},{-31,-29},{-31,-28},{-31,-27},{-31,-26},{-31,-22},{-31,-21},{-31,-20},{-31,-19},{-31,-18},{-31,-11},{-31,-10},{-31,-9},{-31,-8},{-31,-7},{-31,-6},{-31,-5},{-31,-1},{-31,0},
|
||||
{-31,1},{-31,2},{-31,3},{-31,4},{-31,8},{-31,9},{-31,10},{-31,11},{-31,12},{-31,13},{-31,14},{-31,21},{-31,22},{-31,23},{-31,24},{-31,25},{-31,29},{-31,30},{-31,31},{-31,32},{-31,33},{-31,34},{-31,35},{-31,36},{-30,-33},{-30,-32},{-30,-31},{-30,-30},{-30,-29},{-30,-28},
|
||||
{-30,-27},{-30,-26},{-30,-21},{-30,-20},{-30,-19},{-30,-18},{-30,-11},{-30,-10},{-30,-9},{-30,-8},{-30,-7},{-30,-6},{-30,-1},{-30,0},{-30,1},{-30,2},{-30,3},{-30,4},{-30,9},{-30,10},{-30,11},{-30,12},{-30,13},{-30,14},{-30,21},{-30,22},{-30,23},{-30,24},{-30,29},{-30,30},
|
||||
{-30,31},{-30,32},{-30,33},{-30,34},{-30,35},{-30,36},{-29,-37},{-29,-36},{-29,-30},{-29,-29},{-29,-28},{-29,-27},{-29,-26},{-29,-15},{-29,-14},{-29,-10},{-29,-9},{-29,-8},{-29,-7},{-29,10},{-29,11},{-29,12},{-29,13},{-29,17},{-29,18},{-29,29},{-29,30},{-29,31},{-29,32},{-29,33},
|
||||
{-29,39},{-29,40},{-28,-38},{-28,-37},{-28,-36},{-28,-29},{-28,-28},{-28,-27},{-28,-26},{-28,-16},{-28,-15},{-28,-14},{-28,-9},{-28,-8},{-28,11},{-28,12},{-28,17},{-28,18},{-28,19},{-28,29},{-28,30},{-28,31},{-28,32},{-28,39},{-28,40},{-28,41},{-27,-39},{-27,-38},{-27,-37},{-27,-36},
|
||||
{-27,-23},{-27,-22},{-27,-19},{-27,-18},{-27,-17},{-27,-16},{-27,-15},{-27,-5},{-27,-4},{-27,-1},{-27,0},{-27,1},{-27,2},{-27,3},{-27,4},{-27,7},{-27,8},{-27,18},{-27,19},{-27,20},{-27,21},{-27,22},{-27,25},{-27,26},{-27,39},{-27,40},{-27,41},{-27,42},{-26,-39},{-26,-38},
|
||||
{-26,-37},{-26,-36},{-26,-24},{-26,-23},{-26,-22},{-26,-19},{-26,-18},{-26,-17},{-26,-16},{-26,-6},{-26,-5},{-26,-4},{-26,-1},{-26,0},{-26,1},{-26,2},{-26,3},{-26,4},{-26,7},{-26,8},{-26,9},{-26,19},{-26,20},{-26,21},{-26,22},{-26,25},{-26,26},{-26,27},{-26,39},{-26,40},
|
||||
{-26,41},{-26,42},{-25,-33},{-25,-32},{-25,-31},{-25,-30},{-25,-25},{-25,-24},{-25,-23},{-25,-22},{-25,-19},{-25,-18},{-25,-17},{-25,-9},{-25,-8},{-25,-7},{-25,-6},{-25,-5},{-25,-4},{-25,-1},{-25,0},{-25,1},{-25,2},{-25,3},{-25,4},{-25,7},{-25,8},{-25,9},{-25,10},{-25,11},
|
||||
{-25,12},{-25,20},{-25,21},{-25,22},{-25,25},{-25,26},{-25,27},{-25,28},{-25,33},{-25,34},{-25,35},{-25,36},{-24,-33},{-24,-32},{-24,-31},{-24,-30},{-24,-29},{-24,-25},{-24,-24},{-24,-23},{-24,-22},{-24,-19},{-24,-18},{-24,-9},{-24,-8},{-24,-7},{-24,-6},{-24,-5},{-24,-4},{-24,-1},
|
||||
{-24,0},{-24,1},{-24,2},{-24,3},{-24,4},{-24,7},{-24,8},{-24,9},{-24,10},{-24,11},{-24,12},{-24,21},{-24,22},{-24,25},{-24,26},{-24,27},{-24,28},{-24,32},{-24,33},{-24,34},{-24,35},{-24,36},{-23,-37},{-23,-36},{-23,-30},{-23,-29},{-23,-28},{-23,-19},{-23,-18},{-23,-15},
|
||||
{-23,-14},{-23,-9},{-23,-8},{-23,-7},{-23,-6},{-23,-5},{-23,0},{-23,1},{-23,2},{-23,3},{-23,8},{-23,9},{-23,10},{-23,11},{-23,12},{-23,17},{-23,18},{-23,21},{-23,22},{-23,31},{-23,32},{-23,33},{-23,39},{-23,40},{-22,-38},{-22,-37},{-22,-36},{-22,-29},{-22,-28},{-22,-19},
|
||||
{-22,-18},{-22,-15},{-22,-14},{-22,-13},{-22,-9},{-22,-8},{-22,-7},{-22,-6},{-22,1},{-22,2},{-22,9},{-22,10},{-22,11},{-22,12},{-22,16},{-22,17},{-22,18},{-22,21},{-22,22},{-22,31},{-22,32},{-22,39},{-22,40},{-22,41},{-21,-41},{-21,-40},{-21,-39},{-21,-38},{-21,-37},{-21,-29},
|
||||
{-21,-28},{-21,-25},{-21,-24},{-21,-23},{-21,-22},{-21,-21},{-21,-20},{-21,-19},{-21,-18},{-21,-15},{-21,-14},{-21,-13},{-21,-12},{-21,-3},{-21,-2},{-21,5},{-21,6},{-21,15},{-21,16},{-21,17},{-21,18},{-21,21},{-21,22},{-21,23},{-21,24},{-21,25},{-21,26},{-21,27},{-21,28},{-21,31},
|
||||
{-21,32},{-21,40},{-21,41},{-21,42},{-21,43},{-21,44},{-20,-42},{-20,-41},{-20,-40},{-20,-39},{-20,-38},{-20,-29},{-20,-28},{-20,-25},{-20,-24},{-20,-23},{-20,-22},{-20,-21},{-20,-20},{-20,-19},{-20,-18},{-20,-15},{-20,-14},{-20,-13},{-20,-12},{-20,-3},{-20,-2},{-20,-1},{-20,4},{-20,5},
|
||||
{-20,6},{-20,15},{-20,16},{-20,17},{-20,18},{-20,21},{-20,22},{-20,23},{-20,24},{-20,25},{-20,26},{-20,27},{-20,28},{-20,31},{-20,32},{-20,41},{-20,42},{-20,43},{-20,44},{-20,45},{-19,-43},{-19,-42},{-19,-41},{-19,-35},{-19,-34},{-19,-33},{-19,-32},{-19,-25},{-19,-24},{-19,-23},
|
||||
{-19,-15},{-19,-14},{-19,-13},{-19,-9},{-19,-8},{-19,-7},{-19,-6},{-19,-2},{-19,-1},{-19,0},{-19,1},{-19,2},{-19,3},{-19,4},{-19,5},{-19,9},{-19,10},{-19,11},{-19,12},{-19,16},{-19,17},{-19,18},{-19,26},{-19,27},{-19,28},{-19,35},{-19,36},{-19,37},{-19,38},{-19,44},
|
||||
{-19,45},{-19,46},{-18,-43},{-18,-42},{-18,-35},{-18,-34},{-18,-33},{-18,-32},{-18,-31},{-18,-26},{-18,-25},{-18,-24},{-18,-15},{-18,-14},{-18,-10},{-18,-9},{-18,-8},{-18,-7},{-18,-6},{-18,-1},{-18,0},{-18,1},{-18,2},{-18,3},{-18,4},{-18,9},{-18,10},{-18,11},{-18,12},{-18,13},
|
||||
{-18,17},{-18,18},{-18,27},{-18,28},{-18,29},{-18,34},{-18,35},{-18,36},{-18,37},{-18,38},{-18,45},{-18,46},{-17,-43},{-17,-42},{-17,-32},{-17,-31},{-17,-30},{-17,-27},{-17,-26},{-17,-25},{-17,-21},{-17,-20},{-17,-19},{-17,-18},{-17,-17},{-17,-16},{-17,-15},{-17,-14},{-17,-11},{-17,-10},
|
||||
{-17,-9},{-17,-8},{-17,-7},{-17,-6},{-17,0},{-17,1},{-17,2},{-17,3},{-17,9},{-17,10},{-17,11},{-17,12},{-17,13},{-17,14},{-17,17},{-17,18},{-17,19},{-17,20},{-17,21},{-17,22},{-17,23},{-17,24},{-17,28},{-17,29},{-17,30},{-17,33},{-17,34},{-17,35},{-17,45},{-17,46},
|
||||
{-16,-43},{-16,-42},{-16,-31},{-16,-30},{-16,-27},{-16,-26},{-16,-21},{-16,-20},{-16,-19},{-16,-18},{-16,-17},{-16,-16},{-16,-15},{-16,-14},{-16,-11},{-16,-10},{-16,-9},{-16,-8},{-16,-7},{-16,-6},{-16,1},{-16,2},{-16,9},{-16,10},{-16,11},{-16,12},{-16,13},{-16,14},{-16,17},{-16,18},
|
||||
{-16,19},{-16,20},{-16,21},{-16,22},{-16,23},{-16,24},{-16,29},{-16,30},{-16,33},{-16,34},{-16,45},{-16,46},{-15,-43},{-15,-42},{-15,-39},{-15,-38},{-15,-37},{-15,-36},{-15,-35},{-15,-34},{-15,-20},{-15,-19},{-15,-18},{-15,-17},{-15,-10},{-15,-9},{-15,-8},{-15,-7},{-15,-3},{-15,-2},
|
||||
{-15,1},{-15,2},{-15,5},{-15,6},{-15,10},{-15,11},{-15,12},{-15,13},{-15,20},{-15,21},{-15,22},{-15,23},{-15,37},{-15,38},{-15,39},{-15,40},{-15,41},{-15,42},{-15,45},{-15,46},{-14,-43},{-14,-42},{-14,-39},{-14,-38},{-14,-37},{-14,-36},{-14,-35},{-14,-34},{-14,-33},{-14,-19},
|
||||
{-14,-18},{-14,-9},{-14,-8},{-14,-4},{-14,-3},{-14,-2},{-14,1},{-14,2},{-14,5},{-14,6},{-14,7},{-14,11},{-14,12},{-14,21},{-14,22},{-14,36},{-14,37},{-14,38},{-14,39},{-14,40},{-14,41},{-14,42},{-14,45},{-14,46},{-13,-39},{-13,-38},{-13,-35},{-13,-34},{-13,-33},{-13,-32},
|
||||
{-13,-29},{-13,-28},{-13,-15},{-13,-14},{-13,-5},{-13,-4},{-13,-3},{-13,-2},{-13,5},{-13,6},{-13,7},{-13,8},{-13,17},{-13,18},{-13,31},{-13,32},{-13,35},{-13,36},{-13,37},{-13,38},{-13,41},{-13,42},{-12,-39},{-12,-38},{-12,-35},{-12,-34},{-12,-33},{-12,-32},{-12,-29},{-12,-28},
|
||||
{-12,-27},{-12,-16},{-12,-15},{-12,-14},{-12,-13},{-12,-5},{-12,-4},{-12,-3},{-12,-2},{-12,5},{-12,6},{-12,7},{-12,8},{-12,16},{-12,17},{-12,18},{-12,19},{-12,30},{-12,31},{-12,32},{-12,35},{-12,36},{-12,37},{-12,38},{-12,41},{-12,42},{-11,-43},{-11,-42},{-11,-34},{-11,-33},
|
||||
{-11,-32},{-11,-29},{-11,-28},{-11,-27},{-11,-26},{-11,-23},{-11,-22},{-11,-21},{-11,-20},{-11,-17},{-11,-16},{-11,-15},{-11,-14},{-11,-13},{-11,-12},{-11,-9},{-11,-8},{-11,1},{-11,2},{-11,11},{-11,12},{-11,15},{-11,16},{-11,17},{-11,18},{-11,19},{-11,20},{-11,23},{-11,24},{-11,25},
|
||||
{-11,26},{-11,29},{-11,30},{-11,31},{-11,32},{-11,35},{-11,36},{-11,37},{-11,45},{-11,46},{-10,-44},{-10,-43},{-10,-42},{-10,-33},{-10,-32},{-10,-29},{-10,-28},{-10,-27},{-10,-26},{-10,-23},{-10,-22},{-10,-21},{-10,-20},{-10,-17},{-10,-16},{-10,-15},{-10,-14},{-10,-13},{-10,-12},{-10,-9},
|
||||
{-10,-8},{-10,-7},{-10,0},{-10,1},{-10,2},{-10,3},{-10,10},{-10,11},{-10,12},{-10,15},{-10,16},{-10,17},{-10,18},{-10,19},{-10,20},{-10,23},{-10,24},{-10,25},{-10,26},{-10,29},{-10,30},{-10,31},{-10,32},{-10,35},{-10,36},{-10,45},{-10,46},{-10,47},{-9,-45},{-9,-44},
|
||||
{-9,-43},{-9,-29},{-9,-28},{-9,-27},{-9,-23},{-9,-22},{-9,-21},{-9,-20},{-9,-17},{-9,-16},{-9,-15},{-9,-14},{-9,-13},{-9,-8},{-9,-7},{-9,-6},{-9,-5},{-9,-1},{-9,0},{-9,1},{-9,2},{-9,3},{-9,4},{-9,8},{-9,9},{-9,10},{-9,11},{-9,16},{-9,17},{-9,18},
|
||||
{-9,19},{-9,20},{-9,23},{-9,24},{-9,25},{-9,26},{-9,30},{-9,31},{-9,32},{-9,46},{-9,47},{-9,48},{-8,-45},{-8,-44},{-8,-30},{-8,-29},{-8,-28},{-8,-24},{-8,-23},{-8,-22},{-8,-21},{-8,-20},{-8,-17},{-8,-16},{-8,-15},{-8,-14},{-8,-7},{-8,-6},{-8,-5},{-8,-4},
|
||||
{-8,-1},{-8,0},{-8,1},{-8,2},{-8,3},{-8,4},{-8,7},{-8,8},{-8,9},{-8,10},{-8,17},{-8,18},{-8,19},{-8,20},{-8,23},{-8,24},{-8,25},{-8,26},{-8,27},{-8,31},{-8,32},{-8,33},{-8,47},{-8,48},{-7,-45},{-7,-44},{-7,-39},{-7,-38},{-7,-37},{-7,-36},
|
||||
{-7,-31},{-7,-30},{-7,-29},{-7,-25},{-7,-24},{-7,-23},{-7,-22},{-7,-21},{-7,-11},{-7,-10},{-7,-7},{-7,-6},{-7,-5},{-7,-4},{-7,7},{-7,8},{-7,9},{-7,10},{-7,13},{-7,14},{-7,24},{-7,25},{-7,26},{-7,27},{-7,28},{-7,32},{-7,33},{-7,34},{-7,39},{-7,40},
|
||||
{-7,41},{-7,42},{-7,47},{-7,48},{-6,-46},{-6,-45},{-6,-44},{-6,-39},{-6,-38},{-6,-37},{-6,-36},{-6,-35},{-6,-31},{-6,-30},{-6,-25},{-6,-24},{-6,-23},{-6,-22},{-6,-12},{-6,-11},{-6,-10},{-6,-6},{-6,-5},{-6,8},{-6,9},{-6,13},{-6,14},{-6,15},{-6,25},{-6,26},
|
||||
{-6,27},{-6,28},{-6,33},{-6,34},{-6,38},{-6,39},{-6,40},{-6,41},{-6,42},{-6,47},{-6,48},{-6,49},{-5,-47},{-5,-46},{-5,-45},{-5,-44},{-5,-37},{-5,-36},{-5,-35},{-5,-34},{-5,-19},{-5,-18},{-5,-13},{-5,-12},{-5,-11},{-5,-10},{-5,-1},{-5,0},{-5,1},{-5,2},
|
||||
{-5,3},{-5,4},{-5,13},{-5,14},{-5,15},{-5,16},{-5,21},{-5,22},{-5,37},{-5,38},{-5,39},{-5,40},{-5,47},{-5,48},{-5,49},{-5,50},{-4,-47},{-4,-46},{-4,-45},{-4,-44},{-4,-43},{-4,-37},{-4,-36},{-4,-35},{-4,-34},{-4,-19},{-4,-18},{-4,-17},{-4,-13},{-4,-12},
|
||||
{-4,-11},{-4,-10},{-4,-2},{-4,-1},{-4,0},{-4,1},{-4,2},{-4,3},{-4,4},{-4,5},{-4,13},{-4,14},{-4,15},{-4,16},{-4,20},{-4,21},{-4,22},{-4,37},{-4,38},{-4,39},{-4,40},{-4,46},{-4,47},{-4,48},{-4,49},{-4,50},{-3,-44},{-3,-43},{-3,-42},{-3,-41},
|
||||
{-3,-40},{-3,-37},{-3,-36},{-3,-35},{-3,-34},{-3,-31},{-3,-30},{-3,-29},{-3,-28},{-3,-25},{-3,-24},{-3,-23},{-3,-22},{-3,-18},{-3,-17},{-3,-16},{-3,-7},{-3,-6},{-3,-3},{-3,-2},{-3,-1},{-3,0},{-3,3},{-3,4},{-3,5},{-3,6},{-3,9},{-3,10},{-3,19},{-3,20},
|
||||
{-3,21},{-3,25},{-3,26},{-3,27},{-3,28},{-3,31},{-3,32},{-3,33},{-3,34},{-3,37},{-3,38},{-3,39},{-3,40},{-3,43},{-3,44},{-3,45},{-3,46},{-3,47},{-2,-43},{-2,-42},{-2,-41},{-2,-40},{-2,-37},{-2,-36},{-2,-35},{-2,-34},{-2,-31},{-2,-30},{-2,-29},{-2,-28},
|
||||
{-2,-25},{-2,-24},{-2,-23},{-2,-22},{-2,-21},{-2,-17},{-2,-16},{-2,-15},{-2,-8},{-2,-7},{-2,-6},{-2,-3},{-2,-2},{-2,-1},{-2,0},{-2,3},{-2,4},{-2,5},{-2,6},{-2,9},{-2,10},{-2,11},{-2,18},{-2,19},{-2,20},{-2,24},{-2,25},{-2,26},{-2,27},{-2,28},
|
||||
{-2,31},{-2,32},{-2,33},{-2,34},{-2,37},{-2,38},{-2,39},{-2,40},{-2,43},{-2,44},{-2,45},{-2,46},{-1,-47},{-1,-46},{-1,-43},{-1,-42},{-1,-41},{-1,-40},{-1,-37},{-1,-36},{-1,-29},{-1,-28},{-1,-25},{-1,-24},{-1,-23},{-1,-22},{-1,-21},{-1,-20},{-1,-17},{-1,-16},
|
||||
{-1,-15},{-1,-14},{-1,-13},{-1,-12},{-1,-9},{-1,-8},{-1,-7},{-1,-6},{-1,-3},{-1,-2},{-1,5},{-1,6},{-1,9},{-1,10},{-1,11},{-1,12},{-1,15},{-1,16},{-1,17},{-1,18},{-1,19},{-1,20},{-1,23},{-1,24},{-1,25},{-1,26},{-1,27},{-1,28},{-1,31},{-1,32},
|
||||
{-1,39},{-1,40},{-1,43},{-1,44},{-1,45},{-1,46},{-1,49},{-1,50},{0,-47},{0,-46},{0,-43},{0,-42},{0,-41},{0,-40},{0,-37},{0,-36},{0,-29},{0,-28},{0,-25},{0,-24},{0,-23},{0,-22},{0,-21},{0,-20},{0,-17},{0,-16},{0,-15},{0,-14},{0,-13},{0,-12},
|
||||
{0,-9},{0,-8},{0,-7},{0,-6},{0,-3},{0,-2},{0,5},{0,6},{0,9},{0,10},{0,11},{0,12},{0,15},{0,16},{0,17},{0,18},{0,19},{0,20},{0,23},{0,24},{0,25},{0,26},{0,27},{0,28},{0,31},{0,32},{0,39},{0,40},{0,43},{0,44},
|
||||
{0,45},{0,46},{0,49},{0,50},{1,-43},{1,-42},{1,-41},{1,-40},{1,-37},{1,-36},{1,-35},{1,-34},{1,-31},{1,-30},{1,-29},{1,-28},{1,-25},{1,-24},{1,-23},{1,-22},{1,-21},{1,-17},{1,-16},{1,-15},{1,-8},{1,-7},{1,-6},{1,-3},{1,-2},{1,-1},
|
||||
{1,0},{1,3},{1,4},{1,5},{1,6},{1,9},{1,10},{1,11},{1,18},{1,19},{1,20},{1,24},{1,25},{1,26},{1,27},{1,28},{1,31},{1,32},{1,33},{1,34},{1,37},{1,38},{1,39},{1,40},{1,43},{1,44},{1,45},{1,46},{2,-44},{2,-43},
|
||||
{2,-42},{2,-41},{2,-40},{2,-37},{2,-36},{2,-35},{2,-34},{2,-31},{2,-30},{2,-29},{2,-28},{2,-25},{2,-24},{2,-23},{2,-22},{2,-18},{2,-17},{2,-16},{2,-7},{2,-6},{2,-3},{2,-2},{2,-1},{2,0},{2,3},{2,4},{2,5},{2,6},{2,9},{2,10},
|
||||
{2,19},{2,20},{2,21},{2,25},{2,26},{2,27},{2,28},{2,31},{2,32},{2,33},{2,34},{2,37},{2,38},{2,39},{2,40},{2,43},{2,44},{2,45},{2,46},{2,47},{3,-47},{3,-46},{3,-45},{3,-44},{3,-43},{3,-37},{3,-36},{3,-35},{3,-34},{3,-19},
|
||||
{3,-18},{3,-17},{3,-13},{3,-12},{3,-11},{3,-10},{3,-2},{3,-1},{3,0},{3,1},{3,2},{3,3},{3,4},{3,5},{3,13},{3,14},{3,15},{3,16},{3,20},{3,21},{3,22},{3,37},{3,38},{3,39},{3,40},{3,46},{3,47},{3,48},{3,49},{3,50},
|
||||
{4,-47},{4,-46},{4,-45},{4,-44},{4,-37},{4,-36},{4,-35},{4,-34},{4,-19},{4,-18},{4,-13},{4,-12},{4,-11},{4,-10},{4,-1},{4,0},{4,1},{4,2},{4,3},{4,4},{4,13},{4,14},{4,15},{4,16},{4,21},{4,22},{4,37},{4,38},{4,39},{4,40},
|
||||
{4,47},{4,48},{4,49},{4,50},{5,-46},{5,-45},{5,-44},{5,-39},{5,-38},{5,-37},{5,-36},{5,-35},{5,-31},{5,-30},{5,-25},{5,-24},{5,-23},{5,-22},{5,-12},{5,-11},{5,-10},{5,-6},{5,-5},{5,8},{5,9},{5,13},{5,14},{5,15},{5,25},{5,26},
|
||||
{5,27},{5,28},{5,33},{5,34},{5,38},{5,39},{5,40},{5,41},{5,42},{5,47},{5,48},{5,49},{6,-45},{6,-44},{6,-39},{6,-38},{6,-37},{6,-36},{6,-31},{6,-30},{6,-29},{6,-25},{6,-24},{6,-23},{6,-22},{6,-21},{6,-11},{6,-10},{6,-7},{6,-6},
|
||||
{6,-5},{6,-4},{6,7},{6,8},{6,9},{6,10},{6,13},{6,14},{6,24},{6,25},{6,26},{6,27},{6,28},{6,32},{6,33},{6,34},{6,39},{6,40},{6,41},{6,42},{6,47},{6,48},{7,-45},{7,-44},{7,-30},{7,-29},{7,-28},{7,-24},{7,-23},{7,-22},
|
||||
{7,-21},{7,-20},{7,-17},{7,-16},{7,-15},{7,-14},{7,-7},{7,-6},{7,-5},{7,-4},{7,-1},{7,0},{7,1},{7,2},{7,3},{7,4},{7,7},{7,8},{7,9},{7,10},{7,17},{7,18},{7,19},{7,20},{7,23},{7,24},{7,25},{7,26},{7,27},{7,31},
|
||||
{7,32},{7,33},{7,47},{7,48},{8,-45},{8,-44},{8,-43},{8,-29},{8,-28},{8,-27},{8,-23},{8,-22},{8,-21},{8,-20},{8,-17},{8,-16},{8,-15},{8,-14},{8,-13},{8,-8},{8,-7},{8,-6},{8,-5},{8,-1},{8,0},{8,1},{8,2},{8,3},{8,4},{8,8},
|
||||
{8,9},{8,10},{8,11},{8,16},{8,17},{8,18},{8,19},{8,20},{8,23},{8,24},{8,25},{8,26},{8,30},{8,31},{8,32},{8,46},{8,47},{8,48},{9,-44},{9,-43},{9,-42},{9,-33},{9,-32},{9,-29},{9,-28},{9,-27},{9,-26},{9,-23},{9,-22},{9,-21},
|
||||
{9,-20},{9,-17},{9,-16},{9,-15},{9,-14},{9,-13},{9,-12},{9,-9},{9,-8},{9,-7},{9,0},{9,1},{9,2},{9,3},{9,10},{9,11},{9,12},{9,15},{9,16},{9,17},{9,18},{9,19},{9,20},{9,23},{9,24},{9,25},{9,26},{9,29},{9,30},{9,31},
|
||||
{9,32},{9,35},{9,36},{9,45},{9,46},{9,47},{10,-43},{10,-42},{10,-34},{10,-33},{10,-32},{10,-29},{10,-28},{10,-27},{10,-26},{10,-23},{10,-22},{10,-21},{10,-20},{10,-17},{10,-16},{10,-15},{10,-14},{10,-13},{10,-12},{10,-9},{10,-8},{10,1},{10,2},{10,11},
|
||||
{10,12},{10,15},{10,16},{10,17},{10,18},{10,19},{10,20},{10,23},{10,24},{10,25},{10,26},{10,29},{10,30},{10,31},{10,32},{10,35},{10,36},{10,37},{10,45},{10,46},{11,-39},{11,-38},{11,-35},{11,-34},{11,-33},{11,-32},{11,-29},{11,-28},{11,-27},{11,-16},
|
||||
{11,-15},{11,-14},{11,-13},{11,-5},{11,-4},{11,-3},{11,-2},{11,5},{11,6},{11,7},{11,8},{11,16},{11,17},{11,18},{11,19},{11,30},{11,31},{11,32},{11,35},{11,36},{11,37},{11,38},{11,41},{11,42},{12,-39},{12,-38},{12,-35},{12,-34},{12,-33},{12,-32},
|
||||
{12,-29},{12,-28},{12,-15},{12,-14},{12,-5},{12,-4},{12,-3},{12,-2},{12,5},{12,6},{12,7},{12,8},{12,17},{12,18},{12,31},{12,32},{12,35},{12,36},{12,37},{12,38},{12,41},{12,42},{13,-43},{13,-42},{13,-39},{13,-38},{13,-37},{13,-36},{13,-35},{13,-34},
|
||||
{13,-33},{13,-19},{13,-18},{13,-9},{13,-8},{13,-4},{13,-3},{13,-2},{13,1},{13,2},{13,5},{13,6},{13,7},{13,11},{13,12},{13,21},{13,22},{13,36},{13,37},{13,38},{13,39},{13,40},{13,41},{13,42},{13,45},{13,46},{14,-43},{14,-42},{14,-39},{14,-38},
|
||||
{14,-37},{14,-36},{14,-35},{14,-34},{14,-20},{14,-19},{14,-18},{14,-17},{14,-10},{14,-9},{14,-8},{14,-7},{14,-3},{14,-2},{14,1},{14,2},{14,5},{14,6},{14,10},{14,11},{14,12},{14,13},{14,20},{14,21},{14,22},{14,23},{14,37},{14,38},{14,39},{14,40},
|
||||
{14,41},{14,42},{14,45},{14,46},{15,-43},{15,-42},{15,-31},{15,-30},{15,-27},{15,-26},{15,-21},{15,-20},{15,-19},{15,-18},{15,-17},{15,-16},{15,-15},{15,-14},{15,-11},{15,-10},{15,-9},{15,-8},{15,-7},{15,-6},{15,1},{15,2},{15,9},{15,10},{15,11},{15,12},
|
||||
{15,13},{15,14},{15,17},{15,18},{15,19},{15,20},{15,21},{15,22},{15,23},{15,24},{15,29},{15,30},{15,33},{15,34},{15,45},{15,46},{16,-43},{16,-42},{16,-32},{16,-31},{16,-30},{16,-27},{16,-26},{16,-25},{16,-21},{16,-20},{16,-19},{16,-18},{16,-17},{16,-16},
|
||||
{16,-15},{16,-14},{16,-11},{16,-10},{16,-9},{16,-8},{16,-7},{16,-6},{16,0},{16,1},{16,2},{16,3},{16,9},{16,10},{16,11},{16,12},{16,13},{16,14},{16,17},{16,18},{16,19},{16,20},{16,21},{16,22},{16,23},{16,24},{16,28},{16,29},{16,30},{16,33},
|
||||
{16,34},{16,35},{16,45},{16,46},{17,-43},{17,-42},{17,-35},{17,-34},{17,-33},{17,-32},{17,-31},{17,-26},{17,-25},{17,-24},{17,-15},{17,-14},{17,-10},{17,-9},{17,-8},{17,-7},{17,-6},{17,-1},{17,0},{17,1},{17,2},{17,3},{17,4},{17,9},{17,10},{17,11},
|
||||
{17,12},{17,13},{17,17},{17,18},{17,27},{17,28},{17,29},{17,34},{17,35},{17,36},{17,37},{17,38},{17,45},{17,46},{18,-43},{18,-42},{18,-41},{18,-35},{18,-34},{18,-33},{18,-32},{18,-25},{18,-24},{18,-23},{18,-15},{18,-14},{18,-13},{18,-9},{18,-8},{18,-7},
|
||||
{18,-6},{18,-2},{18,-1},{18,0},{18,1},{18,2},{18,3},{18,4},{18,5},{18,9},{18,10},{18,11},{18,12},{18,16},{18,17},{18,18},{18,26},{18,27},{18,28},{18,35},{18,36},{18,37},{18,38},{18,44},{18,45},{18,46},{19,-42},{19,-41},{19,-40},{19,-39},
|
||||
{19,-38},{19,-29},{19,-28},{19,-25},{19,-24},{19,-23},{19,-22},{19,-21},{19,-20},{19,-19},{19,-18},{19,-15},{19,-14},{19,-13},{19,-12},{19,-3},{19,-2},{19,-1},{19,4},{19,5},{19,6},{19,15},{19,16},{19,17},{19,18},{19,21},{19,22},{19,23},{19,24},{19,25},
|
||||
{19,26},{19,27},{19,28},{19,31},{19,32},{19,41},{19,42},{19,43},{19,44},{19,45},{20,-41},{20,-40},{20,-39},{20,-38},{20,-37},{20,-29},{20,-28},{20,-25},{20,-24},{20,-23},{20,-22},{20,-21},{20,-20},{20,-19},{20,-18},{20,-15},{20,-14},{20,-13},{20,-12},{20,-3},
|
||||
{20,-2},{20,5},{20,6},{20,15},{20,16},{20,17},{20,18},{20,21},{20,22},{20,23},{20,24},{20,25},{20,26},{20,27},{20,28},{20,31},{20,32},{20,40},{20,41},{20,42},{20,43},{20,44},{21,-38},{21,-37},{21,-36},{21,-29},{21,-28},{21,-19},{21,-18},{21,-15},
|
||||
{21,-14},{21,-13},{21,-9},{21,-8},{21,-7},{21,-6},{21,1},{21,2},{21,9},{21,10},{21,11},{21,12},{21,16},{21,17},{21,18},{21,21},{21,22},{21,31},{21,32},{21,39},{21,40},{21,41},{22,-37},{22,-36},{22,-30},{22,-29},{22,-28},{22,-19},{22,-18},{22,-15},
|
||||
{22,-14},{22,-9},{22,-8},{22,-7},{22,-6},{22,-5},{22,0},{22,1},{22,2},{22,3},{22,8},{22,9},{22,10},{22,11},{22,12},{22,17},{22,18},{22,21},{22,22},{22,31},{22,32},{22,33},{22,39},{22,40},{23,-33},{23,-32},{23,-31},{23,-30},{23,-29},{23,-25},
|
||||
{23,-24},{23,-23},{23,-22},{23,-19},{23,-18},{23,-9},{23,-8},{23,-7},{23,-6},{23,-5},{23,-4},{23,-1},{23,0},{23,1},{23,2},{23,3},{23,4},{23,7},{23,8},{23,9},{23,10},{23,11},{23,12},{23,21},{23,22},{23,25},{23,26},{23,27},{23,28},{23,32},
|
||||
{23,33},{23,34},{23,35},{23,36},{24,-33},{24,-32},{24,-31},{24,-30},{24,-25},{24,-24},{24,-23},{24,-22},{24,-19},{24,-18},{24,-17},{24,-9},{24,-8},{24,-7},{24,-6},{24,-5},{24,-4},{24,-1},{24,0},{24,1},{24,2},{24,3},{24,4},{24,7},{24,8},{24,9},
|
||||
{24,10},{24,11},{24,12},{24,20},{24,21},{24,22},{24,25},{24,26},{24,27},{24,28},{24,33},{24,34},{24,35},{24,36},{25,-39},{25,-38},{25,-37},{25,-36},{25,-24},{25,-23},{25,-22},{25,-19},{25,-18},{25,-17},{25,-16},{25,-6},{25,-5},{25,-4},{25,-1},{25,0},
|
||||
{25,1},{25,2},{25,3},{25,4},{25,7},{25,8},{25,9},{25,19},{25,20},{25,21},{25,22},{25,25},{25,26},{25,27},{25,39},{25,40},{25,41},{25,42},{26,-39},{26,-38},{26,-37},{26,-36},{26,-23},{26,-22},{26,-19},{26,-18},{26,-17},{26,-16},{26,-15},{26,-5},
|
||||
{26,-4},{26,-1},{26,0},{26,1},{26,2},{26,3},{26,4},{26,7},{26,8},{26,18},{26,19},{26,20},{26,21},{26,22},{26,25},{26,26},{26,39},{26,40},{26,41},{26,42},{27,-38},{27,-37},{27,-36},{27,-29},{27,-28},{27,-27},{27,-26},{27,-16},{27,-15},{27,-14},
|
||||
{27,-9},{27,-8},{27,11},{27,12},{27,17},{27,18},{27,19},{27,29},{27,30},{27,31},{27,32},{27,39},{27,40},{27,41},{28,-37},{28,-36},{28,-30},{28,-29},{28,-28},{28,-27},{28,-26},{28,-15},{28,-14},{28,-10},{28,-9},{28,-8},{28,-7},{28,10},{28,11},{28,12},
|
||||
{28,13},{28,17},{28,18},{28,29},{28,30},{28,31},{28,32},{28,33},{28,39},{28,40},{29,-33},{29,-32},{29,-31},{29,-30},{29,-29},{29,-28},{29,-27},{29,-26},{29,-21},{29,-20},{29,-19},{29,-18},{29,-11},{29,-10},{29,-9},{29,-8},{29,-7},{29,-6},{29,-1},{29,0},
|
||||
{29,1},{29,2},{29,3},{29,4},{29,9},{29,10},{29,11},{29,12},{29,13},{29,14},{29,21},{29,22},{29,23},{29,24},{29,29},{29,30},{29,31},{29,32},{29,33},{29,34},{29,35},{29,36},{30,-33},{30,-32},{30,-31},{30,-30},{30,-29},{30,-28},{30,-27},{30,-26},
|
||||
{30,-22},{30,-21},{30,-20},{30,-19},{30,-18},{30,-11},{30,-10},{30,-9},{30,-8},{30,-7},{30,-6},{30,-5},{30,-1},{30,0},{30,1},{30,2},{30,3},{30,4},{30,8},{30,9},{30,10},{30,11},{30,12},{30,13},{30,14},{30,21},{30,22},{30,23},{30,24},{30,25},
|
||||
{30,29},{30,30},{30,31},{30,32},{30,33},{30,34},{30,35},{30,36},{31,-32},{31,-31},{31,-30},{31,-29},{31,-28},{31,-27},{31,-23},{31,-22},{31,-21},{31,-15},{31,-14},{31,-6},{31,-5},{31,-4},{31,-1},{31,0},{31,3},{31,4},{31,7},{31,8},{31,9},{31,17},
|
||||
{31,18},{31,24},{31,25},{31,26},{31,30},{31,31},{31,32},{31,33},{31,34},{31,35},{32,-31},{32,-30},{32,-29},{32,-28},{32,-23},{32,-22},{32,-16},{32,-15},{32,-14},{32,-5},{32,-4},{32,-1},{32,0},{32,3},{32,4},{32,7},{32,8},{32,17},{32,18},{32,19},
|
||||
{32,25},{32,26},{32,31},{32,32},{32,33},{32,34},{33,-30},{33,-29},{33,-28},{33,-23},{33,-22},{33,-17},{33,-16},{33,-15},{33,-11},{33,-10},{33,-9},{33,-8},{33,11},{33,12},{33,13},{33,14},{33,18},{33,19},{33,20},{33,25},{33,26},{33,31},{33,32},{33,33},
|
||||
{34,-29},{34,-28},{34,-23},{34,-22},{34,-17},{34,-16},{34,-12},{34,-11},{34,-10},{34,-9},{34,-8},{34,11},{34,12},{34,13},{34,14},{34,15},{34,19},{34,20},{34,25},{34,26},{34,31},{34,32},{35,-17},{35,-16},{35,-13},{35,-12},{35,-11},{35,-10},{35,-9},{35,-3},
|
||||
{35,-2},{35,-1},{35,0},{35,3},{35,4},{35,5},{35,6},{35,12},{35,13},{35,14},{35,15},{35,16},{35,19},{35,20},{36,-17},{36,-16},{36,-13},{36,-12},{36,-11},{36,-10},{36,-4},{36,-3},{36,-2},{36,-1},{36,0},{36,3},{36,4},{36,5},{36,6},{36,7},
|
||||
{36,13},{36,14},{36,15},{36,16},{36,19},{36,20},{37,-27},{37,-26},{37,-25},{37,-24},{37,-21},{37,-20},{37,-13},{37,-12},{37,-5},{37,-4},{37,-3},{37,-2},{37,-1},{37,0},{37,1},{37,2},{37,3},{37,4},{37,5},{37,6},{37,7},{37,8},{37,15},{37,16},
|
||||
{37,23},{37,24},{37,27},{37,28},{37,29},{37,30},{38,-27},{38,-26},{38,-25},{38,-24},{38,-21},{38,-20},{38,-19},{38,-13},{38,-12},{38,-5},{38,-4},{38,-3},{38,-2},{38,-1},{38,0},{38,1},{38,2},{38,3},{38,4},{38,5},{38,6},{38,7},{38,8},{38,15},
|
||||
{38,16},{38,22},{38,23},{38,24},{38,27},{38,28},{38,29},{38,30},{39,-26},{39,-25},{39,-24},{39,-20},{39,-19},{39,-18},{39,-13},{39,-12},{39,-11},{39,-10},{39,-5},{39,-4},{39,7},{39,8},{39,13},{39,14},{39,15},{39,16},{39,21},{39,22},{39,23},{39,27},
|
||||
{39,28},{39,29},{40,-25},{40,-24},{40,-19},{40,-18},{40,-13},{40,-12},{40,-11},{40,-10},{40,-5},{40,-4},{40,7},{40,8},{40,13},{40,14},{40,15},{40,16},{40,21},{40,22},{40,27},{40,28},{41,-19},{41,-18},{41,-1},{41,0},{41,1},{41,2},{41,3},{41,4},
|
||||
{41,21},{41,22},{42,-19},{42,-18},{42,-17},{42,-1},{42,0},{42,1},{42,2},{42,3},{42,4},{42,20},{42,21},{42,22},{43,-18},{43,-17},{43,-16},{43,-15},{43,-14},{43,-13},{43,-12},{43,-9},{43,-8},{43,-1},{43,0},{43,1},{43,2},{43,3},{43,4},{43,11},
|
||||
{43,12},{43,15},{43,16},{43,17},{43,18},{43,19},{43,20},{43,21},{44,-17},{44,-16},{44,-15},{44,-14},{44,-13},{44,-12},{44,-9},{44,-8},{44,-7},{44,-2},{44,-1},{44,0},{44,1},{44,2},{44,3},{44,4},{44,5},{44,10},{44,11},{44,12},{44,15},{44,16},
|
||||
{44,17},{44,18},{44,19},{44,20},{45,-8},{45,-7},{45,-6},{45,-5},{45,-4},{45,-3},{45,-2},{45,-1},{45,4},{45,5},{45,6},{45,7},{45,8},{45,9},{45,10},{45,11},{46,-7},{46,-6},{46,-5},{46,-4},{46,-3},{46,-2},{46,5},{46,6},{46,7},{46,8},
|
||||
{46,9},{46,10},{47,-4},{47,-3},{47,-2},{47,1},{47,2},{47,5},{47,6},{47,7},{48,-3},{48,-2},{48,1},{48,2},{48,5},{48,6}
|
||||
}
|
||||
},
|
||||
resource_tiles = {
|
||||
enabled = false,
|
||||
resources = {
|
||||
{
|
||||
enabled = false,
|
||||
name = 'iron-ore',
|
||||
amount = 4000,
|
||||
size = {26, 27},
|
||||
-- offset = {-64,-32}
|
||||
offset = {-64,-64}
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
name = 'copper-ore',
|
||||
amount = 4000,
|
||||
size = {26, 27},
|
||||
-- offset = {-64, 0}
|
||||
offset = {64, -64}
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
name = 'stone',
|
||||
amount = 4000,
|
||||
size = {22, 20},
|
||||
-- offset = {-64, 32}
|
||||
offset = {-64, 64}
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
name = 'coal',
|
||||
amount = 4000,
|
||||
size = {22, 20},
|
||||
-- offset = {-64, -64}
|
||||
offset = {64, 64}
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
name = 'uranium-ore',
|
||||
amount = 4000,
|
||||
size = {22, 20},
|
||||
-- offset = {-64, -96}
|
||||
offset = {0, 64}
|
||||
}
|
||||
}
|
||||
},
|
||||
resource_patches = {
|
||||
enabled = false,
|
||||
resources = {
|
||||
{
|
||||
enabled = false,
|
||||
name = 'crude-oil',
|
||||
num_patches = 4,
|
||||
amount = 4000000,
|
||||
-- offset = {-80, -12},
|
||||
offset = {-12, 64},
|
||||
-- offset_next = {0, 6}
|
||||
offset_next = {6, 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
resource_refill_nearby = {
|
||||
enabled = false,
|
||||
range = 128,
|
||||
resources_name = {
|
||||
'iron-ore',
|
||||
'copper-ore',
|
||||
'stone',
|
||||
'coal',
|
||||
'uranium-ore'
|
||||
},
|
||||
amount = {2500, 4000}
|
||||
}
|
||||
}
|
||||
11
exp_legacy/module/config/station_auto_name.lua
Normal file
11
exp_legacy/module/config/station_auto_name.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
return {
|
||||
--[[
|
||||
__icon__
|
||||
__item_name__
|
||||
__backer_name__
|
||||
__direction__
|
||||
__x__
|
||||
__y__
|
||||
]]
|
||||
station_name = '[L] __icon__'
|
||||
}
|
||||
46
exp_legacy/module/config/statistics.lua
Normal file
46
exp_legacy/module/config/statistics.lua
Normal file
@@ -0,0 +1,46 @@
|
||||
--- A list of all tracked statistics and the events which trigger them
|
||||
-- @config Statistics
|
||||
|
||||
local e = defines.events -- order as per lua api as it was easier just to go down the list
|
||||
return {
|
||||
MapsPlayed = true, --- @setting MapsPlayed If the number of maps which a player has played should be tracked
|
||||
Playtime = true, --- @setting Playtime If playtime is tracked for a player, play time measured in minutes
|
||||
AfkTime = true, --- @setting AfkTime If afk time is tracked for a player, play time measured in minutes, afk is once a player does nothing for 5 minutes
|
||||
DistanceTravelled = true, --- @setting DistanceTravelled If distance Travelled is checked, only counts if not afk
|
||||
MachinesRemoved = true, --- @setting MachinesRemoved If removed machines are tracked, includes marked for decon and player mined entity
|
||||
TreesDestroyed = true, --- @setting OreMined If ore mined is tracked for a player, includes marked for decon and player mined entity but only trees
|
||||
OreMined = true, --- @setting OreMined If ore mined is tracked for a player, includes player mined entity but only ore
|
||||
DamageDealt = true, --- @setting DamageDealt If damage dealt is tracked for a player, includes any damage to entities not on the same force or neutral
|
||||
Kills = true, --- @setting Kills If kills are tracked for a player, includes all kills not on same force or neutral
|
||||
RocketsLaunched = true, --- @setting RocketsLaunched If the number of rockets launched should be tracked, done for all players on the force
|
||||
ResearchCompleted = true, --- @setting ResearchCompleted If the number of researches completed should be tracked, done for all players on the force
|
||||
counters = { --- @setting counters Simple statistics that just go up by one each time an event happens
|
||||
MachinesBuilt = e.on_built_entity,
|
||||
MapTagsMade = e.on_chart_tag_added,
|
||||
ChatMessages = e.on_console_chat,
|
||||
CommandsUsed = e.on_console_command,
|
||||
ItemsPickedUp = e.on_picked_up_item,
|
||||
TilesBuilt = e.on_player_built_tile,
|
||||
ItemsCrafted = e.on_player_crafted_item,
|
||||
DeconstructionPlannerUsed = e.on_player_deconstructed_area,
|
||||
Deaths = e.on_player_died,
|
||||
JoinCount = e.on_player_joined_game,
|
||||
TilesRemoved = e.on_player_mined_tile,
|
||||
CapsulesUsed = e.on_player_used_capsule,
|
||||
EntityRepaired= e.on_player_repaired_entity
|
||||
},
|
||||
display_order = { --- @setting display_order The order that the statistics should be shown in when in a gui or command
|
||||
'Playtime', 'AfkTime',
|
||||
'MapsPlayed', 'JoinCount',
|
||||
'ChatMessages', 'CommandsUsed',
|
||||
'RocketsLaunched', 'ResearchCompleted',
|
||||
'MachinesBuilt', 'MachinesRemoved',
|
||||
'TilesBuilt', 'TilesRemoved',
|
||||
'TreesDestroyed', 'OreMined',
|
||||
'ItemsCrafted', 'ItemsPickedUp',
|
||||
'Kills', 'Deaths',
|
||||
'DamageDealt', 'DistanceTravelled',
|
||||
'CapsulesUsed', 'EntityRepaired',
|
||||
'DeconstructionPlannerUsed', 'MapTagsMade'
|
||||
}
|
||||
}
|
||||
174
exp_legacy/module/config/vlayer.lua
Normal file
174
exp_legacy/module/config/vlayer.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--- Settings for vlayer including the allowed items, the update frequency, and some cheats
|
||||
-- @config Vlayer
|
||||
|
||||
return {
|
||||
update_tick_storage = 60, --- @setting update_tick_storage The number of ticks between each update of the storage interfaces
|
||||
update_tick_energy = 10, --- @setting update_tick_energy The number of ticks between each update of the energy and circuit interfaces
|
||||
update_tick_gui = 60, --- @setting update_tick_gui The number of ticks between each update of the gui
|
||||
|
||||
unlimited_capacity = false, --- @setting unlimited_capacity When true the vlayer has an unlimited energy capacity, accumulators are not required
|
||||
unlimited_surface_area = false, --- @setting unlimited_surface_area When true the vlayer has an unlimited surface area, landfill is not required
|
||||
modded_auto_downgrade = false, --- @setting modded_auto_downgrade When true modded items will be converted into their base game equivalent, original items can not be recovered
|
||||
|
||||
mimic_surface = 'nauvis', --- @setting mimic_surface Surface name/index the vlayer will copy its settings from, use nil to use the settings below
|
||||
surface = { --- @setting surface When mimic_surface is nil these settings will be used instead, see LuaSurface for details
|
||||
always_day = false,
|
||||
solar_power_multiplier = 1,
|
||||
min_brightness = 0.15,
|
||||
ticks_per_day = 25000,
|
||||
daytime = 0,
|
||||
dusk = 0.25,
|
||||
evening = 0.45,
|
||||
morning = 0.55,
|
||||
dawn = 0.75
|
||||
},
|
||||
|
||||
interface_limit = { --- @setting interface_limit Sets the limit for the number of vlayer interfaces that can be created
|
||||
energy = 1, -- >1 allows for disconnected power networks to receive power
|
||||
circuit = 10, -- No caveats
|
||||
storage_input = 10, -- No caveats
|
||||
storage_output = 1 -- >0 allows for item teleportation (allowed_items only)
|
||||
},
|
||||
|
||||
allowed_items = { --- @setting allowed_items List of all items allowed in vlayer storage and their properties
|
||||
--[[
|
||||
Allowed properties:
|
||||
starting_value = 0: The amount of the item placed into the vlayer on game start, ignores area requirements
|
||||
required_area = 0: When greater than 0 the items properties are not applied unless their is sufficient surplus surface area
|
||||
production = 0: The energy production of the item in MW, used for solar panels
|
||||
discharge = 0: The energy discharge of the item in MW, used for accumulators
|
||||
capacity = 0: The energy capacity of the item in MJ, used for accumulators
|
||||
surface_area = 0: The surface area provided by the item, used for landfill
|
||||
]]
|
||||
['solar-panel'] = {
|
||||
starting_value = 0,
|
||||
required_area = 9,
|
||||
production = 0.06 -- MW
|
||||
},
|
||||
['accumulator'] = {
|
||||
starting_value = 0,
|
||||
required_area = 4,
|
||||
discharge = 0.3, -- MW
|
||||
capacity = 5 -- MJ
|
||||
},
|
||||
['landfill'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 6 -- Tiles
|
||||
},
|
||||
['wood'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0,
|
||||
fuel_value = 2, -- MJ
|
||||
power = true -- turn all wood to power to reduce trash
|
||||
},
|
||||
['coal'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0,
|
||||
fuel_value = 4, -- MJ
|
||||
power = false -- turn all coal to power to reduce trash
|
||||
}
|
||||
--[[
|
||||
['iron-ore'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0
|
||||
},
|
||||
['copper-ore'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0
|
||||
},
|
||||
['coal'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0
|
||||
},
|
||||
['stone'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0
|
||||
},
|
||||
['uranium-ore'] = {
|
||||
starting_value = 0,
|
||||
required_area = 0,
|
||||
surface_area = 0
|
||||
},
|
||||
]]
|
||||
},
|
||||
|
||||
modded_items = { --- @setting modded_items List of all modded items allowed in vlayer storage and their base game equivalent
|
||||
['solar-panel-2'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 4
|
||||
},
|
||||
['solar-panel-3'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 16
|
||||
},
|
||||
['solar-panel-4'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 64
|
||||
},
|
||||
['solar-panel-5'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 256
|
||||
},
|
||||
['solar-panel-6'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 1024
|
||||
},
|
||||
['solar-panel-7'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 4096
|
||||
},
|
||||
['solar-panel-8'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'solar-panel',
|
||||
multiplier = 16384
|
||||
},
|
||||
['accumulator-2'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 4
|
||||
},
|
||||
['accumulator-3'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 16
|
||||
},
|
||||
['accumulator-4'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 64
|
||||
},
|
||||
['accumulator-5'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 256
|
||||
},
|
||||
['accumulator-6'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 1024
|
||||
},
|
||||
['accumulator-7'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 4096
|
||||
},
|
||||
['accumulator-8'] = {
|
||||
starting_value = 0,
|
||||
base_game_equivalent = 'accumulator',
|
||||
multiplier = 16384
|
||||
},
|
||||
}
|
||||
}
|
||||
21
exp_legacy/module/config/warnings.lua
Normal file
21
exp_legacy/module/config/warnings.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
--- Config file for the warning system, this is very similar to reports but is for the use of moderators rather than normal users.
|
||||
-- @config Warnings
|
||||
|
||||
return {
|
||||
actions = { --- @setting actions what actions are taking at number of warnings
|
||||
-- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted)
|
||||
{'warnings.received',''},
|
||||
{'warnings.received',''},
|
||||
{'warnings.received',{'warnings.pre-kick'}},
|
||||
function(player,by_player_name,number_of_warnings)
|
||||
game.kick_player(player,{'warnings.received',by_player_name,number_of_warnings,{'warnings.kick'}})
|
||||
end,
|
||||
{'warnings.received',{'warnings.pre-pre-ban'}},
|
||||
{'warnings.received',{'warnings.pre-ban'}},
|
||||
function(player,by_player_name,number_of_warnings)
|
||||
game.ban_player(player,{'warnings.received',by_player_name,number_of_warnings,{'warnings.ban',{'links.website'}}})
|
||||
end
|
||||
},
|
||||
script_warning_cool_down=30, --- @setting script_warning_cool_down time for a script warning (given by script) to be removed (in minutes)
|
||||
script_warning_limit=5 --- @setting script_warning_limit the number of script warnings (given by script) that are allowed before full warnings are given
|
||||
}
|
||||
57
exp_legacy/module/control.lua
Normal file
57
exp_legacy/module/control.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
--- Please go to ./config if you want to change settings, each file is commented with what it does
|
||||
-- if it is not in ./config then you should not attempt to change it unless you know what you are doing
|
||||
-- all files which are loaded (including the config files) are present in ./config/file_loader.lua
|
||||
-- this file is the landing point for all scenarios please DO NOT edit directly, further comments are to aid development
|
||||
|
||||
log('[START] -----| Explosive Gaming Scenario Loader |-----')
|
||||
log('[INFO] Setting up lua environment')
|
||||
|
||||
-- Require the global overrides
|
||||
require 'overrides.stages' -- Data stages used in factorio, often used to test for runtime
|
||||
require 'overrides.print' -- Overrides the _G.print function
|
||||
require 'overrides.math' -- Omitting the math library is a very bad idea
|
||||
require 'overrides.table' -- Adds alot more functions to the table module
|
||||
global.version = require 'overrides.version' -- The current version for exp gaming scenario
|
||||
inspect = require 'overrides.inspect' -- Used to covert any value into human readable string
|
||||
Debug = require 'overrides.debug' -- Global Debug module
|
||||
_C = require 'expcore.common' -- _C is used to store lots of common functions expected to be used
|
||||
_CHEATS = false
|
||||
_DEBUG = false
|
||||
|
||||
-- Please go to config/file_loader.lua to edit the files that are loaded
|
||||
log('[INFO] Reading loader config')
|
||||
local files = require 'config._file_loader'
|
||||
|
||||
-- Error handler for loading files
|
||||
local errors = {}
|
||||
local error_count = 0
|
||||
local error_format = '[ERROR] %s :: %s'
|
||||
local currently_loading = nil
|
||||
local function error_handler(err)
|
||||
error_count = error_count + 1
|
||||
if err:find('module '..currently_loading..' not found;', nil, true) then
|
||||
log('[ERROR] File not found: '..currently_loading)
|
||||
errors[error_count] = error_format:format(currently_loading, err)
|
||||
else
|
||||
log('[ERROR] Failed to load: '..currently_loading)
|
||||
errors[error_count] = debug.traceback(error_format:format(currently_loading, err))
|
||||
end
|
||||
end
|
||||
|
||||
-- Loads all files from the config and logs that they are loaded
|
||||
local total_file_count = string.format('%3d', #files)
|
||||
for index, path in pairs(files) do
|
||||
currently_loading = path
|
||||
log(string.format('[INFO] Loading file %3d/%s (%s)', index, total_file_count, path))
|
||||
xpcall(require, error_handler, path)
|
||||
end
|
||||
|
||||
-- Override the default require; require can no longer load new scripts
|
||||
log('[INFO] Require Overwrite! No more requires can be made!')
|
||||
require 'overrides.require'
|
||||
|
||||
-- Logs all errors again to make it make it easy to find
|
||||
log('[INFO] All files loaded with '..error_count..' errors:')
|
||||
for _, error in ipairs(errors) do log(error) end
|
||||
log('[END] -----| Explosive Gaming Scenario Loader |-----')
|
||||
101
exp_legacy/module/expcore/async.lua
Normal file
101
exp_legacy/module/expcore/async.lua
Normal file
@@ -0,0 +1,101 @@
|
||||
--[[-- Core Module - Async
|
||||
- An extention of task and token to allow a single require to register and run async functions.
|
||||
@core Async
|
||||
@alias Async
|
||||
|
||||
@usage
|
||||
-- To use Async you must register the allowed functions when the file is loaded, often this will just be giving access to
|
||||
-- some functions within a module if you expect that at part may be blocked by in game permissions or a custom system you have made
|
||||
-- you may also want to register functions that you want to have a time delay, such as waiting 2 seconds before printing a message
|
||||
|
||||
-- When player.admin is called (either command or gui element event) by a player who isnt admin then it will error
|
||||
-- here we register the function to promote the player so that it will run async and outside the player scope
|
||||
local promote_player =
|
||||
Async.register(function(player)
|
||||
player.admin = true
|
||||
end)
|
||||
|
||||
-- This will allow us to bypass the error by running one tick later outside of any player scope
|
||||
Async(promote_player, game.player)
|
||||
|
||||
-- Here we make an sync function that we want to have a delay, note the delay is not defined here
|
||||
local print_message =
|
||||
Async.register(function(player, message)
|
||||
player.print(message)
|
||||
end)
|
||||
|
||||
-- We can then call the async function with a delay using the wait function
|
||||
Async.wait(60, print_message, game.player, 'One second has passed!')
|
||||
|
||||
]]
|
||||
local Task = require 'utils.task' --- @dep utils.task
|
||||
local Token = require 'utils.token' --- @dep utils.token
|
||||
|
||||
local Async = {}
|
||||
|
||||
local internal_run =
|
||||
Token.register(function(params)
|
||||
local func = Token.get(params.token)
|
||||
return func(table.unpack(params.params))
|
||||
end)
|
||||
|
||||
--[[-- Register a new async function, must called when the file is loaded
|
||||
@function register
|
||||
@tparam function callback the function that can be called as an async function
|
||||
@treturn string the uid of the async function which can be passed to Async.run and Async.wait
|
||||
|
||||
@usage-- Registering a function to set the admin state of a player
|
||||
local set_admin =
|
||||
Async.register(function(player, state)
|
||||
if player.valid then
|
||||
player.admin = state
|
||||
end
|
||||
end)
|
||||
|
||||
@usage-- Registering a function to print to a player
|
||||
local print_to_player =
|
||||
Async.register(function(player, message)
|
||||
if player.valid then
|
||||
player.print(message)
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
Async.register = Token.register
|
||||
|
||||
--[[-- Runs an async function, you may supply any number of arguments as required by that function
|
||||
@tparam string token the token of the async function you want to run
|
||||
@tparam[opt] any ... the other params that you want to pass to your function
|
||||
|
||||
@usage-- Make a player admin regardless of if you are admin
|
||||
Async.run(set_admin, player, true)
|
||||
|
||||
]]
|
||||
function Async.run(token, ...)
|
||||
Task.queue_task(internal_run, {
|
||||
token = token,
|
||||
params = {...}
|
||||
})
|
||||
end
|
||||
|
||||
--[[-- Runs an async function after the given number of ticks, you may supply any number of arguments as required by that function
|
||||
@tparam number ticks the number of ticks that you want the function to run after
|
||||
@tparam string token the token of the async function you want to run
|
||||
@tparam[opt] any ... the other params that you want to pass to your function
|
||||
|
||||
@usage-- Print a message to a player after 5 seconds
|
||||
Async.wait(300, print_to_player, 'Hello, World!')
|
||||
|
||||
]]
|
||||
function Async.wait(ticks, token, ...)
|
||||
Task.set_timeout_in_ticks(ticks, internal_run, {
|
||||
token = token,
|
||||
params = {...}
|
||||
})
|
||||
end
|
||||
|
||||
return setmetatable(Async, {
|
||||
__call = function(self, ...)
|
||||
self.run(...)
|
||||
end
|
||||
})
|
||||
883
exp_legacy/module/expcore/commands.lua
Normal file
883
exp_legacy/module/expcore/commands.lua
Normal file
@@ -0,0 +1,883 @@
|
||||
--[[-- Core Module - Commands
|
||||
- Factorio command making module that makes commands with better parse and more modularity
|
||||
@core Commands
|
||||
@alias Commands
|
||||
|
||||
@usage--- Full code example, see below for explanation
|
||||
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
|
||||
:add_param('repeat-count', 'number-range-int', 1, 5) -- required int in range 1 to 5 inclusive
|
||||
:add_param('smiley', true, function(input, player, reject) -- optional boolean default false
|
||||
if not input then return end
|
||||
input = input:lower()
|
||||
if input == 'true' or input == 'yes' then return true end
|
||||
return false
|
||||
end)
|
||||
:set_defaults{ smiley = false }
|
||||
:set_flag('admin_only') -- command is admin only
|
||||
:add_alias('name', 'rname') -- allow alias: name and rname
|
||||
:register(function(player, repeat_count, smiley, raw)
|
||||
game.print(player.name..' used a command with input: '..raw)
|
||||
|
||||
local msg = ') '..player.name
|
||||
if smiley then
|
||||
msg = ':'..msg
|
||||
end
|
||||
|
||||
for 1 = 1, repeat_count do
|
||||
Command.print(1..msg)
|
||||
end
|
||||
end)
|
||||
|
||||
@usage--- Example Command Explanation:
|
||||
-- Making commands basics, the commands can be set up with any number of params and flags that you want,
|
||||
-- you can add aliases for the commands and set default values for optional params and of course register your command callback.
|
||||
-- In our example we will have a command that will repeat the users name in chat X amount of times and only allow admins to use it.
|
||||
|
||||
-- First we create the new command, note this will not register the command to the game this is done at the end.
|
||||
-- We will call the command "repeat-name" and set the help message as follows:
|
||||
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
|
||||
|
||||
-- Now for our first param, we have named it "repeat-count" and it will be a required value, between 1 and 5 inclusive:
|
||||
-- By using "number-range-int" we are saying to use this parser to convert our input text, common ones exist in config.expcore.command_general_parse
|
||||
:add_param('repeat-count', 'number-range-int', 1, 5)
|
||||
|
||||
-- Our second param needs a custom parser, meaning it isnt defined with add_parser, this is an option for when it is unlikely for
|
||||
-- any other command to use the same input type. In the example it is a boolean type and we are just showing it here as part of the example.
|
||||
-- As for the param its self it will be called "smiley" and will be optional with a default value of false:
|
||||
:add_param('smiley', true, function(input, player, reject)
|
||||
-- Since it is optional the input can be nil, in which case we just return
|
||||
if not input then return end
|
||||
-- If it is not nil then we check for a truthy value
|
||||
if input == 'true' or input == 'yes' then return true end
|
||||
-- Note that because we did not return nil or reject then false will be passed to command callback, see example parse
|
||||
return false
|
||||
end)
|
||||
|
||||
-- Once all params are defined you can add some default values for your optional params, the default value will be used only
|
||||
-- when no value is given as input, if an invalid value is given then the command will fail and the default will not be used, the
|
||||
-- default can also be a function which is passed the player as an argument and should return a value to be the default.
|
||||
-- Here we set the default for "smiley" to false:
|
||||
:set_defaults{smiley=false}
|
||||
|
||||
-- Another example of defaults if we have: item, amount[opt], player[opt]
|
||||
:set_defaults{
|
||||
amount = 50, -- More than one value can be set at a time
|
||||
player = function(player) return player end -- Default is the player using the command
|
||||
}
|
||||
|
||||
-- Now the params are set up we can alter how the command works, we can set auth flags, add aliases, or enable "auto concat":
|
||||
:set_flag('admin_only') -- In our case we want "admin_only" to be set to true so only admins can use the command
|
||||
:add_alias('name', 'rname') -- We also add two aliases here: "name" and "rname" which point to this command
|
||||
-- :enable_auto_concat() -- We do not use this in our case but this can also be used to enable the "auto concat" feature
|
||||
|
||||
-- And finally we want to register a callback to this command, the callback is what defines what the command does, can be as complex as you
|
||||
-- want it to be, or as simple as our example; the command receives two params plus all param you have defined:
|
||||
-- 1) the player who used the command
|
||||
-- 2) in our case repeat_count which will be a number
|
||||
-- 3) in our case smiley which will be a boolean
|
||||
-- 4) the raw input; this param is always last as is always present as a catch all
|
||||
:register(function(player, repeat_count, smiley, raw)
|
||||
-- This is to show the value for raw as this is an example command, the log file will also show this
|
||||
game.print(player.name..' used a command with input: '..raw)
|
||||
local msg = ') '..player.name
|
||||
|
||||
if smiley then
|
||||
msg = ':'..msg
|
||||
end
|
||||
|
||||
for 1 = 1, repeat_count do
|
||||
-- this print function will return ANY value to the user in a desync safe manor, this includes if the command was used through rcon
|
||||
Command.print(1..msg)
|
||||
end
|
||||
-- See below for what can be used here
|
||||
end)
|
||||
|
||||
-- Values that can be returned from register callback
|
||||
Commands.print(any, colour[opt]) -- This will return any value value to the user including if it is ran through rcon console
|
||||
Commands.error(message[opt]) -- This returns a warning to the user, aka an error that does not prevent execution of the command
|
||||
return Commands.error(message[opt]) -- This returns an error to the user, and will halt the command execution, ie no success message is returned
|
||||
Commands.success(message[opt]) -- Used to return a success message however don't use this method, see below
|
||||
return Commands.success(message[opt]) -- Will return the success message to the user and your given message, halts execution
|
||||
return <any> -- If any value is returned then it will be returned to the player via a Commands.success call
|
||||
|
||||
@usage--- Example Authenticator:
|
||||
-- The command system is best used when you can control who uses commands;
|
||||
-- to do this you need to define an authenticator which is ran every time a command is run;
|
||||
-- in this example I will show a simple one that requires certain commands to require the user to be a game admin.
|
||||
|
||||
-- For our admin only example we will set a flag to true when we want it to be admin only;
|
||||
-- when we define the command will will use :set_flag('admin_only');
|
||||
-- then inside the authenticator we will test if the flag is present using: if flags.admin_only then
|
||||
|
||||
-- When the authenticator is called by the command handler it will be passed 4 arguments:
|
||||
-- 1) player - the player who used the command
|
||||
-- 2) command - the name of the command that is being used
|
||||
-- 3) flags - the flags which have been set for this command, flags are set with :set_flag(name, value)
|
||||
-- 4) reject - the reject function which is the preferred method to prevent execution of the command
|
||||
|
||||
-- No return is required to allow the command to execute but it is best practice to return true;
|
||||
-- we do this in two cases in our authenticator:
|
||||
-- 1) when the "admin_only" flag is not set, which we take assume that any one can use it
|
||||
-- 2) when the "admin_only" flag is set, and the player is admin
|
||||
|
||||
-- When want to prevent execution of the command we must reject it, listed is how that can be done:
|
||||
-- 1) return false -- this is the most basic rejection and should only be used while testing
|
||||
-- 2) return reject -- returning the reject function is as a fail safe in case you forget to call it, same as returning false
|
||||
-- 3) reject() -- this will block execution while allowing further code to be ran in your authenticator
|
||||
-- 4) reject('This command is for admins only!') -- using reject as a function allows a error message to be returned
|
||||
-- 5) return reject() -- using return on either case above is best practice as you should execute all your code before rejecting
|
||||
|
||||
-- Example Code:
|
||||
Commands.add_authenticator(function(player, command, flags, reject)
|
||||
-- Check if the command is admin only
|
||||
if flags.admin_only then
|
||||
-- Return true if player is admin, or reject and return error message
|
||||
return player.admin or reject('This command is for admins only!')
|
||||
else
|
||||
-- Return true if command was not admin only
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
@usage--- Example Parser:
|
||||
-- Before you make a command it is important to understand the most powerful feature of this command handler;
|
||||
-- when you define a command you are able to type the params and have then be parsed and validated before your command is executed;
|
||||
-- This module should be paired with a general command parse but you may want to create your own.
|
||||
|
||||
-- For our example we will create a parse to accept only integer numbers in a given range:
|
||||
-- 1) we will give it the name "number-range-int" this is the "type" that the input is expected to be
|
||||
-- 2) when we define the type we will also define the min and max of the range so we can use the function more than once
|
||||
:add_param('repeat_count', 'number-range-int', 5, 10) -- "repeat_count" is a required "number-range-int" in a range 5 to 10 inclusive
|
||||
|
||||
-- The command parse will be passed 3 arguments plus any other which you define, in our case:
|
||||
-- 1) input - the input that has been given by the user for this param, the role of this function is to transform this value
|
||||
-- nb: the input is a string but can be nil if the param is marked as optional
|
||||
-- 2) player - the player who is using the command, this is always present
|
||||
-- 3) reject - the reject function to throw an error to the user, this is always present
|
||||
-- 4) range_min - the range min, this is user defined and has the value given when the param is defined
|
||||
-- 5) range_max - the range max, this is user defined and has the value given when the param is defined
|
||||
|
||||
-- When returning from the param parse you have a few options with how to do this:
|
||||
-- 1) you return the new value for the param (any non nil value) this value is then passed to the command callback
|
||||
-- 2) not returning will cause a generic invalid error and the command is rejected, not recommenced
|
||||
-- 3) return reject -- this is just a failsafe in case the function is not called, same as no return
|
||||
-- 4) return reject() -- will give a shorter error message as you pass a nil custom error
|
||||
-- 5) return reject('Number entered is not in range: '..range_min..', '..range_max) -- returns a custom error to the user
|
||||
-- nb: if you do not return reject after you call it then you will still be returning nil so there will be a duplicate error message
|
||||
|
||||
-- It should be noted that if you want to expand on an existing parse you can use Commands.parse(type, input, player, reject)
|
||||
-- this function will either return a new value for the input or nil, if it is nil you should return nil to prevent duplicate
|
||||
-- error messages to the user:
|
||||
input = Commands.parse('number-int', input, player, reject)
|
||||
if not input then return end -- nil check
|
||||
|
||||
-- Example Code:
|
||||
Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max)
|
||||
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number
|
||||
if not rtn or rtn < range_min or rtn > range_max then
|
||||
-- the input is either not a number or is outside the range
|
||||
return reject('Number entered is not in range: '..range_min..', '..range_max)
|
||||
else
|
||||
-- returns the input as a number value rather than a string, thus the param is now the correct type
|
||||
return rtn
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local player_return, write_json = _C.player_return, _C.write_json --- @dep expcore.common
|
||||
local trace = debug.traceback
|
||||
|
||||
local Commands = {
|
||||
--- Constant values used by the command system
|
||||
defines = {
|
||||
error = 'CommandError',
|
||||
unauthorized = 'CommandErrorUnauthorized',
|
||||
success = 'CommandSuccess'
|
||||
},
|
||||
--- An array of all custom commands that are registered
|
||||
commands = {},
|
||||
--- When true any authenticator error will result in authorization failure, more secure
|
||||
authorization_failure_on_error = false,
|
||||
--- An array of all custom authenticators that are registered
|
||||
authenticators = {},
|
||||
--- Used to store default functions which are common parse function such as player or number in range
|
||||
parsers = {},
|
||||
--- Returns a value to the player, different to success as this does not signal the end of your command
|
||||
print = player_return,
|
||||
--- The command prototype which stores all command defining functions
|
||||
_prototype = {},
|
||||
}
|
||||
|
||||
--- Authentication.
|
||||
-- Functions that control who can use commands
|
||||
-- @section auth
|
||||
|
||||
--[[-- Adds an authorization function, function used to check if a player if allowed to use a command
|
||||
@tparam function authenticator The function you want to register as an authenticator
|
||||
@treturn number The index it was inserted at, used to remove the authenticator
|
||||
|
||||
@usage-- If the admin_only flag is set, then make sure the player is an admin
|
||||
local admin_authenticator =
|
||||
Commands.add_authenticator(function(player, command, flags, reject)
|
||||
if flags.admin_only and not player.admin then
|
||||
return reject('This command is for admins only!')
|
||||
else
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
function Commands.add_authenticator(authenticator)
|
||||
local next_index = #Commands.authenticators + 1
|
||||
Commands.authenticators[next_index] = authenticator
|
||||
return next_index
|
||||
end
|
||||
|
||||
--[[-- Removes an authorization function, can use the index or the function value
|
||||
@tparam function|number authenticator The authenticator to remove, either the index return from add_authenticator or the function used
|
||||
@treturn boolean If the authenticator was found and removed successfully
|
||||
|
||||
@usage-- Removing the admin authenticator, can not be done during runtime
|
||||
Commands.remove_authenticator(admin_authenticator)
|
||||
|
||||
]]
|
||||
function Commands.remove_authenticator(authenticator)
|
||||
if type(authenticator) == 'number' then
|
||||
-- If a number is passed then it is assumed to be the index
|
||||
if Commands.authenticators[authenticator] then
|
||||
Commands.authenticators[authenticator] = nil
|
||||
return true
|
||||
end
|
||||
else
|
||||
-- will search the array and remove the key
|
||||
for index, value in pairs(Commands.authenticators) do
|
||||
if value == authenticator then
|
||||
Commands.authenticators[index] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[-- Mostly used internally, calls all authenticators, returns if the player is authorized
|
||||
@tparam LuaPlayer player The player who is using the command, passed to authenticators
|
||||
@tparam string command_name The name of the command being used, passed to authenticators
|
||||
@treturn[1] boolean true Player is authorized
|
||||
@treturn[1] string commands Define value for success
|
||||
@treturn[2] boolean false Player is unauthorized
|
||||
@treturn[2] string|locale_string The reason given by the failed authenticator
|
||||
|
||||
@usage-- Test if a player can use "repeat-name"
|
||||
local authorized, status = Commands.authorize(game.player, 'repeat-name')
|
||||
|
||||
]]
|
||||
function Commands.authorize(player, command_name)
|
||||
local command_data = Commands.commands[command_name]
|
||||
if not command_data then return false end
|
||||
if not player then return true end
|
||||
|
||||
-- This is the reject function given to authenticators
|
||||
local failure_message
|
||||
local function reject(message)
|
||||
failure_message = message or {'expcore-commands.unauthorized'}
|
||||
return Commands.defines.unauthorized
|
||||
end
|
||||
|
||||
-- This is the internal error function used when an authenticator errors
|
||||
local function authenticator_error(err)
|
||||
log('[ERROR] Authorization failed: '..trace(err))
|
||||
if Commands.authorization_failure_on_error then
|
||||
return reject('Internal Error')
|
||||
end
|
||||
end
|
||||
|
||||
-- Loops over each authenticator, if any return false then then command will not be ran
|
||||
for _, authenticator in pairs(Commands.authenticators) do
|
||||
-- player: LuaPlayer, command: string, flags: table, reject: function(error_message: string)
|
||||
local _, rtn = xpcall(authenticator, authenticator_error, player, command_name, command_data.flags, reject)
|
||||
if rtn == false or rtn == Commands.defines.unauthorized or rtn == reject or failure_message ~= nil then
|
||||
if failure_message == nil then failure_message = {'expcore-commands.unauthorized'} end
|
||||
return false, failure_message
|
||||
end
|
||||
end
|
||||
|
||||
return true, Commands.defines.success
|
||||
end
|
||||
|
||||
--- Parse.
|
||||
-- Functions that help with parsing
|
||||
-- @section parse
|
||||
|
||||
--[[-- Adds a parse function which can be called by name (used in add_param)
|
||||
nb: this is not required as you can use the callback directly this just allows it to be called by name
|
||||
@tparam string name The name of the parse, should describe a type of input such as number or player, must be unique
|
||||
@tparam function parser The function that is ran to parse the input string
|
||||
@treturn boolean Was the parse added, will be false if the name is already used
|
||||
|
||||
@usage-- Adding a parse to validate integers in a given range
|
||||
Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max)
|
||||
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number
|
||||
if not rtn or rtn < range_min or rtn > range_max then
|
||||
-- The input is either not a number or is outside the range
|
||||
return reject('Number entered is not in range: '..range_min..', '..range_max)
|
||||
else
|
||||
-- Returns the input as a number rather than a string, thus the param is now the correct type
|
||||
return rtn
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
function Commands.add_parse(name, parser)
|
||||
if Commands.parsers[name] then return false end
|
||||
Commands.parsers[name] = parser
|
||||
return true
|
||||
end
|
||||
|
||||
--[[-- Removes a parse function, see add_parse for adding them, cant be done during runtime
|
||||
@tparam string name The name of the parse to remove
|
||||
|
||||
@usage-- Removing a parse
|
||||
Commands.remove_parse('number-range-int')
|
||||
|
||||
]]
|
||||
function Commands.remove_parse(name)
|
||||
Commands.parsers[name] = nil
|
||||
end
|
||||
|
||||
--[[-- Intended to be used within other parse functions, runs a parse and returns success and new value
|
||||
@tparam string name The name of the parse to call, must be a registered parser
|
||||
@tparam string input The input to pass to the parse, must be a string but not necessarily the original input
|
||||
@tparam LuaPlayer player The player that is using the command, pass directly from your arguments
|
||||
@tparam function reject The reject function, pass directly from your arguments
|
||||
@treturn any The new value for the input, if nil is return then either there was an error or the input was nil
|
||||
|
||||
@usage-- Parsing an int after first checking it is a number
|
||||
Commands.add_parse('number', function(input, player, reject)
|
||||
local number = tonumber(input)
|
||||
if number then return number end
|
||||
return reject('Input must be a number value')
|
||||
end)
|
||||
|
||||
Commands.add_parse('number-int', function(input, player, reject)
|
||||
local number = Commands.parse('number', input, player, reject)
|
||||
if not number then return end
|
||||
return math.floor(number)
|
||||
end)
|
||||
|
||||
]]
|
||||
function Commands.parse(name, input, player, reject, ...)
|
||||
if not Commands.parsers[name] then return end
|
||||
local success, rtn = pcall(Commands.parsers[name], input, player, reject, ...)
|
||||
if not success then error(rtn, 2) return end
|
||||
if not rtn or rtn == Commands.defines.error then return end
|
||||
return rtn
|
||||
end
|
||||
|
||||
--- Getters.
|
||||
-- Functions that get commands
|
||||
-- @section getters
|
||||
|
||||
--[[-- Gets all commands that a player is allowed to use, game commands are not included
|
||||
@tparam[opt] LuaPlayer player The player that you want to get commands of, nil will return all commands
|
||||
@treturn table All commands that that player is allowed to use, or all commands
|
||||
|
||||
@usage-- Get the commands you are allowed to use
|
||||
local commands = Commands.get(game.player)
|
||||
|
||||
@usage-- Get all commands that are registered
|
||||
local commands = Commands.get()
|
||||
|
||||
]]
|
||||
function Commands.get(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
|
||||
if not player then
|
||||
return Commands.commands
|
||||
end
|
||||
|
||||
local allowed = {}
|
||||
|
||||
for name, command_data in pairs(Commands.commands) do
|
||||
if Commands.authorize(player, name) then
|
||||
allowed[name] = command_data
|
||||
end
|
||||
end
|
||||
|
||||
return allowed
|
||||
end
|
||||
|
||||
--[[-- Searches command names and help messages to find possible commands, game commands are included
|
||||
@tparam string keyword The word which you are trying to find in your search
|
||||
@tparam[opt] LuaPlayer player The player to get allowed commands of, if nil all commands are searched
|
||||
@treturn table All commands that contain the key word, and allowed by the player if a player was given
|
||||
|
||||
@usage-- Get all commands which "repeat"
|
||||
local commands = Commands.search('repeat')
|
||||
|
||||
@usage-- Get all commands which "repeat" and you are allowed to use
|
||||
local commands = Commands.search('repeat', game.player)
|
||||
|
||||
]]
|
||||
function Commands.search(keyword, player)
|
||||
local custom_commands = Commands.get(player)
|
||||
local matches = {}
|
||||
keyword = keyword:lower()
|
||||
|
||||
-- Loops over custom commands
|
||||
for name, command_data in pairs(custom_commands) do
|
||||
-- combines name help and aliases into one message to be searched
|
||||
local search = string.format('%s %s %s %s', name, command_data.help, command_data.searchable_description, table.concat(command_data.aliases, ' '))
|
||||
|
||||
if search:lower():match(keyword) then
|
||||
matches[name] = command_data
|
||||
end
|
||||
end
|
||||
|
||||
-- Loops over the names of game commands
|
||||
for name, description in pairs(commands.game_commands) do
|
||||
if name:lower():match(keyword) then
|
||||
-- because game commands lack some stuff that the custom ones have they are formatted
|
||||
matches[name] = {
|
||||
name = name,
|
||||
help = description,
|
||||
description = '',
|
||||
aliases = {}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
--- Creation.
|
||||
-- Functions that create a new command
|
||||
-- @section creation
|
||||
|
||||
--[[-- Creates a new command object to added details to, this does not register the command to the game api
|
||||
@tparam string name The name of the command to be created
|
||||
@tparam string help The help message for the command
|
||||
@treturn table This will be used with other functions to define the new command
|
||||
|
||||
@usage-- Define a new command
|
||||
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
|
||||
|
||||
]]
|
||||
function Commands.new_command(name, help, descr)
|
||||
local command = setmetatable({
|
||||
name = name,
|
||||
help = help,
|
||||
searchable_description = descr or '',
|
||||
callback = function() Commands.internal_error(false, name, 'No callback registered') end,
|
||||
auto_concat = false,
|
||||
min_param_count = 0,
|
||||
max_param_count = 0,
|
||||
flags = {}, -- stores flags that can be used by auth
|
||||
aliases = {}, -- stores aliases to this command
|
||||
params = {}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table}
|
||||
}, {
|
||||
__index = Commands._prototype
|
||||
})
|
||||
|
||||
Commands.commands[name] = command
|
||||
|
||||
return command
|
||||
end
|
||||
|
||||
--[[-- Adds a new param to the command this will be displayed in the help and used to parse the input
|
||||
@tparam string name The name of the new param that is being added to the command
|
||||
@tparam[opt=false] boolean optional Is this param optional, these must be added after all required params
|
||||
@tparam[opt] ?string|function parse This function will take the input and return a new value, if not given no parse is done
|
||||
@tparam[opt] any ... Extra args you want to pass to the parse function; for example if the parse is general use
|
||||
@treturn table Pass through to allow more functions to be called
|
||||
|
||||
@usage-- Adding a required param which has a parser pre-defined
|
||||
command:add_param('repeat-count', 'number-range-int', 1, 5)
|
||||
|
||||
@usage-- Adding an optional param which has a custom parse, see Commands.add_parse for details
|
||||
command:add_param('smiley', true, function(input, player, reject)
|
||||
if not input then return end
|
||||
return input:lower() == 'true' or input:lower() == 'yes' or false
|
||||
end)
|
||||
|
||||
]]
|
||||
function Commands._prototype:add_param(name, optional, parse, ...)
|
||||
local parse_args = {...}
|
||||
if type(optional) ~= 'boolean' then
|
||||
parse_args = {parse, ...}
|
||||
parse = optional
|
||||
optional = false
|
||||
end
|
||||
|
||||
self.params[name] = {
|
||||
optional = optional,
|
||||
parse = parse or function(string) return string end,
|
||||
parse_args = parse_args
|
||||
}
|
||||
|
||||
self.max_param_count = self.max_param_count + 1
|
||||
if not optional then
|
||||
self.min_param_count = self.min_param_count + 1
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Add default values to params, only as an effect if the param is optional, if default value is a function it is called with the acting player
|
||||
@tparam table defaults A table which is keyed by the name of the param and the value is the default value for that param
|
||||
@treturn table Pass through to allow more functions to be called
|
||||
|
||||
@usage-- Adding default values
|
||||
command:set_defaults{
|
||||
smiley = false,
|
||||
-- not in example just used to show arguments given
|
||||
player_name = function(player)
|
||||
return player.name
|
||||
end
|
||||
}
|
||||
|
||||
]]
|
||||
function Commands._prototype:set_defaults(defaults)
|
||||
for name, value in pairs(defaults) do
|
||||
if self.params[name] then
|
||||
self.params[name].default = value
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Adds a flag to the command which is passed via the flags param to the authenticators, can be used to assign command roles or usage type
|
||||
@tparam string name The name of the flag to be added, set to true if no value is given
|
||||
@tparam[opt=true] any value The value for the flag, can be anything that the authenticators are expecting
|
||||
@treturn table Pass through to allow more functions to be called
|
||||
|
||||
@usage-- Setting a custom flag
|
||||
command:set_flag('admin_only', true)
|
||||
|
||||
@usage-- When value is true it does not need to be given
|
||||
command:set_flag('admin_only')
|
||||
|
||||
]]
|
||||
function Commands._prototype:set_flag(name, value)
|
||||
self.flags[name] = value or true
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Adds an alias, or multiple, that will be registered to this command, eg /teleport can be used as /tp
|
||||
@tparam string ... Any amount of aliases that you want this command to be callable with
|
||||
@treturn table Pass through to allow more functions to be called
|
||||
|
||||
@usage-- Added multiple aliases to a command
|
||||
command:add_alias('name', 'rname')
|
||||
|
||||
]]
|
||||
function Commands._prototype:add_alias(...)
|
||||
local start_index = #self.aliases
|
||||
for index, alias in ipairs{...} do
|
||||
self.aliases[start_index+index] = alias
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Enables auto concatenation for this command, all params after the last are added to the last param, useful for reasons or other long text input
|
||||
nb: this will disable max param checking as they will be concatenated onto the end of that last param
|
||||
@treturn table Pass through to allow more functions to be called
|
||||
|
||||
@usage-- Enable auto concat for a command
|
||||
command:enable_auto_concat()
|
||||
|
||||
]]
|
||||
function Commands._prototype:enable_auto_concat()
|
||||
self.auto_concat = true
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Adds the callback to the command and registers: aliases, params and help message with the base game api
|
||||
nb: this must be the last function ran on the command and must be done for the command to work
|
||||
@tparam function callback The callback for the command, will receive the player running command, and any params added with add_param
|
||||
|
||||
@usage-- Registering your command to the base game api
|
||||
command:register(function(player, repeat_count, smiley, raw)
|
||||
local msg = ') '..player.name
|
||||
if smiley then msg = ':'..msg end
|
||||
|
||||
for 1 = 1, repeat_count do
|
||||
Command.print(1..msg)
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
function Commands._prototype:register(callback)
|
||||
self.callback = callback
|
||||
|
||||
-- Generates a description to be used
|
||||
local description = ''
|
||||
for param_name, param_details in pairs(self.params) do
|
||||
if param_details.optional then
|
||||
description = string.format('%s [%s]', description, param_name)
|
||||
else
|
||||
description = string.format('%s <%s>', description, param_name)
|
||||
end
|
||||
end
|
||||
self.description = description
|
||||
|
||||
-- Last resort error handler for commands
|
||||
local function command_error(err)
|
||||
Commands.internal_error(false, self.name, trace(err))
|
||||
end
|
||||
|
||||
-- Callback that the game will call
|
||||
local function command_callback(event)
|
||||
event.name = self.name
|
||||
xpcall(Commands.run_command, command_error, event)
|
||||
end
|
||||
|
||||
-- Registers the command under its own name
|
||||
local help = {'expcore-commands.command-help', description, self.help}
|
||||
commands.add_command(self.name, help, command_callback)
|
||||
|
||||
-- Adds any aliases that it has
|
||||
for _, alias in pairs(self.aliases) do
|
||||
if not commands.commands[alias] and not commands.game_commands[alias] then
|
||||
commands.add_command(alias, help, command_callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Status.
|
||||
-- Functions that indicate status
|
||||
-- @section status
|
||||
|
||||
--[[-- Sends a value to the player, followed by a command complete message, returning a value will trigger this automatically
|
||||
@tparam[opt] any value The value to return to the player, if nil then only the success message is returned
|
||||
@treturn Commands.defines.success Return this to the command handler to prevent two success messages
|
||||
|
||||
@usage-- Print a custom success message
|
||||
return Commands.success('Your message has been printed')
|
||||
|
||||
@usage-- Returning the value has the same result
|
||||
return 'Your message has been printed'
|
||||
|
||||
]]
|
||||
function Commands.success(value)
|
||||
if value ~= nil then player_return(value) end
|
||||
player_return({'expcore-commands.command-ran'}, 'cyan')
|
||||
return Commands.defines.success
|
||||
end
|
||||
|
||||
--[[-- Sends a value to the player, different to success as this does not signal the end of your command
|
||||
@function print
|
||||
@tparam any value The value that you want to return to the player
|
||||
@tparam table colour The colour of the message that the player sees
|
||||
|
||||
@usage-- Output a message to the player
|
||||
Commands.print('Your command is in progress')
|
||||
|
||||
]]
|
||||
|
||||
--[[-- Sends an error message to the player and when returned will stop execution of the command
|
||||
nb: this is for non fatal errors meaning there is no log of this event, use during register callback
|
||||
@tparam[opt=''] string error_message An optional error message that can be sent to the user
|
||||
@tparam[opt=utility/wire_pickup] string play_sound The sound to play for the error
|
||||
@treturn Commands.defines.error Return this to command handler to terminate execution
|
||||
|
||||
@usage-- Send an error message to the player, and stops further code running
|
||||
return Commands.error('The player you selected is offline')
|
||||
|
||||
]]
|
||||
function Commands.error(error_message, play_sound)
|
||||
error_message = error_message or ''
|
||||
player_return({'expcore-commands.command-fail', error_message}, 'orange_red')
|
||||
if play_sound ~= false then
|
||||
play_sound = play_sound or 'utility/wire_pickup'
|
||||
if game.player then game.player.play_sound{path=play_sound} end
|
||||
end
|
||||
return Commands.defines.error
|
||||
end
|
||||
|
||||
--[[-- Sends an error to the player and logs the error, used internally please avoid direct use
|
||||
nb: use error(error_message) within your callback to trigger do not trigger directly as code execution may still continue
|
||||
@tparam boolean success The success value returned from pcall, or just false to trigger error
|
||||
@tparam string command_name The name of the command this is used within the log
|
||||
@tparam string error_message The error returned by pcall or some other error, this is logged and not returned to player
|
||||
@treturn boolean The opposite of success so true means to cancel execution, used internally
|
||||
|
||||
@usage-- Used in the command system to log handler errors
|
||||
local success, err = pcall(command_data.callback, player, table.unpack(params))
|
||||
if Commands.internal_error(success, command_data.name, err) then
|
||||
return command_log(player, command_data, 'Internal Error: Command Callback Fail', raw_params, command_event.parameter, err)
|
||||
end
|
||||
|
||||
]]
|
||||
function Commands.internal_error(success, command_name, error_message)
|
||||
if not success then
|
||||
Commands.error('Internal Error, Please contact an admin', 'utility/cannot_build')
|
||||
log{'expcore-commands.command-error-log-format', command_name, error_message}
|
||||
end
|
||||
return not success
|
||||
end
|
||||
|
||||
--- Logs command usage to file
|
||||
local function command_log(player, command, comment, params, raw, details)
|
||||
local player_name = player and player.name or '<Server>'
|
||||
write_json('log/commands.log', {
|
||||
player_name = player_name,
|
||||
command_name = command.name,
|
||||
comment = comment,
|
||||
details = details,
|
||||
params = params,
|
||||
raw = raw
|
||||
})
|
||||
end
|
||||
|
||||
--- Main event function that is ran for all commands, used internally please avoid direct use
|
||||
-- @tparam table command_event Passed directly from the add_command function
|
||||
-- @usage Commands.run_command(event)
|
||||
function Commands.run_command(command_event)
|
||||
local command_data = Commands.commands[command_event.name]
|
||||
-- Player can be nil when it is the server
|
||||
local player
|
||||
if command_event.player_index and command_event.player_index > 0 then
|
||||
player = game.players[command_event.player_index]
|
||||
end
|
||||
|
||||
-- Check if the player is allowed to use the command
|
||||
local authorized, auth_fail = Commands.authorize(player, command_data.name)
|
||||
if not authorized then
|
||||
command_log(player, command_data, 'Failed Auth', {}, command_event.parameter)
|
||||
Commands.error(auth_fail, 'utility/cannot_build')
|
||||
return
|
||||
end
|
||||
|
||||
-- Check for parameter being nil
|
||||
if command_data.min_param_count > 0 and not command_event.parameter then
|
||||
command_log(player, command_data, 'No Params Given', {}, command_event.parameter)
|
||||
Commands.error{'expcore-commands.invalid-inputs', command_data.name, command_data.description}
|
||||
return
|
||||
end
|
||||
|
||||
-- Extract quoted arguments
|
||||
local raw_input = command_event.parameter or ''
|
||||
local quote_params = {}
|
||||
local input_string = raw_input:gsub('"[^"]-"', function(word)
|
||||
local no_spaces = word:gsub('%s', '%%s')
|
||||
quote_params[no_spaces] = word:sub(2, -2)
|
||||
return ' '..no_spaces..' '
|
||||
end)
|
||||
|
||||
-- Extract unquoted arguments
|
||||
local raw_params = {}
|
||||
local last_index = 0
|
||||
local param_number = 0
|
||||
for word in input_string:gmatch('%S+') do
|
||||
param_number = param_number + 1
|
||||
if param_number > command_data.max_param_count then
|
||||
-- there are too many params given to the command
|
||||
if not command_data.auto_concat then
|
||||
-- error as they should not be more
|
||||
command_log(player, command_data, 'Invalid Input: Too Many Params', raw_params, raw_input)
|
||||
Commands.error{'expcore-commands.invalid-inputs', command_data.name, command_data.description}
|
||||
return
|
||||
else
|
||||
-- concat to the last param
|
||||
if quote_params[word] then
|
||||
raw_params[last_index] = raw_params[last_index]..' "'..quote_params[word]..'"'
|
||||
else
|
||||
raw_params[last_index] = raw_params[last_index]..' '..word
|
||||
end
|
||||
end
|
||||
else
|
||||
-- new param that needs to be added
|
||||
if quote_params[word] then
|
||||
last_index = last_index + 1
|
||||
raw_params[last_index] = quote_params[word]
|
||||
else
|
||||
last_index = last_index + 1
|
||||
raw_params[last_index] = word
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check the param count
|
||||
local param_count = #raw_params
|
||||
if param_count < command_data.min_param_count then
|
||||
command_log(player, command_data, 'Invalid Input: Not Enough Params', raw_params, raw_input)
|
||||
Commands.error{'expcore-commands.invalid-inputs', command_data.name, command_data.description}
|
||||
return
|
||||
end
|
||||
|
||||
-- Parse the arguments
|
||||
local index = 1
|
||||
local params = {}
|
||||
for param_name, param_data in pairs(command_data.params) do
|
||||
local parse_callback = param_data.parse
|
||||
-- If its a string this get it from the parser table
|
||||
if type(parse_callback) == 'string' then
|
||||
parse_callback = Commands.parsers[parse_callback]
|
||||
end
|
||||
|
||||
-- If its not a function throw and error
|
||||
if type(parse_callback) ~= 'function' then
|
||||
Commands.internal_error(false, command_data.name, 'Invalid param parse '..tostring(param_data.parse))
|
||||
command_log(player, command_data, 'Internal Error: Invalid Param Parse', params, raw_input, tostring(param_data.parse))
|
||||
return
|
||||
end
|
||||
|
||||
-- This is the reject function given to parse callbacks
|
||||
local function reject(error_message)
|
||||
error_message = error_message or ''
|
||||
command_log(player, command_data, 'Invalid Param Given', raw_params, input_string)
|
||||
return Commands.error{'expcore-commands.invalid-param', param_name, error_message}
|
||||
end
|
||||
|
||||
-- input: string, player: LuaPlayer, reject: function, ... extra args
|
||||
local success, param_parsed = pcall(parse_callback, raw_params[index], player, reject, table.unpack(param_data.parse_args))
|
||||
if Commands.internal_error(success, command_data.name, param_parsed) then
|
||||
return command_log(player, command_data, 'Internal Error: Param Parse Fail', params, raw_input, param_parsed)
|
||||
end
|
||||
|
||||
if param_data.optional == true and raw_params[index] == nil then
|
||||
-- If the param is optional and nil then it is set to default
|
||||
param_parsed = param_data.default
|
||||
if type(param_parsed) == 'function' then
|
||||
success, param_parsed = pcall(param_parsed, player)
|
||||
if Commands.internal_error(success, command_data.name, param_parsed) then
|
||||
return command_log(player, command_data, 'Internal Error: Default Value Fail', params, raw_input, param_parsed)
|
||||
end
|
||||
end
|
||||
|
||||
elseif param_parsed == nil or param_parsed == Commands.defines.error or param_parsed == reject then
|
||||
-- No value was returned or error was returned, if nil then give generic error
|
||||
if param_parsed ~= Commands.defines.error then
|
||||
command_log(player, command_data, 'Invalid Param Given', raw_params, raw_input, param_name)
|
||||
Commands.error{'expcore-commands.command-error-param-format', param_name, 'please make sure it is the correct type'}
|
||||
end
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
-- Add the param to the table to be passed to the command callback
|
||||
params[index] = param_parsed
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
-- Run the command
|
||||
-- player: LuaPlayer, ... command params, raw: string
|
||||
params[command_data.max_param_count+1] = raw_input
|
||||
local success, rtn = pcall(command_data.callback, player, table.unpack(params))
|
||||
if Commands.internal_error(success, command_data.name, rtn) then
|
||||
return command_log(player, command_data, 'Internal Error: Command Callback Fail', raw_params, command_event.parameter, rtn)
|
||||
end
|
||||
|
||||
-- Give output to the player
|
||||
if rtn == Commands.defines.error or rtn == Commands.error then
|
||||
return command_log(player, command_data, 'Custom Error', raw_params, raw_input)
|
||||
elseif rtn ~= Commands.defines.success and rtn ~= Commands.success then
|
||||
Commands.success(rtn)
|
||||
end
|
||||
command_log(player, command_data, 'Success', raw_params, raw_input)
|
||||
end
|
||||
|
||||
return Commands
|
||||
825
exp_legacy/module/expcore/common.lua
Normal file
825
exp_legacy/module/expcore/common.lua
Normal file
@@ -0,0 +1,825 @@
|
||||
--[[-- Core Module - Common
|
||||
- Adds some commonly used functions used in many modules
|
||||
@core Common
|
||||
@alias Common
|
||||
]]
|
||||
|
||||
local Colours = require 'utils.color_presets' --- @dep utils.color_presets
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
local Common = {}
|
||||
|
||||
--- Type Checking.
|
||||
-- @section typeCheck
|
||||
|
||||
--[[-- Asserts the argument is of type test_type
|
||||
@tparam any value the value to be tested
|
||||
@tparam[opt=nil] string test_type the type to test for if not given then it tests for nil
|
||||
@treturn boolean is v of type test_type
|
||||
|
||||
@usage-- Check for a string value
|
||||
local is_string = type_check(value, 'string')
|
||||
|
||||
@usage-- Check for a nil value
|
||||
local is_nil = type_check(value)
|
||||
|
||||
]]
|
||||
function Common.type_check(value, test_type)
|
||||
return test_type and value and type(value) == test_type or not test_type and not value or false
|
||||
end
|
||||
|
||||
--[[-- Raises an error if the value is of the wrong type
|
||||
@tparam any value the value that you want to test the type of
|
||||
@tparam string test_type the type that the value should be
|
||||
@tparam string error_message the error message that is returned
|
||||
@tparam number level the level to call the error on (level = 1 is the caller)
|
||||
@treturn boolean true if no error was called
|
||||
|
||||
@usage-- Raise error if value is not a number
|
||||
type_error(value, 'number', 'Value must be a number')
|
||||
|
||||
]]
|
||||
function Common.type_error(value, test_type, error_message, level)
|
||||
level = level and level+1 or 2
|
||||
return Common.type_check(value, test_type) or error(error_message, level)
|
||||
end
|
||||
|
||||
--[[-- Asserts the argument is one of type test_types
|
||||
@param value the variable to check
|
||||
@param test_types the type as a table of strings
|
||||
@treturn boolean true if value is one of test_types
|
||||
|
||||
@usage-- Check for a string or table
|
||||
local is_string_or_table = multi_type_check(value, {'string', 'table'})
|
||||
|
||||
]]
|
||||
function Common.multi_type_check(value, test_types)
|
||||
local vtype = type(value)
|
||||
for _, arg_type in ipairs(test_types) do
|
||||
if vtype == arg_type then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[-- Raises an error if the value is of the wrong type
|
||||
@tparam any value the value that you want to test the type of
|
||||
@tparam table test_types the type as a table of strings
|
||||
@tparam string error_message the error message that is returned
|
||||
@tparam number level the level to call the error on (level = 1 is the caller)
|
||||
@treturn boolean true if no error was called
|
||||
|
||||
@usage-- Raise error if value is not a string or table
|
||||
multi_type_error('foo', {'string', 'table'}, 'Value must be a string or table')
|
||||
|
||||
]]
|
||||
function Common.multi_type_error(value, test_types, error_message, level)
|
||||
level = level and level+1 or 2
|
||||
return Common.mult_type_check(value, test_types) or error(error_message, level)
|
||||
end
|
||||
|
||||
--[[-- Raises an error when the value is the incorrect type, uses a consistent error message format
|
||||
@tparam any value the value that you want to test the type of
|
||||
@tparam string test_type the type that the value should be
|
||||
@tparam number param_number the number param it is
|
||||
@tparam[opt] string param_name the name of the param
|
||||
@treturn boolean true if no error was raised
|
||||
|
||||
@usage-- Output: "Bad argument #2 to "<anon>"; argument is of type string expected number"
|
||||
validate_argument_type(value, 'number', 2)
|
||||
|
||||
@usage-- Output: "Bad argument #2 to "<anon>"; "repeat_count" is of type string expected number"
|
||||
validate_argument_type(value, 'number', 2, 'repeat_count')
|
||||
|
||||
]]
|
||||
function Common.validate_argument_type(value, test_type, param_number, param_name)
|
||||
if not Common.test_type(value, test_type) then
|
||||
local function_name = debug.getinfo(2, 'n').name or '<anon>'
|
||||
local error_message
|
||||
if param_name then
|
||||
error_message = string.format('Bad argument #%d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), test_type)
|
||||
else
|
||||
error_message = string.format('Bad argument #%d to %q; argument is of type %s expected %s', param_number, function_name, type(value), test_type)
|
||||
end
|
||||
return error(error_message, 3)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--[[-- Raises an error when the value is the incorrect type, uses a consistent error message format
|
||||
@tparam any value the value that you want to test the type of
|
||||
@tparam string test_types the types that the value should be
|
||||
@tparam number param_number the number param it is
|
||||
@tparam[opt] string param_name the name of the param
|
||||
@treturn boolean true if no error was raised
|
||||
|
||||
@usage-- Output: "Bad argument #2 to "<anon>"; argument is of type number expected string or table"
|
||||
validate_argument_type(value, {'string', 'table'}, 2)
|
||||
|
||||
@usage-- Output: "Bad argument #2 to "<anon>"; "player" is of type number expected string or table"
|
||||
validate_argument_type(value, {'string', 'table'}, 2, 'player')
|
||||
|
||||
]]
|
||||
function Common.validate_argument_multi_type(value, test_types, param_number, param_name)
|
||||
if not Common.multi_type_check(value, test_types) then
|
||||
local function_name = debug.getinfo(2, 'n').name or '<anon>'
|
||||
local error_message
|
||||
if param_name then
|
||||
error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), table.concat(test_types, ' or '))
|
||||
else
|
||||
error_message = string.format('Bad argument #%2d to %q; argument is of type %s expected %s', param_number, function_name, type(value), table.concat(test_types, ' or '))
|
||||
end
|
||||
return error(error_message, 3)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Will raise an error if called during runtime
|
||||
-- @usage error_if_runtime()
|
||||
function Common.error_if_runtime()
|
||||
if _LIFECYCLE == 8 then
|
||||
local function_name = debug.getinfo(2, 'n').name or '<anon>'
|
||||
error(function_name..' can not be called during runtime', 3)
|
||||
end
|
||||
end
|
||||
|
||||
--- Will raise an error if the function is a closure
|
||||
-- @usage error_if_runetime_closure(func)
|
||||
function Common.error_if_runetime_closure(func)
|
||||
if _LIFECYCLE == 8 and Debug.is_closure(func) then
|
||||
local function_name = debug.getinfo(2, 'n').name or '<anon>'
|
||||
error(function_name..' can not be called during runtime with a closure', 3)
|
||||
end
|
||||
end
|
||||
|
||||
--- Value Returns.
|
||||
-- @section valueReturns
|
||||
|
||||
--[[-- Tests if a string contains a given substring.
|
||||
@tparam string s the string to check for the substring
|
||||
@tparam string contains the substring to test for
|
||||
@treturn boolean true if the substring was found in the string
|
||||
|
||||
@usage-- Test if a string contains a sub string
|
||||
local found = string_contains(str, 'foo')
|
||||
|
||||
]]
|
||||
function Common.string_contains(s, contains)
|
||||
return s and string.find(s, contains) ~= nil
|
||||
end
|
||||
|
||||
--[[-- Used to resolve a value that could also be a function returning that value
|
||||
@tparam any value the value which you want to test is not nil and if it is a function then call the function
|
||||
@treturn any the value given or returned by value if it is a function
|
||||
|
||||
@usage-- Default value handling
|
||||
-- if default value is not a function then it is returned
|
||||
-- if default value is a function then it is called with the first argument being self
|
||||
local value = Common.resolve_value(self.defaut_value, self)
|
||||
|
||||
]]
|
||||
function Common.resolve_value(value, ...)
|
||||
return value and type(value) == 'function' and value(...) or value
|
||||
end
|
||||
|
||||
--- Converts a varible into its boolean value, nil and false return false
|
||||
-- @treturn boolean the boolean form of the varible
|
||||
-- @usage local bool = cast_bool(var)
|
||||
function Common.cast_bool(var)
|
||||
return var and true or false
|
||||
end
|
||||
|
||||
--- Returns either the second or third argument based on the first argument
|
||||
-- @usage ternary(input_string == 'test', 'Input is test', 'Input is not test')
|
||||
function Common.ternary(c, t, f)
|
||||
return c and t or f
|
||||
end
|
||||
|
||||
--- Returns a string for a number with comma seperators
|
||||
-- @usage comma_value(input_number)
|
||||
function Common.comma_value(n) -- credit http://richard.warburton.it
|
||||
local left, num, right = string.match(n, '^([^%d]*%d)(%d*)(.-)$')
|
||||
return left .. (num:reverse():gsub('(%d%d%d)', '%1, '):reverse()) .. right
|
||||
end
|
||||
|
||||
--[[-- Sets a table element to value while also returning value.
|
||||
@tparam table tbl to change the element of
|
||||
@tparam string key the key to set the value of
|
||||
@tparam any value the value to set the key as
|
||||
@treturn any the value that was set
|
||||
|
||||
@usage-- Set and return value
|
||||
local value = set_and_return(players, player.name, player.online_time)
|
||||
|
||||
]]
|
||||
function Common.set_and_return(tbl, key, value)
|
||||
tbl[key] = value
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Writes a table object to a file in json format
|
||||
@tparam string path the path of the file to write include / to use dir
|
||||
@tparam table tbl the table that will be converted to a json string and wrote to file
|
||||
|
||||
@usage-- Write a lua table as a json to script-outpt/dump
|
||||
write_json('dump', tbl)
|
||||
|
||||
]]
|
||||
function Common.write_json(path, tbl)
|
||||
game.write_file(path, game.table_to_json(tbl)..'\n', true, 0)
|
||||
end
|
||||
|
||||
--[[-- Calls a require that will not error if the file is not found
|
||||
@usage local file = opt_require('file.not.present') -- will not cause any error
|
||||
@tparam string path the path that you want to require
|
||||
@return the returns from that file or nil, error if not loaded
|
||||
|
||||
@usage-- Require a file without causing errors, for when a file might not exist
|
||||
local Module = opt_require 'expcore.common'
|
||||
|
||||
]]
|
||||
function Common.opt_require(path)
|
||||
local success, rtn = pcall(require, path)
|
||||
if success then return rtn
|
||||
else return nil, rtn end
|
||||
end
|
||||
|
||||
--[[-- Returns a desync safe file path for the current file
|
||||
@tparam[opt=0] number offset the offset in the stack to get, 0 is current file
|
||||
@treturn string the file path
|
||||
|
||||
@usage-- Get the current file path
|
||||
local file_path = get_file_path()
|
||||
|
||||
]]
|
||||
function Common.get_file_path(offset)
|
||||
offset = offset or 0
|
||||
return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
end
|
||||
|
||||
--[[-- Converts a table to an enum
|
||||
@tparam table tbl table the that will be converted
|
||||
@treturn table the new table that acts like an enum
|
||||
|
||||
@usage-- Make an enum
|
||||
local colors = enum{
|
||||
'red',
|
||||
'green',
|
||||
'blue'
|
||||
}
|
||||
|
||||
]]
|
||||
function Common.enum(tbl)
|
||||
local rtn = {}
|
||||
for k, v in pairs(tbl) do
|
||||
if type(k) ~= 'number' then
|
||||
rtn[v]=k
|
||||
end
|
||||
end
|
||||
for k, v in pairs(tbl) do
|
||||
if type(k) == 'number' then
|
||||
table.insert(rtn, v)
|
||||
end
|
||||
end
|
||||
for k, v in pairs(rtn) do
|
||||
rtn[v]=k
|
||||
end
|
||||
return rtn
|
||||
end
|
||||
|
||||
--[[-- Returns the closest match to the input
|
||||
@tparam table options table a of options for the auto complete
|
||||
@tparam string input string the input that will be completed
|
||||
@tparam[opt=false] boolean use_key when true the keys of options will be used as the options
|
||||
@tparam[opt=false] boolean rtn_key when true the the key will be returned rather than the value
|
||||
@return the list item found that matches the input
|
||||
|
||||
@usage-- Get the element that includes "foo"
|
||||
local value = auto_complete(tbl, "foo")
|
||||
|
||||
@usage-- Get the element with a key that includes "foo"
|
||||
local value = auto_complete(tbl, "foo", true)
|
||||
|
||||
@usage-- Get the key with that includes "foo"
|
||||
local key = auto_complete(tbl, "foo", true, true)
|
||||
|
||||
]]
|
||||
function Common.auto_complete(options, input, use_key, rtn_key)
|
||||
if type(input) ~= 'string' then return end
|
||||
input = input:lower()
|
||||
for key, value in pairs(options) do
|
||||
local check = use_key and key or value
|
||||
if Common.string_contains(string.lower(check), input) then
|
||||
return rtn_key and key or value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Formatting.
|
||||
-- @section formatting
|
||||
|
||||
--[[-- Returns a valid string with the name of the actor of a command.
|
||||
@tparam string player_name the name of the player to use rather than server, used only if game.player is nil
|
||||
@treturn string the name of the current actor
|
||||
|
||||
@usage-- Get the current actor
|
||||
local player_name = get_actor()
|
||||
|
||||
]]
|
||||
function Common.get_actor(player_name)
|
||||
return game.player and game.player.name or player_name or '<server>'
|
||||
end
|
||||
|
||||
--[[-- Returns a message with valid chat tags to change its colour
|
||||
@tparam string message the message that will be in the output
|
||||
@tparam table color a color which contains r, g, b as its keys
|
||||
@treturn string the message with the color tags included
|
||||
|
||||
@usage-- Use factorio tags to color a chat message
|
||||
local message = format_chat_colour('Hello, World!', { r=355, g=100, b=100 })
|
||||
|
||||
]]
|
||||
function Common.format_chat_colour(message, color)
|
||||
color = color or Colours.white
|
||||
local color_tag = '[color='..math.round(color.r, 3)..', '..math.round(color.g, 3)..', '..math.round(color.b, 3)..']'
|
||||
return string.format('%s%s[/color]', color_tag, message)
|
||||
end
|
||||
|
||||
--[[-- Returns a message with valid chat tags to change its colour, using localization
|
||||
@tparam ?string|table message the message that will be in the output
|
||||
@tparam table color a color which contains r, g, b as its keys
|
||||
@treturn table the message with the color tags included
|
||||
|
||||
@usage-- Use factorio tags and locale strings to color a chat message
|
||||
local message = format_chat_colour_localized('Hello, World!', { r=355, g=100, b=100 })
|
||||
|
||||
]]
|
||||
function Common.format_chat_colour_localized(message, color)
|
||||
color = color or Colours.white
|
||||
color = math.round(color.r, 3)..', '..math.round(color.g, 3)..', '..math.round(color.b, 3)
|
||||
return {'color-tag', color, message}
|
||||
end
|
||||
|
||||
--[[-- Returns the players name in the players color
|
||||
@tparam LuaPlayer player the player to use the name and color of
|
||||
@tparam[opt=false] boolean raw_string when true a string is returned rather than a localized string
|
||||
@treturn table the players name with tags for the players color
|
||||
|
||||
@usage-- Format a players name using the players color as a string
|
||||
local message = format_chat_player_name(game.player, true)
|
||||
|
||||
]]
|
||||
function Common.format_chat_player_name(player, raw_string)
|
||||
player = Game.get_player_from_any(player)
|
||||
local player_name = player and player.name or '<Server>'
|
||||
local player_chat_colour = player and player.chat_color or Colours.white
|
||||
if raw_string then
|
||||
return Common.format_chat_colour(player_name, player_chat_colour)
|
||||
else
|
||||
return Common.format_chat_colour_localized(player_name, player_chat_colour)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Will return a value of any type to the player/server console, allows colour for in-game players
|
||||
@tparam any value a value of any type that will be returned to the player or console
|
||||
@tparam[opt=defines.colour.white] ?defines.color|string colour the colour of the text for the player, ignored when printing to console
|
||||
@tparam[opt=game.player] LuaPlayer player the player that return will go to, if no game.player then returns to server
|
||||
|
||||
@usage-- Return a value to the current actor, rcon included
|
||||
player_return('Hello, World!')
|
||||
|
||||
@usage-- Return a value to the current actor, with color
|
||||
player_return('Hello, World!', 'green')
|
||||
|
||||
@usage-- Return to a player other than the current
|
||||
player_return('Hello, World!', nil, player)
|
||||
|
||||
]]
|
||||
function Common.player_return(value, colour, player)
|
||||
colour = Common.type_check(colour, 'table') and colour or Colours[colour] ~= Colours.white and Colours[colour] or Colours.white
|
||||
player = player or game.player
|
||||
-- converts the value to a string
|
||||
local returnAsString
|
||||
if Common.type_check(value, 'table') or type(value) == 'userdata' then
|
||||
if Common.type_check(value.__self, 'userdata') or type(value) == 'userdata' then
|
||||
-- value is userdata
|
||||
returnAsString = 'Cant Display Userdata'
|
||||
elseif Common.type_check(value[1], 'string') and string.find(value[1], '.+[.].+') and not string.find(value[1], '%s') then
|
||||
-- value is a locale string
|
||||
returnAsString = value
|
||||
elseif getmetatable(value) ~= nil and not tostring(value):find('table: 0x') then
|
||||
-- value has a tostring meta method
|
||||
returnAsString = tostring(value)
|
||||
else
|
||||
-- value is a table
|
||||
returnAsString = table.inspect(value, {depth=5, indent=' ', newline='\n'})
|
||||
end
|
||||
elseif Common.type_check(value, 'function') then
|
||||
-- value is a function
|
||||
returnAsString = 'Cant Display Functions'
|
||||
else returnAsString = tostring(value) end
|
||||
-- returns to the player or the server
|
||||
if player then
|
||||
-- allows any valid player identifier to be used
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player then error('Invalid Player given to player_return', 2) end
|
||||
-- plays a nice sound that is different to normal message sound
|
||||
player.play_sound{path='utility/scenario_message'}
|
||||
player.print(returnAsString, colour)
|
||||
else rcon.print(returnAsString) end
|
||||
end
|
||||
|
||||
--[[-- Formats tick into a clean format, denominations from highest to lowest
|
||||
-- time will use : separates
|
||||
-- when a denomination is false it will overflow into the next one
|
||||
@tparam number ticks the number of ticks that represents a time
|
||||
@tparam table options table a of options to use for the format
|
||||
@treturn string a locale string that can be used
|
||||
|
||||
@usage-- Output: "0h 5m"
|
||||
local time = format_time(18000, { hours=true, minutes=true, string=true })
|
||||
|
||||
@usage-- Output: "0 hours and 5 minutes"
|
||||
local time = format_time(18000, { hours=true, minutes=true, string=true, long=true })
|
||||
|
||||
@usage-- Output: "00:05:00"
|
||||
local time = format_time(18000, { hours=true, minutes=true, seconds=true, string=true })
|
||||
|
||||
@usage-- Output: "--:--:--"
|
||||
local time = format_time(18000, { hours=true, minutes=true, seconds=true, string=true, null=true })
|
||||
|
||||
]]
|
||||
function Common.format_time(ticks, options)
|
||||
-- Sets up the options
|
||||
options = options or {
|
||||
days=false,
|
||||
hours=true,
|
||||
minutes=true,
|
||||
seconds=false,
|
||||
long=false,
|
||||
time=false,
|
||||
string=false,
|
||||
null=false
|
||||
}
|
||||
-- Basic numbers that are used in calculations
|
||||
local max_days, max_hours, max_minutes, max_seconds = ticks/5184000, ticks/216000, ticks/3600, ticks/60
|
||||
local days, hours = max_days, max_hours-math.floor(max_days)*24
|
||||
local minutes, seconds = max_minutes-math.floor(max_hours)*60, max_seconds-math.floor(max_minutes)*60
|
||||
-- Handles overflow of disabled denominations
|
||||
local rtn_days, rtn_hours, rtn_minutes, rtn_seconds = math.floor(days), math.floor(hours), math.floor(minutes), math.floor(seconds)
|
||||
if not options.days then
|
||||
rtn_hours = rtn_hours + rtn_days*24
|
||||
end
|
||||
if not options.hours then
|
||||
rtn_minutes = rtn_minutes + rtn_hours*60
|
||||
end
|
||||
if not options.minutes then
|
||||
rtn_seconds = rtn_seconds + rtn_minutes*60
|
||||
end
|
||||
-- Creates the null time format, does not work with long
|
||||
if options.null and not options.long then
|
||||
rtn_days='--'
|
||||
rtn_hours='--'
|
||||
rtn_minutes='--'
|
||||
rtn_seconds='--'
|
||||
end
|
||||
-- Format options
|
||||
local suffix = 'time-symbol-'
|
||||
local suffix_2 = '-short'
|
||||
if options.long then
|
||||
suffix = ''
|
||||
suffix_2 = ''
|
||||
end
|
||||
local div = options.string and ' ' or 'time-format.simple-format-tagged'
|
||||
if options.time then
|
||||
div = options.string and ':' or 'time-format.simple-format-div'
|
||||
suffix = false
|
||||
end
|
||||
-- Adds formatting
|
||||
if suffix ~= false then
|
||||
if options.string then
|
||||
-- format it as a string
|
||||
local long = suffix == ''
|
||||
rtn_days = long and rtn_days..' days' or rtn_days..'d'
|
||||
rtn_hours = long and rtn_hours..' hours' or rtn_hours..'h'
|
||||
rtn_minutes = long and rtn_minutes..' minutes' or rtn_minutes..'m'
|
||||
rtn_seconds = long and rtn_seconds..' seconds' or rtn_seconds..'s'
|
||||
else
|
||||
rtn_days = {suffix..'days'..suffix_2, rtn_days}
|
||||
rtn_hours = {suffix..'hours'..suffix_2, rtn_hours}
|
||||
rtn_minutes = {suffix..'minutes'..suffix_2, rtn_minutes}
|
||||
rtn_seconds = {suffix..'seconds'..suffix_2, rtn_seconds}
|
||||
end
|
||||
elseif not options.null then
|
||||
-- weather string or not it has same format
|
||||
rtn_days = string.format('%02d', rtn_days)
|
||||
rtn_hours = string.format('%02d', rtn_hours)
|
||||
rtn_minutes = string.format('%02d', rtn_minutes)
|
||||
rtn_seconds = string.format('%02d', rtn_seconds)
|
||||
end
|
||||
-- The final return is construed
|
||||
local rtn
|
||||
local append = function(dom, value)
|
||||
if dom and options.string then
|
||||
rtn = rtn and rtn..div..value or value
|
||||
elseif dom then
|
||||
rtn = rtn and {div, rtn, value} or value
|
||||
end
|
||||
end
|
||||
append(options.days, rtn_days)
|
||||
append(options.hours, rtn_hours)
|
||||
append(options.minutes, rtn_minutes)
|
||||
append(options.seconds, rtn_seconds)
|
||||
return rtn
|
||||
end
|
||||
|
||||
--- Factorio.
|
||||
-- @section factorio
|
||||
|
||||
--[[-- Copies items to the position and stores them in the closest entity of the type given
|
||||
-- Copies the items by prototype name, but keeps them in the original inventory
|
||||
@tparam table items items which are to be added to the chests, an array of LuaItemStack
|
||||
@tparam[opt=navies] LuaSurface surface the surface that the items will be copied to
|
||||
@tparam[opt={0, 0}] table position the position that the items will be copied to {x=100, y=100}
|
||||
@tparam[opt=32] number radius the radius in which the items are allowed to be placed
|
||||
@tparam[opt=iron-chest] string chest_type the chest type that the items should be copied into
|
||||
@treturn LuaEntity the last chest that had items inserted into it
|
||||
|
||||
@usage-- Copy all the items in a players inventory and place them in chests at {0, 0}
|
||||
copy_items_stack(game.player.get_main_inventory().get_contents())
|
||||
|
||||
]]
|
||||
function Common.copy_items_stack(items, surface, position, radius, chest_type)
|
||||
chest_type = chest_type or 'iron-chest'
|
||||
surface = surface or game.surfaces[1]
|
||||
if position and type(position) ~= 'table' then return end
|
||||
if type(items) ~= 'table' then return end
|
||||
-- Finds all entities of the given type
|
||||
local p = position or {x=0, y=0}
|
||||
local r = radius or 32
|
||||
local entities = surface.find_entities_filtered{area={{p.x-r, p.y-r}, {p.x+r, p.y+r}}, name=chest_type} or {}
|
||||
local count = #entities
|
||||
local current = 1
|
||||
-- Makes a new empty chest when it is needed
|
||||
local function make_new_chest()
|
||||
local pos = surface.find_non_colliding_position(chest_type, position, 32, 1)
|
||||
local chest = surface.create_entity{name=chest_type, position=pos, force='neutral'}
|
||||
table.insert(entities, chest)
|
||||
count = count + 1
|
||||
return chest
|
||||
end
|
||||
-- Function used to round robin the items into all chests
|
||||
local function next_chest(item)
|
||||
local chest = entities[current]
|
||||
if count == 0 then return make_new_chest() end
|
||||
if chest.get_inventory(defines.inventory.chest).can_insert(item) then
|
||||
-- If the item can be inserted then the chest is returned
|
||||
current = current+1
|
||||
if current > count then current = 1 end
|
||||
return chest
|
||||
else
|
||||
-- Other wise it is removed from the list
|
||||
table.remove(entities, current)
|
||||
count = count - 1
|
||||
end
|
||||
end
|
||||
-- Inserts the items into the chests
|
||||
local last_chest
|
||||
for i=1,#items do
|
||||
local item = items[i]
|
||||
if item.valid_for_read then
|
||||
local chest = next_chest(item)
|
||||
if not chest or not chest.valid then return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y)) end
|
||||
chest.insert(item)
|
||||
last_chest = chest
|
||||
end
|
||||
end
|
||||
return last_chest
|
||||
end
|
||||
|
||||
--[[-- Moves items to the position and stores them in the closest entity of the type given
|
||||
-- Differs from move_items by accepting a table of LuaItemStack and transferring them into the inventory - not copying
|
||||
@tparam table items items which are to be added to the chests, an array of LuaItemStack
|
||||
@tparam[opt=navies] LuaSurface surface the surface that the items will be moved to
|
||||
@tparam[opt={0, 0}] table position the position that the items will be moved to {x=100, y=100}
|
||||
@tparam[opt=32] number radius the radius in which the items are allowed to be placed
|
||||
@tparam[opt=iron-chest] string chest_type the chest type that the items should be moved into
|
||||
@treturn LuaEntity the last chest that had items inserted into it
|
||||
|
||||
@usage-- Copy all the items in a players inventory and place them in chests at {0, 0}
|
||||
move_items_stack(game.player.get_main_inventory())
|
||||
|
||||
]]
|
||||
function Common.move_items_stack(items, surface, position, radius, chest_type)
|
||||
chest_type = chest_type or 'steel-chest'
|
||||
surface = surface or game.surfaces[1]
|
||||
|
||||
if position and type(position) ~= 'table' then
|
||||
return
|
||||
end
|
||||
|
||||
if type(items) ~= 'table' then
|
||||
return
|
||||
end
|
||||
|
||||
-- Finds all entities of the given type
|
||||
local p = position or {x=0, y=0}
|
||||
local r = radius or 32
|
||||
local entities = surface.find_entities_filtered{area={{p.x - r, p.y - r}, {p.x + r, p.y + r}}, name={chest_type, 'iron-chest'}} or {}
|
||||
local count = #entities
|
||||
local current = 0
|
||||
local last_entity = nil
|
||||
|
||||
-- ipairs does not work on LuaInventory
|
||||
for i = 1, #items do
|
||||
local item = items[i]
|
||||
if item.valid_for_read then
|
||||
local inserted = false
|
||||
|
||||
-- Attempt to insert the items
|
||||
for j = 1, count do
|
||||
local entity = entities[((current + j - 1) % count) + 1]
|
||||
|
||||
if entity.can_insert(item) then
|
||||
last_entity = entity
|
||||
current = current + 1
|
||||
entity.insert(item)
|
||||
inserted = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- If it was not inserted then a new entity is needed
|
||||
if not inserted then
|
||||
--[[
|
||||
if not options.allow_creation then
|
||||
error('Unable to insert items into a valid entity, consider enabling allow_creation')
|
||||
end
|
||||
|
||||
if options.name == nil then
|
||||
error('Name must be provided to allow creation of new entities')
|
||||
end
|
||||
|
||||
if options.position then
|
||||
pos = surface.find_non_colliding_position(chest_type, p, r, 1, true)
|
||||
|
||||
elseif options.area then
|
||||
pos = surface.find_non_colliding_position_in_box(chest_type, options.area, 1, true)
|
||||
|
||||
else
|
||||
pos = surface.find_non_colliding_position(chest_type, {0,0}, 0, 1, true)
|
||||
end
|
||||
]]
|
||||
|
||||
local pos = surface.find_non_colliding_position(chest_type, p, r, 1, true)
|
||||
last_entity = surface.create_entity{name=chest_type, position=pos, force='neutral'}
|
||||
|
||||
count = count + 1
|
||||
entities[count] = last_entity
|
||||
|
||||
last_entity.insert(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
-- Makes a new empty chest when it is needed
|
||||
local function make_new_chest()
|
||||
local pos = surface.find_non_colliding_position(chest_type, position, 32, 1)
|
||||
local chest = surface.create_entity{name=chest_type, position=pos, force='neutral'}
|
||||
table.insert(entities, chest)
|
||||
count = count + 1
|
||||
|
||||
return chest
|
||||
end
|
||||
|
||||
-- Function used to round robin the items into all chests
|
||||
local function next_chest(item)
|
||||
local chest = entities[current]
|
||||
|
||||
if count == 0 then
|
||||
return make_new_chest()
|
||||
end
|
||||
|
||||
if chest.get_inventory(defines.inventory.chest).can_insert(item) then
|
||||
-- If the item can be inserted then the chest is returned
|
||||
current = current + 1
|
||||
if current > count then
|
||||
current = 1
|
||||
end
|
||||
|
||||
return chest
|
||||
|
||||
else
|
||||
-- Other wise it is removed from the list
|
||||
table.remove(entities, current)
|
||||
count = count - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Inserts the items into the chests
|
||||
local last_chest
|
||||
|
||||
for i=1,#items do
|
||||
local item = items[i]
|
||||
|
||||
if item.valid_for_read then
|
||||
local chest = next_chest(item)
|
||||
|
||||
if not chest or not chest.valid then
|
||||
return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y))
|
||||
end
|
||||
|
||||
local empty_stack = chest.get_inventory(defines.inventory.chest).find_empty_stack(item.name)
|
||||
|
||||
if not empty_stack then
|
||||
return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y))
|
||||
end
|
||||
|
||||
empty_stack.transfer_stack(item)
|
||||
last_chest = chest
|
||||
end
|
||||
end
|
||||
return last_chest
|
||||
]]
|
||||
|
||||
return last_entity
|
||||
end
|
||||
|
||||
--[[-- Prints a colored value on a location, color is based on the value.
|
||||
nb: src is below but the gradent has been edited
|
||||
https://github.com/Refactorio/RedMew/blob/9184b2940f311d8c9c891e83429fc57ec7e0c4a2/map_gen/maps/diggy/debug.lua#L31
|
||||
@tparam number value the value to show must be between -1 and 1, scale can be used to achive this
|
||||
@tparam LuaSurface surface the surface to palce the value on
|
||||
@tparam table position {x, y} the possition to palce the value at
|
||||
@tparam[opt=1] number scale how much to scale the colours by
|
||||
@tparam[opt=0] number offset the offset in the +x +y direction
|
||||
@tparam[opt=false] boolean immutable if immutable, only set, never do a surface lookup, values never change
|
||||
|
||||
@usage-- Place a 0 at {0, 0}
|
||||
print_grid_value(0, game.player.surface, { x=0, y=0 })
|
||||
|
||||
]]
|
||||
function Common.print_grid_value(value, surface, position, scale, offset, immutable)
|
||||
local is_string = type(value) == 'string'
|
||||
local color = Colours.white
|
||||
local text = value
|
||||
|
||||
if type(immutable) ~= 'boolean' then
|
||||
immutable = false
|
||||
end
|
||||
|
||||
if not is_string then
|
||||
scale = scale or 1
|
||||
offset = offset or 0
|
||||
position = {x = position.x + offset, y = position.y + offset}
|
||||
local r = math.clamp(-value/scale, 0, 1)
|
||||
local g = math.clamp(1-math.abs(value)/scale, 0, 1)
|
||||
local b = math.clamp(value/scale, 0, 1)
|
||||
|
||||
color = { r = r, g = g, b = b}
|
||||
|
||||
-- round at precision of 2
|
||||
text = math.floor(100 * value) * 0.01
|
||||
|
||||
if (0 == text) then
|
||||
text = '0.00'
|
||||
end
|
||||
end
|
||||
|
||||
if not immutable then
|
||||
local text_entity = surface.find_entity('flying-text', position)
|
||||
|
||||
if text_entity then
|
||||
text_entity.text = text
|
||||
text_entity.color = color
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
surface.create_entity{
|
||||
name = 'flying-text',
|
||||
color = color,
|
||||
text = text,
|
||||
position = position
|
||||
}.active = false
|
||||
end
|
||||
|
||||
--[[-- Clears all flying text entities on a surface
|
||||
@tparam LuaSurface surface the surface to clear
|
||||
|
||||
@usage-- Remove all flying text on the surface
|
||||
clear_flying_text(game.player.surface)
|
||||
|
||||
]]
|
||||
function Common.clear_flying_text(surface)
|
||||
local entities = surface.find_entities_filtered{name ='flying-text'}
|
||||
for _, entity in pairs(entities) do
|
||||
if entity and entity.valid then
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Common
|
||||
864
exp_legacy/module/expcore/datastore.lua
Normal file
864
exp_legacy/module/expcore/datastore.lua
Normal file
@@ -0,0 +1,864 @@
|
||||
--[[-- Core Module - Datastore
|
||||
- A module used to store data in the global table with the option to have it sync to an external source.
|
||||
@core Datastore
|
||||
@alias DatastoreManager
|
||||
|
||||
@usage-- Types of Datastore
|
||||
-- This datastore will not save data externally and can be used to watch for updates on values within it
|
||||
-- A common use might be to store data for a gui and only update the gui when a value changes
|
||||
local LocalDatastore = Datastore.connect('LocalDatastore')
|
||||
|
||||
-- This datastore will allow you to use the save and request method, this allows you to have persistent data
|
||||
-- Should be used over auto save as it creates less save requests, but this means you need to tell the data to be saved
|
||||
-- We use this type for player data as we know the data only needs to be saved when the player leaves
|
||||
local PersistentDatastore = Datastore.connect('PersistentDatastore', true) -- save_to_disk
|
||||
|
||||
-- This datastore is the same as above but the save method will be called automatically when ever you change a value
|
||||
-- An auto save datastore should be used if the data does not change often, this can be global settings and things of that sort
|
||||
-- If it is at all possible to setup events to unload and/or save the data then this is preferable
|
||||
local AutosaveDatastore = Datastore.connect('AutosaveDatastore', true, true) -- save_to_disk, auto_save
|
||||
|
||||
-- Finally you can have a datastore that propagates its changes to all other connected servers, this means request does not need to be used
|
||||
-- This should be used when you might have data conflicts while saving, this is done by pushing the saved value to all active servers
|
||||
-- The request method has little use after server start as any external changes to the value will be pushed automatically
|
||||
-- Auto save can also be used with this type and you should follow the same guidelines above for when this should be avoided
|
||||
local PropagateDatastore = Datastore.connect('PropagateDatastore', true, false, true) -- save_to_disk, propagate_changes
|
||||
|
||||
@usage-- Using Datastores Locally
|
||||
-- Once you have your datastore connection setup, any further requests with connect will return the same datastore
|
||||
-- This is important to know because the settings passed as parameters you have an effect when it is first created
|
||||
|
||||
-- One useful thing that you might want to set up before runtime is a serializer, this will convert non string keys into strings
|
||||
-- This serializer will allow use to pass a player object and still have it serialized to the players name
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set_serializer(function(rawKey)
|
||||
return rawKey.name
|
||||
end)
|
||||
|
||||
-- If we want to get data from the datastore we can use get or get_all
|
||||
local value = ExampleData:get(player, defaultValue)
|
||||
local values = ExampleData:get_all()
|
||||
|
||||
-- If we want to set data then we can use set, increment, update, or update_all
|
||||
ExampleData:set(player, 10)
|
||||
ExampleData:increment(player)
|
||||
ExampleData:update(player, function(player_name, value)
|
||||
return value * 2
|
||||
end)
|
||||
ExampleData:update_all(function(player_name, value)
|
||||
return value * 2
|
||||
end)
|
||||
|
||||
-- If we want to remove data then we use remove
|
||||
ExampleData:remove(player)
|
||||
|
||||
-- We can also listen for updates to a value done by any of the above methods with on_update
|
||||
ExampleData:on_update(function(player_name, value)
|
||||
game.print(player_name..' has had their example data updated to '..tostring(value))
|
||||
end)
|
||||
|
||||
@usage-- Using Datastore Externally
|
||||
-- If save_to_disk is used then this opens up the option for persistent data which you can request, save, and remove
|
||||
-- All of the local methods are still usable put now there is the option for extra events
|
||||
-- In order for this to work there must be an external script to read datastore.pipe and inject with Datastore.ingest
|
||||
|
||||
-- To request data you would use request and the on_load event, this event can be used to modify data before it is used
|
||||
ExampleData:request(player)
|
||||
ExampleData:on_load(function(player_name, value)
|
||||
game.print('Loaded example data for '..player_name)
|
||||
-- A value can be returned here to overwrite the received value
|
||||
end)
|
||||
|
||||
-- To save data you would use save and the on_save event, this event can be used to modify data before it is saved
|
||||
ExampleData:save(player)
|
||||
ExampleData:on_save(function(player_name, value)
|
||||
game.print('Saved example data for '..player_name)
|
||||
-- A value can be returned here to overwrite the value which is saved
|
||||
end)
|
||||
|
||||
-- To remove data locally but not externally, like if a player logs off, you would use unload and on_unload
|
||||
ExampleData:unload(player)
|
||||
ExampleData:on_unload(function(player_name, value)
|
||||
game.print('Unloaded example data for '..player_name)
|
||||
-- Any return is ignored, this is event is for cleaning up other data
|
||||
end)
|
||||
|
||||
@usage-- Using Datastore Messaging
|
||||
-- The message action can be used regardless of save_to_disk being set as no data is saved, but an external script is still required
|
||||
-- These messages can be used to send data to other servers which doesnt need to be saved such as shouts or commands
|
||||
-- Using messages is quite simple only using message and on_message
|
||||
ExampleData:message(key, message)
|
||||
ExampleData:on_message(function(key, message)
|
||||
game.print('Received message '..message)
|
||||
end)
|
||||
|
||||
@usage-- Combined Datastores
|
||||
-- A combined datastore is a datastore which stores its data inside of another datastore
|
||||
-- This means that the data is stored more efficiently in the external database and less requests need to be made
|
||||
-- To understand how combined datastores work think of each key in the parent as a table where the sub datastore is a key in that table
|
||||
-- Player data is the most used version of the combined datastore, below is how the player data module is setup
|
||||
local PlayerData = Datastore.connect('PlayerData', true) -- saveToDisk
|
||||
PlayerData:set_serializer(Datastore.name_serializer) -- use player name as key
|
||||
PlayerData:combine('Statistics')
|
||||
PlayerData:combine('Settings')
|
||||
PlayerData:combine('Required')
|
||||
|
||||
-- You can then further combine datastores to any depth, below we add some possible settings and statistics that we might use
|
||||
-- Although we dont in this example, each of these functions returns the datastore object which you should use as a local value
|
||||
PlayerData.Settings:combine('Color')
|
||||
PlayerData.Settings:combine('Quickbar')
|
||||
PlayerData.Settings:combine('JoinMessage')
|
||||
PlayerData.Statistics:combine('Playtime')
|
||||
PlayerData.Statistics:combine('JoinCount')
|
||||
|
||||
-- Because sub datastore work just like a normal datastore you dont need any special code, using get and set will still return as if it wasnt a sub datastore
|
||||
-- Things like the serializer and the datastore settings are always the same as the parent so you dont need to worry about setting up the serializer each time
|
||||
-- And because save, request, and unload methods all point to the root datastore you are able to request and save your data as normal
|
||||
|
||||
-- If you used get_all on PlayerData this is what you would get:
|
||||
{
|
||||
Cooldude2606 = {
|
||||
Settings = {
|
||||
Color = 'ColorValue',
|
||||
Quickbar = 'QuickbarValue',
|
||||
JoinMessage = 'JoinMessageValue'
|
||||
},
|
||||
Statistics = {
|
||||
Playtime = 'PlaytimeValue',
|
||||
JoinCount = 'JoinCountValue'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- If you used get_all on PlayerData.Settings this is what you would get:
|
||||
{
|
||||
Cooldude2606 = {
|
||||
Color = 'ColorValue',
|
||||
Quickbar = 'QuickbarValue',
|
||||
JoinMessage = 'JoinMessageValue'
|
||||
}
|
||||
}
|
||||
|
||||
-- If you used get_all on PlayerData.Settings.Color this is what you would get:
|
||||
{
|
||||
Cooldude2606 = 'ColorValue'
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
|
||||
local DatastoreManager = {}
|
||||
local Datastores = {}
|
||||
local Datastore = {}
|
||||
local Data = {}
|
||||
local copy = table.deep_copy
|
||||
local trace = debug.traceback
|
||||
|
||||
--- Save datastores in the global table
|
||||
global.datastores = Data
|
||||
Event.on_load(function()
|
||||
Data = global.datastores
|
||||
for datastoreName, datastore in pairs(Datastores) do
|
||||
datastore.data = Data[datastoreName]
|
||||
end
|
||||
end)
|
||||
|
||||
----- Datastore Manager
|
||||
-- @section datastoreManager
|
||||
|
||||
--- Metatable used on datastores
|
||||
DatastoreManager.metatable = {
|
||||
__index = function(self, key) return rawget(self.children, key) or rawget(Datastore, key) end,
|
||||
__newidnex = function(_, _, _) error('Datastore can not be modified', 2) end,
|
||||
__call = function(self, ...) return self:get(...) end
|
||||
}
|
||||
|
||||
--[[-- Make a new datastore connection, if a connection already exists then it is returned
|
||||
@tparam string datastoreName The name that you want the new datastore to have, this can not have any whitespace
|
||||
@tparam[opt=false] boolean saveToDisk When set to true, using the save method with write the data to datastore.pipe
|
||||
@tparam[opt=false] boolean autoSave When set to true, using any method which modifies data will cause the data to be saved
|
||||
@tparam[opt=false] boolean propagateChanges When set to true, using the save method will send the data to all other connected servers
|
||||
@treturn table The new datastore connection that can be used to access and modify data in the datastore
|
||||
|
||||
@usage-- Connecting to the test datastore which will allow saving to disk
|
||||
local ExampleData = Datastore.connect('ExampleData', true) -- saveToDisk
|
||||
|
||||
]]
|
||||
function DatastoreManager.connect(datastoreName, saveToDisk, autoSave, propagateChanges)
|
||||
if Datastores[datastoreName] then return Datastores[datastoreName] end
|
||||
if _LIFECYCLE ~= _STAGE.control then
|
||||
-- Only allow this function to be called during the control stage
|
||||
error('New datastore connection can not be created during runtime', 2)
|
||||
end
|
||||
|
||||
local new_datastore = {
|
||||
name = datastoreName,
|
||||
value_name = datastoreName,
|
||||
auto_save = autoSave or false,
|
||||
save_to_disk = saveToDisk or false,
|
||||
propagate_changes = propagateChanges or false,
|
||||
serializer = false,
|
||||
parent = false,
|
||||
children = {},
|
||||
metadata = {},
|
||||
events = {},
|
||||
data = {}
|
||||
}
|
||||
|
||||
Data[datastoreName] = new_datastore.data
|
||||
Datastores[datastoreName] = new_datastore
|
||||
return setmetatable(new_datastore, DatastoreManager.metatable)
|
||||
end
|
||||
|
||||
--[[-- Make a new datastore that stores its data inside of another one
|
||||
@tparam string datastoreName The name of the datastore that will contain the data for the new datastore
|
||||
@tparam string subDatastoreName The name of the new datastore, this name will also be used as the key inside the parent datastore
|
||||
@treturn table The new datastore connection that can be used to access and modify data in the datastore
|
||||
|
||||
@usage-- Setting up a datastore which stores its data inside of another datastore
|
||||
local BarData = Datastore.combine('ExampleData', 'Bar')
|
||||
|
||||
]]
|
||||
function DatastoreManager.combine(datastoreName, subDatastoreName)
|
||||
local datastore = assert(Datastores[datastoreName], 'Datastore not found '..tostring(datastoreName))
|
||||
return datastore:combine(subDatastoreName)
|
||||
end
|
||||
|
||||
--[[-- Ingest the result from a request, this is used through a rcon interface to sync data
|
||||
@tparam string action The action that should be done, can be: remove, message, propagate, or request
|
||||
@tparam string datastoreName The name of the datastore that should have the action done to it
|
||||
@tparam string key The key of that datastore that is having the action done to it
|
||||
@tparam string valueJson The json string for the value being ingested, remove does not require a value
|
||||
|
||||
@usage-- Replying to a data request
|
||||
Datastore.ingest('request', 'ExampleData', 'TestKey', 'Foo')
|
||||
|
||||
]]
|
||||
function DatastoreManager.ingest(action, datastoreName, key, valueJson)
|
||||
local datastore = assert(Datastores[datastoreName], 'Datastore ingest error, Datastore not found '..tostring(datastoreName))
|
||||
assert(type(action) == 'string', 'Datastore ingest error, Action is not a string got: '..type(action))
|
||||
assert(type(key) == 'string', 'Datastore ingest error, Key is not a string got: '..type(key))
|
||||
|
||||
if action == 'remove' then
|
||||
datastore:raw_set(key)
|
||||
|
||||
elseif action == 'message' then
|
||||
local success, value = pcall(game.json_to_table, valueJson)
|
||||
if not success or value == nil then value = tonumber(valueJson) or valueJson end
|
||||
datastore:raise_event('on_message', key, value)
|
||||
|
||||
elseif action == 'propagate' or action == 'request' then
|
||||
local success, value = pcall(game.json_to_table, valueJson)
|
||||
if not success or value == nil then value = tonumber(valueJson) or valueJson end
|
||||
local old_value = datastore:raw_get(key)
|
||||
value = datastore:raise_event('on_load', key, value, old_value)
|
||||
datastore:set(key, value)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[-- Debug, Use to get all datastores, or return debug info on a datastore
|
||||
@tparam[opt] string datastoreName The name of the datastore to get the debug info of
|
||||
|
||||
@usage-- Get all the datastores
|
||||
local datastores = Datastore.debug()
|
||||
|
||||
@usage-- Getting the debug info for a datastore
|
||||
local debug_info = Datastore.debug('ExampleData')
|
||||
|
||||
]]
|
||||
function DatastoreManager.debug(datastoreName)
|
||||
if not datastoreName then return Datastores end
|
||||
local datastore = assert(Datastores[datastoreName], 'Datastore not found '..tostring(datastoreName))
|
||||
return datastore:debug()
|
||||
end
|
||||
|
||||
--[[-- Commonly used serializer, returns the name of the object
|
||||
@tparam any rawKey The raw key that will be serialized, this can be things like player, force, surface, etc
|
||||
@treturn string The name of the object that was passed
|
||||
|
||||
@usage-- Using the name serializer for your datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set_serializer(Datastore.name_serializer)
|
||||
|
||||
]]
|
||||
function DatastoreManager.name_serializer(rawKey)
|
||||
return rawKey.name
|
||||
end
|
||||
|
||||
----- Datastore Internal
|
||||
-- @section datastore-internal
|
||||
|
||||
--[[-- Debug, Get the debug info for this datastore
|
||||
@treturn table The debug info for this datastore, contains stuff like parent, settings, children, etc
|
||||
|
||||
@usage-- Get the debug info for a datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local debug_info = ExampleData:debug()
|
||||
|
||||
]]
|
||||
function Datastore:debug()
|
||||
local debug_info = {}
|
||||
|
||||
if self.parent then
|
||||
debug_info.parent = self.parent.name
|
||||
else
|
||||
debug_info.settings = { auto_save = self.auto_save, save_to_disk = self.save_to_disk, propagate_changes = self.propagate_changes, serializer = not not self.serializer }
|
||||
end
|
||||
|
||||
local children = {}
|
||||
for name in pairs(self.children) do children[#children+1] = name end
|
||||
if #children > 0 then debug_info.children = children end
|
||||
|
||||
local events = {}
|
||||
for name, handlers in pairs(self.events) do events[name] = #handlers end
|
||||
if next(events) then debug_info.events = events end
|
||||
|
||||
if next(self.metadata) then debug_info.metadata = self.metadata end
|
||||
debug_info.data = self:get_all()
|
||||
|
||||
return debug_info
|
||||
end
|
||||
|
||||
--[[-- Internal, Get data following combine logic
|
||||
@tparam string key The key to get the value of from this datastore
|
||||
@tparam[opt=false] boolean fromChild If the get request came from a child of this datastore
|
||||
@treturn any The value that was stored at this key in this datastore
|
||||
|
||||
@usage-- Internal, Get the data from a datastore
|
||||
local value = self:raw_get('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:raw_get(key, fromChild)
|
||||
local data = self.data
|
||||
if self.parent then
|
||||
data = self.parent:raw_get(key, true)
|
||||
key = self.value_name
|
||||
end
|
||||
local value = data[key]
|
||||
if value ~= nil then return value end
|
||||
if fromChild then value = {} end
|
||||
data[key] = value
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Internal, Set data following combine logic
|
||||
@tparam string key The key to set the value of in this datastore
|
||||
@tparam any value The value that will be set at this key
|
||||
|
||||
@usage-- Internal, Set the value in a datastore
|
||||
self:raw_set('TestKey', 'Foo')
|
||||
|
||||
]]
|
||||
function Datastore:raw_set(key, value)
|
||||
if self.parent then
|
||||
local data = self.parent:raw_get(key, true)
|
||||
data[self.value_name] = value
|
||||
else
|
||||
self.data[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
local function serialize_error(err) error('An error ocurred in a datastore serializer: '..trace(err)) end
|
||||
--[[-- Internal, Return the serialized key
|
||||
@tparam any rawKey The key that needs to be serialized, if it is already a string then it is returned
|
||||
@treturn string The key after it has been serialized
|
||||
|
||||
@usage-- Internal, Ensure that the key is a string
|
||||
key = self:serialize(key)
|
||||
|
||||
]]
|
||||
function Datastore:serialize(rawKey)
|
||||
if type(rawKey) == 'string' then return rawKey end
|
||||
assert(self.serializer, 'Datastore does not have a serializer and received non string key')
|
||||
local success, key = xpcall(self.serializer, serialize_error, rawKey)
|
||||
return success and key or nil
|
||||
end
|
||||
|
||||
--[[-- Internal, Writes an event to the output file to be saved and/or propagated
|
||||
@tparam string action The action that should be wrote to datastore.pipe, can be request, remove, message, save, propagate
|
||||
@tparam string key The key that the action is being preformed on
|
||||
@tparam any value The value that should be used with the action
|
||||
|
||||
@usage-- Write a data request to datastore.pipe
|
||||
self:write_action('request', 'TestKey')
|
||||
|
||||
@usage-- Write a data save to datastore.pipe
|
||||
self:write_action('save', 'TestKey', 'Foo')
|
||||
|
||||
]]
|
||||
function Datastore:write_action(action, key, value)
|
||||
local data = {action, self.name, key}
|
||||
if value ~= nil then
|
||||
data[4] = type(value) == 'table' and game.table_to_json(value) or value
|
||||
end
|
||||
game.write_file('ext/datastore.out', table.concat(data, ' ')..'\n', true, 0)
|
||||
end
|
||||
|
||||
----- Datastore Local
|
||||
-- @section datastore-local
|
||||
|
||||
--[[-- Create a new datastore which is stores its data inside of this datastore
|
||||
@tparam string subDatastoreName The name of the datastore that will have its data stored in this datastore
|
||||
@treturn table The new datastore that was created inside of this datastore
|
||||
|
||||
@usage-- Add a new sub datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local BarData = ExampleData:combine('Bar')
|
||||
|
||||
]]
|
||||
function Datastore:combine(subDatastoreName)
|
||||
local new_datastore = DatastoreManager.connect(self.name..'.'..subDatastoreName)
|
||||
self.children[subDatastoreName] = new_datastore
|
||||
new_datastore.value_name = subDatastoreName
|
||||
new_datastore.serializer = self.serializer
|
||||
new_datastore.auto_save = self.auto_save
|
||||
new_datastore.parent = self
|
||||
Data[new_datastore.name] = nil
|
||||
new_datastore.data = nil
|
||||
return new_datastore
|
||||
end
|
||||
|
||||
--[[-- Set a callback that will be used to serialize keys which aren't strings
|
||||
@tparam function callback The function that will be used to serialize non string keys passed as an argument
|
||||
|
||||
@usage-- Set a custom serializer, this would be the same as Datastore.name_serializer
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set_serializer(function(rawKey)
|
||||
return rawKey.name
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:set_serializer(callback)
|
||||
assert(type(callback) == 'function', 'Callback must be a function')
|
||||
self.serializer = callback
|
||||
end
|
||||
|
||||
--[[-- Set a default value to be returned by get if no other default is given, using will mean get will never return nil, set using the default will set to nil to save space
|
||||
@tparam any value The value that will be deep copied by get if the value is nil and no other default is given
|
||||
@tparam boolean allowSet When true if the default is passed as the value for set it will be set rather than setting nil
|
||||
|
||||
@usage-- Set a default value to be returned by get
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set_default('Foo')
|
||||
|
||||
]]
|
||||
function Datastore:set_default(value, allowSet)
|
||||
self.default = value
|
||||
self.allow_set_to_default = allowSet
|
||||
end
|
||||
|
||||
--[[-- Set metadata tags on this datastore which can be accessed by other scripts
|
||||
@tparam table tags A table of tags that you want to set in the metadata for this datastore
|
||||
|
||||
@usage-- Adding metadata that could be used by a gui to help understand the stored data
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set_metadata{
|
||||
caption = 'Test Data',
|
||||
tooltip = 'Data used for testing datastores',
|
||||
type = 'table'
|
||||
}
|
||||
|
||||
]]
|
||||
function Datastore:set_metadata(tags)
|
||||
local metadata = self.metadata
|
||||
for key, value in pairs(tags) do
|
||||
metadata[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Get a value from local storage, option to have a default value, do not edit the data returned as changes may not save, use update if you want to make changes
|
||||
@tparam any key The key that you want to get the value of, must be a string unless a serializer is set
|
||||
@tparam[opt] any default The default value that will be returned if no value is found in the datastore
|
||||
|
||||
@usage-- Get a key from the datastore, the default will be deep copied if no value exists in the datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local value = ExampleData:get('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:get(key, default)
|
||||
key = self:serialize(key)
|
||||
local value = self:raw_get(key)
|
||||
if value ~= nil then return value end
|
||||
return copy(default or self.default)
|
||||
end
|
||||
|
||||
--[[-- Set a value in local storage, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
|
||||
@tparam any key The key that you want to set the value of, must be a string unless a serializer is set
|
||||
@tparam any value The value that you want to set for this key
|
||||
|
||||
@usage-- Set a value in the datastore, this will trigger on_update, if auto_save is true then will trigger save
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:set('TestKey', 'Foo')
|
||||
|
||||
]]
|
||||
function Datastore:set(key, value)
|
||||
key = self:serialize(key)
|
||||
local old_value = self:raw_get(key)
|
||||
if value == self.default and not self.allow_set_to_default then
|
||||
self:raw_set(key)
|
||||
else
|
||||
self:raw_set(key, value)
|
||||
end
|
||||
self:raise_event('on_update', key, value, old_value)
|
||||
if self.auto_save then self:save(key) end
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Increment the value in local storage, only works for number values, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
|
||||
@tparam any key The key that you want to increment the value of, must be a string unless a serializer is set
|
||||
@tparam[opt=1] number delta The amount that you want to increment the value by, can be negative or a decimal
|
||||
|
||||
@usage-- Increment a value in a datastore, the value must be a number or nil, if nil 0 is used as the start value
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:increment('TestNumber')
|
||||
|
||||
]]
|
||||
function Datastore:increment(key, delta)
|
||||
key = self:serialize(key)
|
||||
local value = self:raw_get(key) or 0
|
||||
return self:set(key, value + (delta or 1))
|
||||
end
|
||||
|
||||
local function update_error(err) log('An error occurred in datastore update:\n\t'..trace(err)) end
|
||||
--[[-- Use a function to update the value locally, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
|
||||
@tparam any key The key that you want to apply the update to, must be a string unless a serializer is set
|
||||
@tparam function callback The function that will be used to update the value at this key
|
||||
|
||||
@usage-- Using a function to update a value, if a value is returned then this will be the new value
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:increment('TestKey', function(key, value)
|
||||
return value..value
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:update(key, callback)
|
||||
key = self:serialize(key)
|
||||
local value = self:get(key)
|
||||
local raw_value = self:raw_get(key)
|
||||
local old_value = copy(self:raw_get(key))
|
||||
local success, new_value = xpcall(callback, update_error, key, value)
|
||||
if not success then
|
||||
self:raw_set(key, old_value)
|
||||
elseif new_value ~= nil then
|
||||
self:set(key, new_value)
|
||||
elseif raw_value == nil then
|
||||
self:set(key, value)
|
||||
else
|
||||
self:raise_event('on_update', key, value, old_value)
|
||||
if self.auto_save then self:save(key) end
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Remove a value locally and on the external source, works regardless of propagateChanges, requires save_to_disk for external changes
|
||||
@tparam any key The key that you want to remove locally and externally, must be a string unless a serializer is set
|
||||
|
||||
@usage-- Remove a key locally and externally
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:remove('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:remove(key)
|
||||
key = self:serialize(key)
|
||||
local old_value = self:raw_get(key)
|
||||
self:raw_set(key)
|
||||
self:raise_event('on_update', key, nil, old_value)
|
||||
if self.save_to_disk then self:write_action('remove', key) end
|
||||
if self.parent and self.parent.auto_save then return self.parent:save(key) end
|
||||
end
|
||||
|
||||
local function filter_error(err) log('An error ocurred in a datastore filter:\n\t'..trace(err)) end
|
||||
--[[-- Internal, Used to filter elements from a table
|
||||
@tparam table tbl The table that will have the filter applied to it
|
||||
@tparam[opt] function callback The function that will be used as a filter, if none giving then the provided table is returned
|
||||
@treturn table The table which has only the key values pairs which passed the filter
|
||||
|
||||
@usage-- Internal, Filter a table by the values it contains, return true to keep the key value pair
|
||||
local filtered_table = filter({5,3,4,1,2}, function(key, value)
|
||||
return value > 2
|
||||
end)
|
||||
|
||||
]]
|
||||
local function filter(tbl, callback)
|
||||
if not callback then return tbl end
|
||||
local rtn = {}
|
||||
for key, value in pairs(tbl) do
|
||||
local success, add = xpcall(callback, filter_error, key, value)
|
||||
if success and add then rtn[key] = value end
|
||||
end
|
||||
return rtn
|
||||
end
|
||||
|
||||
--[[-- Get all keys in this datastore, optional filter callback
|
||||
@tparam[opt] function callback The filter function that can be used to filter the results returned
|
||||
@treturn table All the data that is in this datastore, filtered if a filter was provided
|
||||
|
||||
@usage-- Get all the data in this datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local data = ExampleData:get_all()
|
||||
|
||||
@usage-- Get all the data in this datastore, with a filter
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local data = ExampleData:get_all(function(key, value)
|
||||
return type(value) == 'string'
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:get_all(callback)
|
||||
if not self.parent then
|
||||
return filter(self.data, callback)
|
||||
else
|
||||
local data, value_name = {}, self.value_name
|
||||
for key, value in pairs(self.parent:get_all()) do
|
||||
data[key] = value[value_name]
|
||||
end
|
||||
return filter(data, callback)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Update all keys in this datastore using the same update function
|
||||
@tparam function callback The update function that will be applied to each key
|
||||
|
||||
@usage-- Get all the data in this datastore, with a filter
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:update_all(function(key, value)
|
||||
return value..value
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:update_all(callback)
|
||||
local data = self:get_all()
|
||||
for key, value in pairs(data) do
|
||||
local old_value = copy(value)
|
||||
local success, new_value = xpcall(callback, update_error, key, value)
|
||||
if success and new_value ~= nil then
|
||||
self:set(key, new_value)
|
||||
else
|
||||
self:raise_event('on_update', key, value, old_value)
|
||||
if self.auto_save then self:save(key) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----- Datastore External
|
||||
-- @section datastore-external
|
||||
|
||||
--[[-- Request a value from an external source, will trigger on_load when data is received
|
||||
@tparam any key The key that you want to request from an external source, must be a string unless a serializer is set
|
||||
|
||||
@usage-- Request a key from an external source, on_load is triggered when data is received
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:request('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:request(key)
|
||||
if self.parent then return self.parent:request(key) end
|
||||
key = self:serialize(key)
|
||||
self:write_action('request', key)
|
||||
end
|
||||
|
||||
--[[-- Save a value to an external source, will trigger on_save before data is saved, save_to_disk must be set to true
|
||||
@tparam any key The key that you want to save to an external source, must be a string unless a serializer is set
|
||||
|
||||
@usage-- Save a key to an external source, save_to_disk must be set to true for there to be any effect
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:save('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:save(key)
|
||||
if self.parent then self.parent:save(key) end
|
||||
if not self.save_to_disk then return end
|
||||
key = self:serialize(key)
|
||||
local value = self:raise_event('on_save', key, copy(self:raw_get(key)))
|
||||
local action = self.propagate_changes and 'propagate' or 'save'
|
||||
self:write_action(action, key, value)
|
||||
end
|
||||
|
||||
--[[-- Save a value to an external source and remove locally, will trigger on_unload then on_save, save_to_disk is not required for on_unload
|
||||
@tparam any key The key that you want to unload from the datastore, must be a string unless a serializer is set
|
||||
|
||||
@usage-- Unload a key from the datastore, get will now return nil and value will be saved externally if save_to_disk is set to true
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:unload('TestKey')
|
||||
|
||||
]]
|
||||
function Datastore:unload(key)
|
||||
if self.parent then return self.parent:unload(key) end
|
||||
key = self:serialize(key)
|
||||
self:raise_event('on_unload', key, copy(self:raw_get(key)))
|
||||
self:save(key)
|
||||
self:raw_set(key)
|
||||
end
|
||||
|
||||
--[[-- Use to send a message over the connection, works regardless of saveToDisk and propagateChanges
|
||||
@tparam any key The key that you want to send a message over, must be a string unless a serializer is set
|
||||
@tparam any message The message that you want to send to other connected servers, or external source
|
||||
|
||||
@usage-- Send a message to other servers on this key, can listen for messages with on_message
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:message('TestKey', 'Foo')
|
||||
|
||||
]]
|
||||
function Datastore:message(key, message)
|
||||
key = self:serialize(key)
|
||||
self:write_action('message', key, message)
|
||||
end
|
||||
|
||||
--[[-- Save all the keys in the datastore, optional filter callback
|
||||
@tparam[opt] function callback The filter function that can be used to filter the keys saved
|
||||
|
||||
@usage-- Save all the data in this datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
local data = ExampleData:save_all()
|
||||
|
||||
@usage-- Save all the data in this datastore, with a filter
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:save_all(function(key, value)
|
||||
return type(value) == 'string'
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:save_all(callback)
|
||||
local data = self:get_all(callback)
|
||||
for key in pairs(data) do self:save(key) end
|
||||
end
|
||||
|
||||
--[[-- Unload all the keys in the datastore, optional filter callback
|
||||
@tparam[opt] function callback The filter function that can be used to filter the keys unloaded
|
||||
|
||||
@usage-- Unload all the data in this datastore
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:unload_all()
|
||||
|
||||
@usage-- Unload all the data in this datastore, with a filter
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:unload_all(function(key, value)
|
||||
return type(value) == 'string'
|
||||
end)
|
||||
|
||||
]]
|
||||
function Datastore:unload_all(callback)
|
||||
local data = self:get_all(callback)
|
||||
for key in pairs(data) do self:unload(key) end
|
||||
end
|
||||
|
||||
----- Events
|
||||
-- @section events
|
||||
|
||||
local function event_error(err) log('An error ocurred in a datastore event handler:\n\t'..trace(err)) end
|
||||
--[[-- Internal, Raise an event on this datastore
|
||||
@tparam string event_name The name of the event to raise for this datastore
|
||||
@tparam string key The key that this event is being raised for
|
||||
@tparam[opt] any value The current value that this key has, might be a deep copy of the value
|
||||
@tparam[opt] any old_value The previous value that this key has, might be a deep copy of the value
|
||||
@tparam[opt] string source Where this call came from, used to do event recursion so can be parent or child
|
||||
@treturn any The value that is left after being passed through all the event handlers
|
||||
|
||||
@usage-- Internal, Getting the value that should be saved
|
||||
value = self:raise_event('on_save', key, value)
|
||||
|
||||
]]
|
||||
function Datastore:raise_event(event_name, key, value, old_value, source)
|
||||
-- Raise the event for the children of this datastore
|
||||
if source ~= 'child' and next(self.children) then
|
||||
if type(value) ~= 'table' then value = {} end
|
||||
for value_name, child in pairs(self.children) do
|
||||
local old_child_value = old_value and old_value[value_name] or nil
|
||||
value[value_name] = child:raise_event(event_name, key, value[value_name], old_child_value, 'parent')
|
||||
end
|
||||
end
|
||||
|
||||
-- Raise the event for this datastore
|
||||
local handlers = self.events[event_name]
|
||||
if handlers then
|
||||
for _, handler in ipairs(handlers) do
|
||||
local success, new_value = xpcall(handler, event_error, key, value, old_value)
|
||||
if success and new_value ~= nil then value = new_value end
|
||||
end
|
||||
end
|
||||
|
||||
-- Raise the event for the parent of this datastore
|
||||
if source ~= 'parent' and self.parent then
|
||||
local parent_value = self.parent:raw_get(key, true)
|
||||
self.parent:raise_event(event_name, key, parent_value, parent_value, 'child')
|
||||
end
|
||||
|
||||
-- If this is the save event and the table is empty then return nil
|
||||
if event_name == 'on_save' and next(self.children) and not next(value) then return end
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Internal, Returns a function which will add a callback to an event
|
||||
@tparam string event_name The name of the event that this should create a handler adder for
|
||||
@treturn function The function that can be used to add handlers to this event
|
||||
|
||||
@usage-- Internal, Get the function to add handlers to on_load
|
||||
Datastore.on_load = event_factory('on_load')
|
||||
|
||||
]]
|
||||
local function event_factory(event_name)
|
||||
return function(self, callback)
|
||||
assert(type(callback) == 'function', 'Handler must be a function')
|
||||
local handlers = self.events[event_name]
|
||||
if not handlers then
|
||||
self.events[event_name] = { callback }
|
||||
else
|
||||
handlers[#handlers+1] = callback
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Register a callback that triggers when data is loaded from an external source, returned value is saved locally
|
||||
@tparam function callback The handler that will be registered to the on_load event
|
||||
@usage-- Adding a handler to on_load, returned value will be saved locally, can be used to deserialize the value beyond a normal json
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:on_load(function(key, value)
|
||||
game.print('Test data loaded for: '..key)
|
||||
end)
|
||||
]]
|
||||
Datastore.on_load = event_factory('on_load')
|
||||
|
||||
--[[-- Register a callback that triggers before data is saved, returned value is saved externally
|
||||
@tparam function callback The handler that will be registered to the on_load event
|
||||
@usage-- Adding a handler to on_save, returned value will be saved externally, can be used to serialize the value beyond a normal json
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:on_save(function(key, value)
|
||||
game.print('Test data saved for: '..key)
|
||||
end)
|
||||
]]
|
||||
Datastore.on_save = event_factory('on_save')
|
||||
|
||||
--[[-- Register a callback that triggers before data is unloaded, returned value is ignored
|
||||
@tparam function callback The handler that will be registered to the on_load event
|
||||
@usage-- Adding a handler to on_unload, returned value is ignored, can be used to clean up guis or local values related to this data
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:on_load(function(key, value)
|
||||
game.print('Test data unloaded for: '..key)
|
||||
end)
|
||||
]]
|
||||
Datastore.on_unload = event_factory('on_unload')
|
||||
|
||||
--[[-- Register a callback that triggers when a message is received, returned value is ignored
|
||||
@tparam function callback The handler that will be registered to the on_load event
|
||||
@usage-- Adding a handler to on_message, returned value is ignored, can be used to receive messages from other connected servers without saving data
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:on_message(function(key, value)
|
||||
game.print('Test data message for: '..key)
|
||||
end)
|
||||
]]
|
||||
Datastore.on_message = event_factory('on_message')
|
||||
|
||||
--[[-- Register a callback that triggers any time a value is changed, returned value is ignored
|
||||
@tparam function callback The handler that will be registered to the on_load event
|
||||
@usage-- Adding a handler to on_update, returned value is ignored, can be used to update guis or send messages when data is changed
|
||||
local ExampleData = Datastore.connect('ExampleData')
|
||||
ExampleData:on_update(function(key, value)
|
||||
game.print('Test data updated for: '..key)
|
||||
end)
|
||||
]]
|
||||
Datastore.on_update = event_factory('on_update')
|
||||
|
||||
----- Module Return
|
||||
return DatastoreManager
|
||||
153
exp_legacy/module/expcore/external.lua
Normal file
153
exp_legacy/module/expcore/external.lua
Normal file
@@ -0,0 +1,153 @@
|
||||
--[[-- Core Module - External
|
||||
- A module used to make accessing externally set data easier.
|
||||
@core External
|
||||
@alias External
|
||||
|
||||
@usage-- Printing all server to chat
|
||||
local External = require 'expcore.external' --- @dep expcore.external
|
||||
|
||||
local message = 'id: %s name: %s version: %s status: %s'
|
||||
for server_id, server in pairs(External.get_servers()) do
|
||||
local status = External.get_server_status(server_id)
|
||||
game.print(message:format(server_id, server.name, server.version, status))
|
||||
end
|
||||
|
||||
]]
|
||||
|
||||
local ext, var
|
||||
local concat = table.concat
|
||||
|
||||
local External = {}
|
||||
|
||||
--[[-- Checks that local links are valid, will try to add the links if invalid
|
||||
@treturn boolean If the external data is valid, if false you should not call any other methods from External
|
||||
|
||||
@usage-- Check that external data is valid
|
||||
if not External.valid() then
|
||||
-- error code here
|
||||
end
|
||||
|
||||
]]
|
||||
function External.valid()
|
||||
if global.ext == nil then return false end
|
||||
if ext == global.ext and var == ext.var then
|
||||
return var ~= nil
|
||||
else
|
||||
ext = global.ext
|
||||
var = ext.var
|
||||
return var ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Gets a table of all the servers, key is the server id, value is the server details
|
||||
@treturn table A table containing all the servers, key is the server id, value is the server details
|
||||
|
||||
@usage-- Get all servers
|
||||
local servers = External.get_servers()
|
||||
|
||||
]]
|
||||
function External.get_servers()
|
||||
assert(ext, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
return assert(ext.servers, 'No server list was found, please ensure that the external service is running')
|
||||
end
|
||||
|
||||
--[[-- Gets a table of all the servers filtered by name, key is the server id, value is the server details
|
||||
@tparam string search The string to search for, names, short_names and ids are checked for this string.
|
||||
@treturn table A table containing all the servers filtered by name, key is the server id, value is the server details
|
||||
|
||||
@usage-- Get all servers with public in the name
|
||||
local servers = External.get_servers_filtered(public)
|
||||
|
||||
]]
|
||||
function External.get_servers_filtered(search)
|
||||
assert(ext, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
local servers = assert(ext.servers, 'No server list was found, please ensure that the external service is running')
|
||||
local found_servers = {}
|
||||
search = search:lower()
|
||||
for server_id, server in pairs(servers) do
|
||||
local str = concat{server.name, server.short_name, server.id}
|
||||
if str:lower():find(search, 1, true) then found_servers[server_id] = server end
|
||||
end
|
||||
return found_servers
|
||||
end
|
||||
|
||||
--[[-- Gets the details of the current server
|
||||
@treturn table The details of the current server
|
||||
|
||||
@usage-- Get the details of the current server
|
||||
local server = External.get_current_server()
|
||||
|
||||
]]
|
||||
function External.get_current_server()
|
||||
assert(ext, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
local servers = assert(ext.servers, 'No server list was found, please ensure that the external service is running')
|
||||
local server_id = assert(ext.current, 'No current id was found, please ensure that the external service is running')
|
||||
return servers[server_id]
|
||||
end
|
||||
|
||||
--[[-- Gets the details of the given server
|
||||
@tparam string server_id The internal server if for the server you want the details of
|
||||
@treturn table The details of the given server
|
||||
|
||||
@usage-- Get the details of the given server
|
||||
local server = External.get_server_details('eu-01')
|
||||
|
||||
]]
|
||||
function External.get_server_details(server_id)
|
||||
assert(ext, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
local servers = assert(ext.servers, 'No server list was found, please ensure that the external service is running')
|
||||
return servers[server_id]
|
||||
end
|
||||
|
||||
--[[-- Gets the status of the given server
|
||||
@tparam string server_id The internal server if for the server you want the status of
|
||||
@tparam boolean raw When true Current will not be returned as status but rather the raw status for the server
|
||||
@treturn string The status of the given server, one of: Online, Modded, Protected, Current, Offline
|
||||
|
||||
@usage-- Get the status of the given server
|
||||
local status = External.get_server_status('eu-01')
|
||||
|
||||
]]
|
||||
function External.get_server_status(server_id, raw)
|
||||
assert(var, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
local servers = assert(var.status, 'No server status was found, please ensure that the external service is running')
|
||||
local current = assert(ext.current, 'No current id was found, please ensure that the external service is running')
|
||||
return not raw and server_id == current and 'Current' or servers[server_id]
|
||||
end
|
||||
|
||||
--[[-- Gets the ups of the current server
|
||||
@usage-- Get the ups of the current server
|
||||
local server_ups = External.get_server_ups()
|
||||
|
||||
]]
|
||||
function External.get_server_ups()
|
||||
assert(var, 'No external data was found, use External.valid() to ensure external data exists.')
|
||||
return assert(var.server_ups, 'No server ups was found, please ensure that the external service is running')
|
||||
end
|
||||
|
||||
--[[-- Connect a player to the given server
|
||||
@tparam LuaPlayer player The player that you want to request to join a different server
|
||||
@tparam string server_id The internal id of the server to connect to, can also be any address but this will show Unknown Server
|
||||
@tparam[opt=false] boolean self_requested If the player requested the join them selfs, this will hide the message about being asked to switch
|
||||
|
||||
@usage-- Request that a player joins a different server
|
||||
External.request_connection(player, 'eu-01')
|
||||
|
||||
@usage-- Request that a player joins a different server, by own request
|
||||
External.request_connection(player, 'eu-01', true)
|
||||
|
||||
]]
|
||||
function External.request_connection(player, server_id, self_requested)
|
||||
local server = { address = server_id, name = 'Unknown Server', description = 'This server is not ran by us, please check the address of the server.' }
|
||||
if ext and ext.servers and ext.servers[server_id] then server = ext.servers[server_id] end
|
||||
local message = 'Please press the connect button below to join.'
|
||||
if not self_requested then message = 'You have been asked to switch to a different server.\n'..message end
|
||||
player.connect_to_server{
|
||||
address = server.address,
|
||||
name = '\n[color=orange][font=heading-1]'..server.name..'[/font][/color]\n',
|
||||
description = server.description..'\n'..message
|
||||
}
|
||||
end
|
||||
|
||||
--- Module return
|
||||
return External
|
||||
1
exp_legacy/module/expcore/gui.lua
Normal file
1
exp_legacy/module/expcore/gui.lua
Normal file
@@ -0,0 +1 @@
|
||||
return require 'expcore.gui._require'
|
||||
144
exp_legacy/module/expcore/gui/_require.lua
Normal file
144
exp_legacy/module/expcore/gui/_require.lua
Normal file
@@ -0,0 +1,144 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Used to simplify gui creation using factory functions called element defines
|
||||
@core Gui
|
||||
@alias Gui
|
||||
|
||||
@usage-- To draw your element you only need to call the factory function
|
||||
-- You are able to pass any other arguments that are used in your custom functions but the first is always the parent element
|
||||
local example_button_element = example_button(parent_element)
|
||||
|
||||
@usage-- Making a factory function for a button with the caption "Example Button"
|
||||
-- This method has all the same features as LuaGuiElement.add
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button'
|
||||
}
|
||||
|
||||
@usage-- Making a factory function for a button which is contained within a flow
|
||||
-- This method is for when you still want to register event handlers but cant use the table method
|
||||
local example_flow_with_button =
|
||||
Gui.element(function(definition, parent, ...)
|
||||
-- ... shows that all other arguments from the factory call are passed to this function
|
||||
-- Here we are adding a flow which we will then later add a button to
|
||||
local flow =
|
||||
parent.add{ -- paraent is the element which is passed to the factory function
|
||||
name = 'example_flow',
|
||||
type = 'flow'
|
||||
}
|
||||
|
||||
-- Now we add the button to the flow that we created earlier
|
||||
local element = definition:triggers_event(
|
||||
flow.add{
|
||||
type = 'button',
|
||||
caption = 'Example Button'
|
||||
}
|
||||
)
|
||||
|
||||
-- You must return a new element, this is so styles can be applied and returned to the caller
|
||||
-- You may return any of your elements that you added, consider the context in which it will be used for which should be returned
|
||||
return element
|
||||
end)
|
||||
|
||||
@usage-- Styles can be added to any element define, simplest way mimics LuaGuiElement.style[key] = value
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button',
|
||||
style = 'forward_button' -- factorio styles can be applied here
|
||||
}
|
||||
:style{
|
||||
height = 25, -- same as element.style.height = 25
|
||||
width = 100 -- same as element.style.width = 25
|
||||
}
|
||||
|
||||
@usage-- Styles can also have a custom function when the style is dynamic and depends on other factors
|
||||
-- Use this method if your style is dynamic and depends on other factors
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button',
|
||||
style = 'forward_button' -- factorio styles can be applied here
|
||||
}
|
||||
:style(function(style, element, ...)
|
||||
-- style is the current style object for the elemenent
|
||||
-- element is the element that is being changed
|
||||
-- ... shows that all other arguments from the factory call are passed to this function
|
||||
local player = game.players[element.player_index]
|
||||
style.height = 25
|
||||
style.width = 100
|
||||
style.font_color = player.color
|
||||
end)
|
||||
|
||||
@usage-- You are able to register event handlers to your elements, these can be factorio events or custom ones
|
||||
-- All events are checked to be valid before raising any handlers, this means element.valid = true and player.valid = true
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button'
|
||||
}
|
||||
:on_click(function(player, element, event)
|
||||
-- player is the player who interacted with the element to cause the event
|
||||
-- element is a refrence to the element which caused the event
|
||||
-- event is a raw refrence to the event data if player and element are not enough
|
||||
player.print('Clicked: '..element.name)
|
||||
end)
|
||||
|
||||
@usage-- Example from core_defines, Gui.core_defines.hide_left_flow, called like: hide_left_flow(parent_element)
|
||||
--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible
|
||||
-- @element hide_left_flow
|
||||
local hide_left_flow =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = 'utility/close_black',
|
||||
style = 'tool_button',
|
||||
tooltip = {'expcore-gui.left-button-tooltip'}
|
||||
}
|
||||
:style{
|
||||
padding = -3,
|
||||
width = 18,
|
||||
height = 20
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.hide_left_flow(player)
|
||||
end)
|
||||
|
||||
@usage-- Eample from defines, Gui.alignment, called like: Gui.alignment(parent, name, horizontal_align, vertical_align)
|
||||
-- Notice how _ are used to blank arguments that are not needed in that context and how they line up with above
|
||||
Gui.alignment =
|
||||
Gui.element(function(_, parent, name, _,_)
|
||||
return parent.add{
|
||||
name = name or 'alignment',
|
||||
type = 'flow',
|
||||
}
|
||||
end)
|
||||
:style(function(style, _,_, horizontal_align, vertical_align)
|
||||
style.padding = {1, 2}
|
||||
style.vertical_align = vertical_align or 'center'
|
||||
style.horizontal_align = horizontal_align or 'right'
|
||||
style.vertically_stretchable = style.vertical_align ~= 'center'
|
||||
style.horizontally_stretchable = style.horizontal_align ~= 'center'
|
||||
end)
|
||||
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
require 'expcore.gui.helper_functions'
|
||||
require 'expcore.gui.core_defines'
|
||||
require 'expcore.gui.top_flow'
|
||||
require 'expcore.gui.left_flow'
|
||||
require 'expcore.gui.defines'
|
||||
|
||||
local Roles = _C.opt_require('expcore.roles')
|
||||
local Event = _C.opt_require('utils.event')
|
||||
|
||||
if Roles and Event then
|
||||
Event.add(Roles.events.on_role_assigned, function(e)
|
||||
Gui.update_top_flow(game.get_player(e.player_index))
|
||||
end)
|
||||
Event.add(Roles.events.on_role_unassigned, function(e)
|
||||
Gui.update_top_flow(game.get_player(e.player_index))
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
return Gui
|
||||
89
exp_legacy/module/expcore/gui/core_defines.lua
Normal file
89
exp_legacy/module/expcore/gui/core_defines.lua
Normal file
@@ -0,0 +1,89 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Gui defines that are used internally by the gui system
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
local Event = require 'utils.event'
|
||||
|
||||
--- Core Defines.
|
||||
-- @section coreDefines
|
||||
|
||||
--- Button which toggles the top flow elements, version which shows inside the top flow when top flow is visible
|
||||
-- @element hide_top_flow
|
||||
local hide_top_flow =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = 'utility/preset',
|
||||
style = 'tool_button',
|
||||
tooltip = {'gui_util.button_tooltip'},
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
padding = -2,
|
||||
width = 18,
|
||||
height = 36
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.toggle_top_flow(player, false)
|
||||
end)
|
||||
Gui.core_defines.hide_top_flow = hide_top_flow
|
||||
|
||||
--- Button which toggles the top flow elements, version which shows inside the left flow when top flow is hidden
|
||||
-- @element show_top_flow
|
||||
local show_top_flow =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = 'utility/preset',
|
||||
style = 'tool_button',
|
||||
tooltip = {'gui_util.button_tooltip'},
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
padding = -2,
|
||||
width = 18,
|
||||
height = 20
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.toggle_top_flow(player, true)
|
||||
end)
|
||||
Gui.core_defines.show_top_flow = show_top_flow
|
||||
|
||||
--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible
|
||||
-- @element hide_left_flow
|
||||
local hide_left_flow =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = 'utility/close_black',
|
||||
style = 'tool_button',
|
||||
tooltip = {'expcore-gui.left-button-tooltip'},
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
padding = -3,
|
||||
width = 18,
|
||||
height = 20
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.hide_left_flow(player)
|
||||
end)
|
||||
Gui.core_defines.hide_left_flow = hide_left_flow
|
||||
|
||||
--- Draw the core elements when a player joins the game
|
||||
Event.add(defines.events.on_player_created, function(event)
|
||||
local player = game.players[event.player_index]
|
||||
|
||||
-- Draw the top flow
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
hide_top_flow(top_flow)
|
||||
Gui.update_top_flow(player)
|
||||
|
||||
-- Draw the left flow
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local button_flow = left_flow.add{ type = 'flow', name = 'gui_core_buttons', direction = 'vertical' }
|
||||
local show_top = show_top_flow(button_flow)
|
||||
local hide_left = hide_left_flow(button_flow)
|
||||
show_top.visible = false
|
||||
hide_left.visible = false
|
||||
Gui.draw_left_flow(player)
|
||||
end)
|
||||
298
exp_legacy/module/expcore/gui/defines.lua
Normal file
298
exp_legacy/module/expcore/gui/defines.lua
Normal file
@@ -0,0 +1,298 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Common defines that are used by other modules, non of these are used internally
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
|
||||
--- Defines.
|
||||
-- @section defines
|
||||
|
||||
--[[-- Draw a flow used to align its child elements, default is right align
|
||||
@element Gui.alignment
|
||||
@tparam LuaGuiElement parent the parent element to which the alignment will be added
|
||||
@tparam[opt='alignment'] string name the name of the alignment flow which is added
|
||||
@tparam[opt='right'] string horizontal_align the horizontal alignment of the elements in the flow
|
||||
@tparam[opt='center'] string vertical_align the vertical alignment of the elements in the flow
|
||||
@treturn LuaGuiElement the alignment flow that was created
|
||||
|
||||
@usage-- Adding a right align flow
|
||||
local alignment = Gui.alignment(element, 'example_right_alignment')
|
||||
|
||||
@usage-- Adding a horizontal center and top align flow
|
||||
local alignment = Gui.alignment(element, 'example_center_top_alignment', 'center', 'top')
|
||||
|
||||
]]
|
||||
Gui.alignment =
|
||||
Gui.element(function(_, parent, name, _,_)
|
||||
return parent.add{
|
||||
name = name or 'alignment',
|
||||
type = 'flow',
|
||||
}
|
||||
end)
|
||||
:style(function(style, _,_, horizontal_align, vertical_align)
|
||||
style.padding = {1, 2}
|
||||
style.vertical_align = vertical_align or 'center'
|
||||
style.horizontal_align = horizontal_align or 'right'
|
||||
style.vertically_stretchable = style.vertical_align ~= 'center'
|
||||
style.horizontally_stretchable = style.horizontal_align ~= 'center'
|
||||
end)
|
||||
|
||||
--[[-- Draw a scroll pane that has a table inside of it
|
||||
@element Gui.scroll_table
|
||||
@tparam LuaGuiElement parent the parent element to which the scroll table will be added
|
||||
@tparam number height the maximum height for the scroll pane
|
||||
@tparam number column_count the number of columns that the table will have
|
||||
@tparam[opt='scroll'] string name the name of the scroll pane that is added, the table is always called "table"
|
||||
@treturn LuaGuiElement the table that was created
|
||||
|
||||
@usage-- Adding a scroll table with max height of 200 and column count of 3
|
||||
local scroll_table = Gui.scroll_table(element, 200, 3)
|
||||
|
||||
]]
|
||||
Gui.scroll_table =
|
||||
Gui.element(function(_, parent, height, column_count, name)
|
||||
-- Draw the scroll
|
||||
local scroll_pane =
|
||||
parent.add{
|
||||
name = name or 'scroll',
|
||||
type = 'scroll-pane',
|
||||
direction = 'vertical',
|
||||
horizontal_scroll_policy = 'never',
|
||||
vertical_scroll_policy = 'auto',
|
||||
style = 'scroll_pane_under_subheader'
|
||||
}
|
||||
|
||||
-- Set the style of the scroll pane
|
||||
local scroll_style = scroll_pane.style
|
||||
scroll_style.padding = {1, 3}
|
||||
scroll_style.maximal_height = height
|
||||
scroll_style.horizontally_stretchable = true
|
||||
|
||||
-- Draw the table
|
||||
local scroll_table =
|
||||
scroll_pane.add{
|
||||
type = 'table',
|
||||
name = 'table',
|
||||
column_count = column_count
|
||||
}
|
||||
|
||||
-- Return the scroll table
|
||||
return scroll_table
|
||||
end)
|
||||
:style{
|
||||
padding = 0,
|
||||
cell_padding = 0,
|
||||
vertical_align = 'center',
|
||||
horizontally_stretchable = true
|
||||
}
|
||||
|
||||
--[[-- Used to add a frame with the header style, has the option for a right alignment flow for buttons
|
||||
@element Gui.header
|
||||
@tparam LuaGuiElement parent the parent element to which the header will be added
|
||||
@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the header
|
||||
@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the header
|
||||
@tparam[opt=false] boolean add_alignment when true an alignment flow will be added to the header
|
||||
@tparam[opt='header'] string name the name of the header that is being added, the alignment is always called "alignment"
|
||||
@treturn LuaGuiElement either the header or the header alignment if add_alignment is true
|
||||
|
||||
@usage-- Adding a custom header with a label
|
||||
local header = Gui.header(
|
||||
element,
|
||||
'Example Caption',
|
||||
'Example Tooltip'
|
||||
)
|
||||
|
||||
]]
|
||||
Gui.header =
|
||||
Gui.element(function(_, parent, caption, tooltip, add_alignment, name, label_name)
|
||||
-- Draw the header
|
||||
local header =
|
||||
parent.add{
|
||||
name = name or 'header',
|
||||
type = 'frame',
|
||||
style = 'subheader_frame'
|
||||
}
|
||||
|
||||
-- Change the style of the header
|
||||
local style = header.style
|
||||
style.padding = {2, 4}
|
||||
style.use_header_filler = false
|
||||
style.horizontally_stretchable = true
|
||||
|
||||
-- Draw the caption label
|
||||
if caption then
|
||||
header.add{
|
||||
name = label_name or 'header_label',
|
||||
type = 'label',
|
||||
style = 'heading_1_label',
|
||||
caption = caption,
|
||||
tooltip = tooltip
|
||||
}
|
||||
end
|
||||
|
||||
-- Return either the header or the added alignment
|
||||
return add_alignment and Gui.alignment(header) or header
|
||||
end)
|
||||
|
||||
--[[-- Used to add a frame with the footer style, has the option for a right alignment flow for buttons
|
||||
@element Gui.footer
|
||||
@tparam LuaGuiElement parent the parent element to which the footer will be added
|
||||
@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the footer
|
||||
@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the footer
|
||||
@tparam[opt=false] boolean add_alignment when true an alignment flow will be added to the footer
|
||||
@tparam[opt='footer'] string name the name of the footer that is being added, the alignment is always called "alignment"
|
||||
@treturn LuaGuiElement either the footer or the footer alignment if add_alignment is true
|
||||
|
||||
@usage-- Adding a custom footer with a label
|
||||
local footer = Gui.footer(
|
||||
element,
|
||||
'Example Caption',
|
||||
'Example Tooltip'
|
||||
)
|
||||
|
||||
]]
|
||||
Gui.footer =
|
||||
Gui.element(function(_, parent, caption, tooltip, add_alignment, name)
|
||||
-- Draw the header
|
||||
local footer =
|
||||
parent.add{
|
||||
name = name or 'footer',
|
||||
type = 'frame',
|
||||
style = 'subfooter_frame'
|
||||
}
|
||||
|
||||
-- Change the style of the footer
|
||||
local style = footer.style
|
||||
style.padding = {2, 4}
|
||||
style.use_header_filler = false
|
||||
style.horizontally_stretchable = true
|
||||
|
||||
-- Draw the caption label
|
||||
if caption then
|
||||
footer.add{
|
||||
name = 'footer_label',
|
||||
type = 'label',
|
||||
style = 'heading_1_label',
|
||||
caption = caption,
|
||||
tooltip = tooltip
|
||||
}
|
||||
end
|
||||
|
||||
-- Return either the footer or the added alignment
|
||||
return add_alignment and Gui.alignment(footer) or footer
|
||||
end)
|
||||
|
||||
--[[-- Used for left frames to give them a nice boarder
|
||||
@element Gui.container
|
||||
@tparam LuaGuiElement parent the parent element to which the container will be added
|
||||
@tparam string name the name that you want to give to the outer frame, often just event_trigger
|
||||
@tparam number width the minimal width that the frame will have
|
||||
|
||||
@usage-- Adding a container as a base
|
||||
local container = Gui.container(parent, 'my_container', 200)
|
||||
|
||||
]]
|
||||
Gui.container =
|
||||
Gui.element(function(_, parent, name, _)
|
||||
-- Draw the external container
|
||||
local frame =
|
||||
parent.add{
|
||||
name = name,
|
||||
type = 'frame'
|
||||
}
|
||||
|
||||
-- Return the container
|
||||
return frame.add{
|
||||
name = 'container',
|
||||
type = 'frame',
|
||||
direction = 'vertical',
|
||||
style = 'window_content_frame_packed'
|
||||
}
|
||||
end)
|
||||
:style(function(style, element, _,width)
|
||||
style.vertically_stretchable = false
|
||||
local frame_style = element.parent.style
|
||||
frame_style.padding = 2
|
||||
frame_style.minimal_width = width
|
||||
end)
|
||||
|
||||
--[[-- Used to make a solid white bar in a gui
|
||||
@element Gui.bar
|
||||
@tparam LuaGuiElement parent the parent element to which the bar will be added
|
||||
@tparam number width the width of the bar that will be made, if not given bar will strech to fill the parent
|
||||
|
||||
@usage-- Adding a bar to a gui
|
||||
local bar = Gui.bar(parent, 100)
|
||||
|
||||
]]
|
||||
Gui.bar =
|
||||
Gui.element(function(_, parent)
|
||||
return parent.add{
|
||||
type = 'progressbar',
|
||||
size = 1,
|
||||
value = 1
|
||||
}
|
||||
end)
|
||||
:style(function(style, _,width)
|
||||
style.height = 3
|
||||
style.color = {r=255, g=255, b=255}
|
||||
if width then style.width = width
|
||||
else style.horizontally_stretchable = true end
|
||||
end)
|
||||
|
||||
--[[-- Used to make a label which is centered and of a certian size
|
||||
@element Gui.centered_label
|
||||
@tparam LuaGuiElement parent the parent element to which the label will be added
|
||||
@tparam number width the width of the label, must be given in order to center the caption
|
||||
@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the label
|
||||
@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the label
|
||||
|
||||
@usage-- Adding a centered label
|
||||
local label = Gui.centered_label(parent, 100, 'This is centered')
|
||||
|
||||
]]
|
||||
Gui.centered_label =
|
||||
Gui.element(function(_, parent, width, caption, tooltip)
|
||||
local label = parent.add{
|
||||
type = 'label',
|
||||
caption = caption,
|
||||
tooltip = tooltip,
|
||||
style = 'description_label'
|
||||
}
|
||||
|
||||
local style = label.style
|
||||
style.horizontal_align = 'center'
|
||||
style.single_line = false
|
||||
style.width = width
|
||||
|
||||
return label
|
||||
end)
|
||||
|
||||
--[[-- Used to make a title which has two bars on either side
|
||||
@element Gui.title_label
|
||||
@tparam LuaGuiElement parent the parent element to which the label will be added
|
||||
@tparam number width the width of the first bar, this can be used to position the label
|
||||
@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the label
|
||||
@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the label
|
||||
|
||||
@usage-- Adding a centered label
|
||||
local label = Gui.centered_label(parent, 100, 'This is centered')
|
||||
|
||||
]]
|
||||
Gui.title_label =
|
||||
Gui.element(function(_, parent, width, caption, tooltip)
|
||||
local title_flow = parent.add{ type='flow' }
|
||||
title_flow.style.vertical_align = 'center'
|
||||
|
||||
Gui.bar(title_flow, width)
|
||||
local title_label = title_flow.add{
|
||||
type = 'label',
|
||||
caption = caption,
|
||||
tooltip = tooltip,
|
||||
style = 'heading_1_label'
|
||||
}
|
||||
Gui.bar(title_flow)
|
||||
|
||||
return title_label
|
||||
end)
|
||||
91
exp_legacy/module/expcore/gui/helper_functions.lua
Normal file
91
exp_legacy/module/expcore/gui/helper_functions.lua
Normal file
@@ -0,0 +1,91 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Functions used to help with the use of guis
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
|
||||
--- Helper Functions.
|
||||
-- @section helperFunctions
|
||||
|
||||
--[[-- Get the player that owns a gui element
|
||||
@tparam LuaGuiElement element the element to get the owner of
|
||||
@treturn LuaPlayer the player that owns this element
|
||||
|
||||
@usage-- Geting the owner of an element
|
||||
local player = Gui.get_player_from_element(element)
|
||||
|
||||
]]
|
||||
function Gui.get_player_from_element(element)
|
||||
if not element or not element.valid then return end
|
||||
return game.players[element.player_index]
|
||||
end
|
||||
|
||||
--[[-- Will toggle the enabled state of an element or set it to the one given
|
||||
@tparam LuaGuiElement element the element to toggle/set the enabled state of
|
||||
@tparam[opt] boolean state with given will set the state, else state will be toggled
|
||||
@treturn boolean the new enabled state that the element has
|
||||
|
||||
@usage-- Toggling the the enabled state
|
||||
local new_enabled_state = Gui.toggle_enabled_state(element)
|
||||
|
||||
]]
|
||||
function Gui.toggle_enabled_state(element, state)
|
||||
if not element or not element.valid then return end
|
||||
if state == nil then state = not element.enabled end
|
||||
element.enabled = state
|
||||
return state
|
||||
end
|
||||
|
||||
--[[-- Will toggle the visible state of an element or set it to the one given
|
||||
@tparam LuaGuiElement element the element to toggle/set the visible state of
|
||||
@tparam[opt] boolean state with given will set the state, else state will be toggled
|
||||
@treturn boolean the new visible state that the element has
|
||||
|
||||
@usage-- Toggling the the visible state
|
||||
local new_visible_state = Gui.toggle_visible_state(element)
|
||||
|
||||
]]
|
||||
function Gui.toggle_visible_state(element, state)
|
||||
if not element or not element.valid then return end
|
||||
if state == nil then state = not element.visible end
|
||||
element.visible = state
|
||||
return state
|
||||
end
|
||||
|
||||
--[[-- Destory a gui element without causing any errors, often because the element was already removed
|
||||
@tparam LuaGuiElement element the element that you want to remove
|
||||
@treturn boolean true if the element was valid and has been removed
|
||||
|
||||
@usage-- Remove a child element if it exists
|
||||
Gui.destroy_if_valid(element[child_name])
|
||||
|
||||
]]
|
||||
function Gui.destroy_if_valid(element)
|
||||
if not element or not element.valid then return false end
|
||||
element.destroy()
|
||||
return true
|
||||
end
|
||||
|
||||
--[[-- Returns a table to be used as the style for a sprite buttons, produces a sqaure button
|
||||
@tparam number size the size that you want the button to be
|
||||
@tparam[opt=-2] number padding the padding that you want on the sprite
|
||||
@tparam[opt] table style any extra style settings that you want to have
|
||||
@treturn table the style table to be used with element_define:style()
|
||||
|
||||
@usage-- Adding a sprite button with size 20
|
||||
local button =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = 'entity/inserter'
|
||||
}
|
||||
:style(Gui.sprite_style(20))
|
||||
|
||||
]]
|
||||
function Gui.sprite_style(size, padding, style)
|
||||
style = style or {}
|
||||
style.padding = padding or -2
|
||||
style.height = size
|
||||
style.width = size
|
||||
return style
|
||||
end
|
||||
275
exp_legacy/module/expcore/gui/left_flow.lua
Normal file
275
exp_legacy/module/expcore/gui/left_flow.lua
Normal file
@@ -0,0 +1,275 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Used to define new gui elements and gui event handlers
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
local mod_gui = require 'mod-gui'
|
||||
|
||||
local hide_left_flow = Gui.core_defines.hide_left_flow.name
|
||||
|
||||
--- Left Flow.
|
||||
-- @section leftFlow
|
||||
|
||||
-- Triggered when a user changed the visibility of a left flow element by clicking a button
|
||||
Gui.events.on_visibility_changed_by_click = 'on_visibility_changed_by_click'
|
||||
|
||||
--- Contains the uids of the elements that will shown on the left flow and their join functions
|
||||
-- @table left_elements
|
||||
Gui.left_elements = {}
|
||||
|
||||
--[[-- Gets the flow refered to as the left flow, each player has one left flow
|
||||
@function Gui.get_left_flow(player)
|
||||
@tparam LuaPlayer player the player that you want to get the left flow for
|
||||
@treturn LuaGuiElement the left element flow
|
||||
|
||||
@usage-- Geting your left flow
|
||||
local left_flow = Gui.get_left_flow(game.player)
|
||||
|
||||
]]
|
||||
Gui.get_left_flow = mod_gui.get_frame_flow
|
||||
|
||||
--[[-- Sets an element define to be drawn to the left flow when a player joins, includes optional check
|
||||
@tparam[opt] ?boolean|function open_on_join called during first darw to decide if the element should be visible
|
||||
@treturn table the new element define that is used to register events to this element
|
||||
|
||||
@usage-- Adding the example button
|
||||
example_flow_with_button:add_to_left_flow(true)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:add_to_left_flow(open_on_join)
|
||||
_C.error_if_runtime()
|
||||
if not self.name then error("Elements for the top flow must have a static name") end
|
||||
self.open_on_join = open_on_join or false
|
||||
table.insert(Gui.left_elements, self)
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Creates a button on the top flow which will toggle the given element define, the define must exist in the left flow
|
||||
@tparam string sprite the sprite that you want to use on the button
|
||||
@tparam ?string|Concepts.LocalizedString tooltip the tooltip that you want the button to have
|
||||
@tparam table element_define the element define that you want to have toggled by this button, define must exist on the left flow
|
||||
@tparam[opt] function authenticator used to decide if the button should be visible to a player
|
||||
|
||||
@usage-- Add a button to toggle a left element
|
||||
local toolbar_button =
|
||||
Gui.left_toolbar_button('entity/inserter', 'Nothing to see here', example_flow_with_button, function(player)
|
||||
return player.admin
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui.left_toolbar_button(sprite, tooltip, element_define, authenticator)
|
||||
local button = Gui.toolbar_button(sprite, tooltip, authenticator)
|
||||
|
||||
-- Add on_click handler to handle click events comming from the player
|
||||
button:on_click(function(player, _, _)
|
||||
-- Raise custom event that tells listening elements if the element has changed visibility by a player clicking
|
||||
-- Used in warp gui to handle the keep open logic
|
||||
button:raise_event{
|
||||
name = Gui.events.on_visibility_changed_by_click,
|
||||
element = Gui.get_top_element(player, button),
|
||||
state = Gui.toggle_left_element(player, element_define)
|
||||
}
|
||||
end)
|
||||
|
||||
-- Add property to the left flow element with the name of the button
|
||||
-- This is for the ability to reverse lookup the button from the left flow element
|
||||
element_define.toolbar_button = button
|
||||
button.left_flow_element = element_define
|
||||
return button
|
||||
end
|
||||
|
||||
Gui._left_flow_order_src = "<default>"
|
||||
--- Get the order of elements in the left flow, first argument is player but is unused in the default method
|
||||
function Gui.get_left_flow_order(_)
|
||||
return Gui.left_elements
|
||||
end
|
||||
|
||||
--- Inject a custom left flow order provider, this should accept a player and return a list of elements definitions to draw
|
||||
function Gui.inject_left_flow_order(provider)
|
||||
Gui.get_left_flow_order = provider
|
||||
local debug_info = debug.getinfo(2, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or ("<anonymous:"..debug_info.linedefined..">")
|
||||
Gui._left_flow_order_src = file_name..":"..func_name
|
||||
end
|
||||
|
||||
--[[-- Draw all the left elements onto the left flow, internal use only with on join
|
||||
@tparam LuaPlayer player the player that you want to draw the elements for
|
||||
|
||||
@usage-- Draw all the left elements
|
||||
Gui.draw_left_flow(player)
|
||||
|
||||
]]
|
||||
function Gui.draw_left_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local hide_button = left_flow.gui_core_buttons[hide_left_flow]
|
||||
local show_hide_button = false
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_left_flow_order(player)
|
||||
if #flow_order ~= #Gui.left_elements then
|
||||
error(string.format("Left flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._left_flow_order_src, #Gui.left_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
for _, element_define in ipairs(flow_order) do
|
||||
-- Draw the element to the left flow
|
||||
local draw_success, left_element = xpcall(function()
|
||||
return element_define(left_flow)
|
||||
end, debug.traceback)
|
||||
|
||||
if not draw_success then
|
||||
log('There as been an error with an element draw function: '..element_define.defined_at..'\n\t'..left_element)
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- Check if it should be open by default
|
||||
local open_on_join = element_define.open_on_join
|
||||
local visible = type(open_on_join) == 'boolean' and open_on_join or false
|
||||
if type(open_on_join) == 'function' then
|
||||
local success, err = xpcall(open_on_join, debug.traceback, player)
|
||||
if not success then
|
||||
log('There as been an error with an open on join hander for a gui element:\n\t'..err)
|
||||
goto continue
|
||||
end
|
||||
visible = err
|
||||
end
|
||||
|
||||
-- Set the visible state of the element
|
||||
left_element.visible = visible
|
||||
show_hide_button = show_hide_button or visible
|
||||
|
||||
-- Check if the the element has a button attached
|
||||
if element_define.toolbar_button then
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, visible)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
||||
hide_button.visible = show_hide_button
|
||||
end
|
||||
|
||||
--- Reorder the left flow elements to match that returned by the provider, uses a method equivalent to insert sort
|
||||
function Gui.reorder_left_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_left_flow_order(player)
|
||||
if #flow_order ~= #Gui.left_elements then
|
||||
error(string.format("Left flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._left_flow_order_src, #Gui.left_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Reorder the elements, index 1 is the core ui buttons so +1 is required
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
local element = left_flow[element_define.name]
|
||||
left_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Update the visible state of the hide button, can be used to check if any frames are visible
|
||||
@tparam LuaPlayer player the player to update the left flow for
|
||||
@treturn boolean true if any left element is visible
|
||||
|
||||
@usage-- Check if any left elements are visible
|
||||
local visible = Gui.update_left_flow(player)
|
||||
|
||||
]]
|
||||
function Gui.update_left_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local hide_button = left_flow.gui_core_buttons[hide_left_flow]
|
||||
for _, element_define in ipairs(Gui.left_elements) do
|
||||
local left_element = left_flow[element_define.name]
|
||||
if left_element.visible then
|
||||
hide_button.visible = true
|
||||
return true
|
||||
end
|
||||
end
|
||||
hide_button.visible = false
|
||||
return false
|
||||
end
|
||||
|
||||
--[[-- Hides all left elements for a player
|
||||
@tparam LuaPlayer player the player to hide the elements for
|
||||
|
||||
@usage-- Hide your left elements
|
||||
Gui.hide_left_flow(game.player)
|
||||
|
||||
]]
|
||||
function Gui.hide_left_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local hide_button = left_flow.gui_core_buttons[hide_left_flow]
|
||||
|
||||
-- Set the visible state of all elements in the flow
|
||||
hide_button.visible = false
|
||||
for _, element_define in ipairs(Gui.left_elements) do
|
||||
left_flow[element_define.name].visible = false
|
||||
|
||||
-- Check if the the element has a toobar button attached
|
||||
if element_define.toolbar_button then
|
||||
-- Check if the topflow contains the button
|
||||
local button = top_flow[element_define.toolbar_button.name]
|
||||
if button then
|
||||
-- Style the button
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, false)
|
||||
-- Raise the custom event if all of the top checks have passed
|
||||
element_define.toolbar_button:raise_event{
|
||||
name = Gui.events.on_visibility_changed_by_click,
|
||||
element = button,
|
||||
state = false
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if an element is loaded, used internally when the normal left gui assumptions may not hold
|
||||
function Gui.left_flow_loaded(player, element_define)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
return left_flow[element_define.name] ~= nil
|
||||
end
|
||||
|
||||
--[[-- Get the element define that is in the left flow, use in events without an element refrence
|
||||
@tparam LuaPlayer player the player that you want to get the element for
|
||||
@tparam table element_define the element that you want to get
|
||||
@treturn LuaGuiElement the gui element linked to this define for this player
|
||||
|
||||
@usage-- Get your left element
|
||||
local frame = Gui.get_left_element(game.player, example_flow_with_button)
|
||||
|
||||
]]
|
||||
function Gui.get_left_element(player, element_define)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
return assert(left_flow[element_define.name], "Left element failed to load")
|
||||
end
|
||||
|
||||
--[[-- Toggles the visible state of a left element for a given player, can be used to set the visible state
|
||||
@tparam LuaPlayer player the player that you want to toggle the element for
|
||||
@tparam table element_define the element that you want to toggle
|
||||
@tparam[opt] boolean state with given will set the state, else state will be toggled
|
||||
@treturn boolean the new visible state of the element
|
||||
|
||||
@usage-- Toggle your example button
|
||||
Gui.toggle_top_flow(game.player, example_flow_with_button)
|
||||
|
||||
@usage-- Show your example button
|
||||
Gui.toggle_top_flow(game.player, example_flow_with_button, true)
|
||||
|
||||
]]
|
||||
function Gui.toggle_left_element(player, element_define, state)
|
||||
-- Set the visible state
|
||||
local element = Gui.get_left_element(player, element_define)
|
||||
if state == nil then state = not element.visible end
|
||||
element.visible = state
|
||||
Gui.update_left_flow(player)
|
||||
|
||||
-- Check if the the element has a button attached
|
||||
if element_define.toolbar_button then
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, state)
|
||||
end
|
||||
return state
|
||||
end
|
||||
412
exp_legacy/module/expcore/gui/prototype.lua
Normal file
412
exp_legacy/module/expcore/gui/prototype.lua
Normal file
@@ -0,0 +1,412 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Used to simplify gui creation using factory functions called element defines
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
|
||||
local Gui = {
|
||||
--- The current highest uid that is being used by a define, will not increase during runtime
|
||||
uid = 0,
|
||||
--- Used to automatically assign a unique static name to an element
|
||||
unique_static_name = {},
|
||||
--- String indexed table used to avoid conflict with custom event names, similar to how defines.events works
|
||||
events = {},
|
||||
--- Uid indexed array that stores all the factory functions that were defined, no new values will be added during runtime
|
||||
defines = {},
|
||||
--- An string indexed table of all the defines which are used by the core of the gui system, used for internal reference
|
||||
core_defines = {},
|
||||
--- Used to store the file names where elements were defined, this can be useful to find the uid of an element, mostly for debugging
|
||||
file_paths = {},
|
||||
--- Used to store extra information about elements as they get defined such as the params used and event handlers registered to them
|
||||
debug_info = {},
|
||||
--- The prototype used to store the functions of an element define
|
||||
_prototype_element = {},
|
||||
--- The prototype metatable applied to new element defines
|
||||
_mt_element = {}
|
||||
}
|
||||
|
||||
--- Allow access to the element prototype methods
|
||||
Gui._mt_element.__index = Gui._prototype_element
|
||||
|
||||
--- Allows the define to be called to draw the element
|
||||
function Gui._mt_element.__call(self, parent, ...)
|
||||
local element, no_events = self._draw(self, parent, ...)
|
||||
if self._style then self._style(element.style, element, ...) end
|
||||
|
||||
-- Asserts to catch common errors
|
||||
if element then
|
||||
if self.name and self.name ~= element.name then
|
||||
error("Static name \""..self.name.."\" expected but got: "..tostring(element.name))
|
||||
end
|
||||
local event_triggers = element.tags and element.tags.ExpGui_event_triggers
|
||||
if event_triggers and table.array_contains(event_triggers, self.uid) then
|
||||
error("Element::triggers_events should not be called on the value you return from the definition")
|
||||
end
|
||||
elseif self.name then
|
||||
error("Static name \""..self.name.."\" expected but no element was returned from the definition")
|
||||
end
|
||||
|
||||
-- Register events by default, but allow skipping them
|
||||
if no_events == self.no_events then
|
||||
return element
|
||||
else
|
||||
return element and self:triggers_events(element)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get where a function was defined as a string
|
||||
local function get_defined_at(level)
|
||||
local debug_info = debug.getinfo(level, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or ("<anonymous:"..debug_info.linedefined..">")
|
||||
return file_name..":"..func_name
|
||||
end
|
||||
|
||||
--- Element Define.
|
||||
-- @section elementDefine
|
||||
|
||||
--[[-- Used to define new elements for your gui, can be used like LuaGuiElement.add or a custom function
|
||||
@tparam ?table|function element_define the define information for the gui element, same data as LuaGuiElement.add, or a custom function may be used
|
||||
@treturn table the new element define, this can be considered a factory for the element which can be called to draw the element to any other element
|
||||
|
||||
@usage-- Using element defines like LuaGuiElement.add
|
||||
-- This returns a factory function to draw a button with the caption "Example Button"
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button'
|
||||
}
|
||||
|
||||
@usage-- Using element defines with a custom factory function
|
||||
-- This method can be used if you still want to be able register event handlers but it is too complex to be compatible with LuaGuiElement.add
|
||||
local example_flow_with_button =
|
||||
Gui.element(function(event_trigger, parent, ...)
|
||||
-- ... shows that all other arguments from the factory call are passed to this function
|
||||
-- parent is the element which was passed to the factory function where you should add your new element
|
||||
-- here we are adding a flow which we will then later add a button to
|
||||
local flow =
|
||||
parent.add{
|
||||
name = 'example_flow',
|
||||
type = 'flow'
|
||||
}
|
||||
|
||||
-- event_trigger should be the name of any elements you want to trigger your event handlers, such as on_click or on_state_changed
|
||||
-- now we add the button to the flow that we created earlier
|
||||
local element =
|
||||
flow.add{
|
||||
name = event_trigger,
|
||||
type = 'button',
|
||||
caption = 'Example Button'
|
||||
}
|
||||
|
||||
-- you must return your new element, this is so styles can be applied and returned to the caller
|
||||
-- you may return any of your elements that you add, consider the context in which it will be used for what should be returned
|
||||
return element
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui.element(element_define)
|
||||
_C.error_if_runtime()
|
||||
-- Set the metatable to allow access to register events
|
||||
local element = setmetatable({}, Gui._mt_element)
|
||||
|
||||
-- Increment the uid counter
|
||||
local uid = Gui.uid + 1
|
||||
Gui.uid = uid
|
||||
element.uid = uid
|
||||
Gui.debug_info[uid] = { draw = 'None', style = 'None', events = {} }
|
||||
|
||||
-- Add the definition function
|
||||
if type(element_define) == 'table' then
|
||||
Gui.debug_info[uid].draw = element_define
|
||||
if element_define.name == Gui.unique_static_name then
|
||||
element_define.name = "ExpGui_"..tostring(uid)
|
||||
end
|
||||
for k, v in pairs(element_define) do
|
||||
if element[k] == nil then
|
||||
element[k] = v
|
||||
end
|
||||
end
|
||||
element._draw = function(_, parent)
|
||||
return parent.add(element_define)
|
||||
end
|
||||
else
|
||||
Gui.debug_info[uid].draw = get_defined_at(element_define)
|
||||
element._draw = element_define
|
||||
end
|
||||
|
||||
-- Add the define to the base module
|
||||
element.defined_at = get_defined_at(3)
|
||||
Gui.file_paths[uid] = element.defined_at
|
||||
Gui.defines[uid] = element
|
||||
|
||||
-- Return the element so event handers can be accessed
|
||||
return element
|
||||
end
|
||||
|
||||
--[[-- Used to extent your element define with a style factory, this style will be applied to your element when created, can also be a custom function
|
||||
@tparam ?table|function style_define style table where each key and value pair is treated like LuaGuiElement.style[key] = value, a custom function can be used
|
||||
@treturn table the element define is returned to allow for event handlers to be registered
|
||||
|
||||
@usage-- Using the table method of setting the style
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button',
|
||||
style = 'forward_button' -- factorio styles can be applied here
|
||||
}
|
||||
:style{
|
||||
height = 25, -- same as element.style.height = 25
|
||||
width = 100 -- same as element.style.width = 25
|
||||
}
|
||||
|
||||
@usage-- Using the function method to set the style
|
||||
-- Use this method if your style is dynamic and depends on other factors
|
||||
local example_button =
|
||||
Gui.element{
|
||||
type = 'button',
|
||||
caption = 'Example Button',
|
||||
style = 'forward_button' -- factorio styles can be applied here
|
||||
}
|
||||
:style(function(style, element, ...)
|
||||
-- style is the current style object for the elemenent
|
||||
-- element is the element that is being changed
|
||||
-- ... shows that all other arguments from the factory call are passed to this function
|
||||
local player = game.players[element.player_index]
|
||||
style.height = 25
|
||||
style.width = 100
|
||||
style.font_color = player.color
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:style(style_define)
|
||||
_C.error_if_runtime()
|
||||
-- Add the definition function
|
||||
if type(style_define) == 'table' then
|
||||
Gui.debug_info[self.uid].style = style_define
|
||||
self._style = function(style)
|
||||
for key, value in pairs(style_define) do
|
||||
style[key] = value
|
||||
end
|
||||
end
|
||||
else
|
||||
Gui.debug_info[self.uid].style = get_defined_at(style_define)
|
||||
self._style = style_define
|
||||
end
|
||||
|
||||
-- Return the element so event handers can be accessed
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Enforce the fact the element has a static name, this is required for the cases when a function define is used
|
||||
@tparam[opt] string element The element that will trigger calls to the event handlers
|
||||
@treturn table the element define is returned to allow for event handlers to be registered
|
||||
]]
|
||||
function Gui._prototype_element:static_name(name)
|
||||
_C.error_if_runtime()
|
||||
if name == Gui.unique_static_name then
|
||||
self.name = "ExpGui_"..tostring(self.uid)
|
||||
else
|
||||
self.name = name
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Used to link an element to an element define such that any event on the element will call the handlers on the element define
|
||||
-- You should not call this on the element you return from your constructor because this is done automatically
|
||||
@tparam LuaGuiElement element The element that will trigger calls to the event handlers
|
||||
@treturn LuaGuiElement The element passed as the argument to allow for cleaner returns
|
||||
]]
|
||||
function Gui._prototype_element:triggers_events(element)
|
||||
if not self._has_events then return element end
|
||||
local tags = element.tags
|
||||
if not tags then
|
||||
element.tags = { ExpGui_event_triggers = { self.uid } }
|
||||
return element
|
||||
elseif not tags.ExpGui_event_triggers then
|
||||
tags.ExpGui_event_triggers = { self.uid }
|
||||
elseif table.array_contains(tags.ExpGui_event_triggers, self.uid) then
|
||||
error("Element::triggers_events called multiple times on the same element with the same definition")
|
||||
else
|
||||
table.insert(tags.ExpGui_event_triggers, self.uid)
|
||||
end
|
||||
-- To modify a set of tags, the whole table needs to be written back to the respective property.
|
||||
element.tags = tags
|
||||
return element
|
||||
end
|
||||
|
||||
--- Explicitly skip events on the element returned by your definition function
|
||||
function Gui._prototype_element:no_events(element)
|
||||
return element, self.no_events
|
||||
end
|
||||
|
||||
--[[-- Set the handler which will be called for a custom event, only one handler can be used per event per element
|
||||
@tparam string event_name the name of the event you want to handler to be called on, often from Gui.events
|
||||
@tparam function handler the handler that you want to be called when the event is raised
|
||||
@treturn table the element define so more handleres can be registered
|
||||
|
||||
@usage-- Register a handler to "my_custom_event" for this element
|
||||
element_deinfe:on_event('my_custom_event', function(event)
|
||||
event.player.print(player.name)
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:on_event(event_name, handler)
|
||||
_C.error_if_runtime()
|
||||
table.insert(Gui.debug_info[self.uid].events, event_name)
|
||||
Gui.events[event_name] = event_name
|
||||
self[event_name] = handler
|
||||
self._has_events = true
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Raise the handler which is attached to an event; external use should be limited to custom events
|
||||
@tparam table event the event table passed to the handler, must contain fields: name, element
|
||||
@treturn table the element define so more events can be raised
|
||||
|
||||
@usage Raising a custom event
|
||||
element_define:raise_event{
|
||||
name = 'my_custom_event',
|
||||
element = element
|
||||
}
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:raise_event(event)
|
||||
-- Check the element is valid
|
||||
local element = event.element
|
||||
if not element or not element.valid then
|
||||
return self
|
||||
end
|
||||
|
||||
-- Get the event handler for this element
|
||||
local handler = self[event.name]
|
||||
if not handler then
|
||||
return self
|
||||
end
|
||||
|
||||
-- Get the player for this event
|
||||
local player_index = event.player_index or element.player_index
|
||||
local player = game.players[player_index]
|
||||
if not player or not player.valid then
|
||||
return self
|
||||
end
|
||||
event.player = player
|
||||
|
||||
local success, err = xpcall(handler, debug.traceback, player, element, event)
|
||||
if not success then
|
||||
error('There as been an error with an event handler for a gui element:\n\t'..err)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
-- This function is used to link element define events and the events from the factorio api
|
||||
local function event_handler_factory(event_name)
|
||||
Event.add(event_name, function(event)
|
||||
local element = event.element
|
||||
if not element or not element.valid then return end
|
||||
local event_triggers = element.tags.ExpGui_event_triggers
|
||||
if not event_triggers then return end
|
||||
for _, uid in pairs(event_triggers) do
|
||||
local element_define = Gui.defines[uid]
|
||||
if element_define then
|
||||
element_define:raise_event(event)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.events[event_name] = event_name
|
||||
return function(self, handler)
|
||||
return self:on_event(event_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
--- Element Events.
|
||||
-- @section elementEvents
|
||||
|
||||
--- Called when the player opens a GUI.
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_open(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_open = event_handler_factory(defines.events.on_gui_opened)
|
||||
|
||||
--- Called when the player closes the GUI they have open.
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_close(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_close = event_handler_factory(defines.events.on_gui_closed)
|
||||
|
||||
--- Called when LuaGuiElement is clicked.
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_click(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_click = event_handler_factory(defines.events.on_gui_click)
|
||||
|
||||
--- Called when a LuaGuiElement is confirmed, for example by pressing Enter in a textfield.
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_confirmed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_confirmed = event_handler_factory(defines.events.on_gui_confirmed)
|
||||
|
||||
--- Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_checked_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_checked_changed = event_handler_factory(defines.events.on_gui_checked_state_changed)
|
||||
|
||||
--- Called when LuaGuiElement element value is changed (related to choose element buttons).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_elem_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_elem_changed = event_handler_factory(defines.events.on_gui_elem_changed)
|
||||
|
||||
--- Called when LuaGuiElement element location is changed (related to frames in player.gui.screen).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_location_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_location_changed = event_handler_factory(defines.events.on_gui_location_changed)
|
||||
|
||||
--- Called when LuaGuiElement selected tab is changed (related to tabbed-panes).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_tab_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_tab_changed = event_handler_factory(defines.events.on_gui_selected_tab_changed)
|
||||
|
||||
--- Called when LuaGuiElement selection state is changed (related to drop-downs and listboxes).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_selection_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_selection_changed = event_handler_factory(defines.events.on_gui_selection_state_changed)
|
||||
|
||||
--- Called when LuaGuiElement switch state is changed (related to switches).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_switch_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_switch_changed = event_handler_factory(defines.events.on_gui_switch_state_changed)
|
||||
|
||||
--- Called when LuaGuiElement text is changed by the player.
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_text_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_text_changed = event_handler_factory(defines.events.on_gui_text_changed)
|
||||
|
||||
--- Called when LuaGuiElement slider value is changed (related to the slider element).
|
||||
-- @tparam function handler the event handler which will be called
|
||||
-- @usage element_define:on_value_changed(function(event)
|
||||
-- event.player.print(table.inspect(event))
|
||||
--end)
|
||||
Gui._prototype_element.on_value_changed = event_handler_factory(defines.events.on_gui_value_changed)
|
||||
|
||||
-- Module return
|
||||
return Gui
|
||||
315
exp_legacy/module/expcore/gui/top_flow.lua
Normal file
315
exp_legacy/module/expcore/gui/top_flow.lua
Normal file
@@ -0,0 +1,315 @@
|
||||
--[[-- Core Module - Gui
|
||||
- Controls the elements on the top flow
|
||||
@module Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
|
||||
local toolbar_button_size = 36
|
||||
local hide_top_flow = Gui.core_defines.hide_top_flow.name
|
||||
local show_top_flow = Gui.core_defines.show_top_flow.name
|
||||
|
||||
--- Top Flow.
|
||||
-- @section topFlow
|
||||
|
||||
-- Triggered when a user changed the visibility of a left flow element by clicking a button
|
||||
Gui.events.on_toolbar_button_toggled = 'on_toolbar_button_toggled'
|
||||
|
||||
--- Contains the uids of the elements that will shown on the top flow and their auth functions
|
||||
-- @table top_elements
|
||||
Gui.top_elements = {}
|
||||
|
||||
--- The style that should be used for buttons on the top flow
|
||||
-- @field Gui.top_flow_button_style
|
||||
Gui.top_flow_button_style = mod_gui.button_style
|
||||
|
||||
--- The style that should be used for buttons on the top flow when their flow is visible
|
||||
-- @field Gui.top_flow_button_toggled_style
|
||||
Gui.top_flow_button_toggled_style = 'menu_button_continue'
|
||||
|
||||
--[[-- Styles a top flow button depending on the state given
|
||||
@tparam LuaGuiElement button the button element to style
|
||||
@tparam boolean state The state the button is in
|
||||
|
||||
@usage-- Sets the button to the visible style
|
||||
Gui.toolbar_button_style(button, true)
|
||||
|
||||
@usage-- Sets the button to the hidden style
|
||||
Gui.toolbar_button_style(button, false)
|
||||
|
||||
]]
|
||||
function Gui.toolbar_button_style(button, state, size)
|
||||
---@cast button LuaGuiElement
|
||||
if state then
|
||||
button.style = Gui.top_flow_button_toggled_style
|
||||
else
|
||||
button.style = Gui.top_flow_button_style
|
||||
end
|
||||
button.style.minimal_width = size or toolbar_button_size
|
||||
button.style.height = size or toolbar_button_size
|
||||
button.style.padding = -2
|
||||
end
|
||||
|
||||
--[[-- Gets the flow refered to as the top flow, each player has one top flow
|
||||
@function Gui.get_top_flow(player)
|
||||
@tparam LuaPlayer player the player that you want to get the flow for
|
||||
@treturn LuaGuiElement the top element flow
|
||||
|
||||
@usage-- Geting your top flow
|
||||
local top_flow = Gui.get_top_flow(game.player)
|
||||
|
||||
]]
|
||||
Gui.get_top_flow = mod_gui.get_button_flow
|
||||
|
||||
--[[-- Sets an element define to be drawn to the top flow when a player joins, includes optional authenticator
|
||||
@tparam[opt] function authenticator called during toggle or update to decide weather the element should be visible
|
||||
@treturn table the new element define to allow event handlers to be registered
|
||||
|
||||
@usage-- Adding an element to the top flow on join
|
||||
example_button:add_to_top_flow(function(player)
|
||||
-- example button will only be shown if the player is an admin
|
||||
-- note button will not update its state when player.admin is changed Gui.update_top_flow must be called for this
|
||||
return player.admin
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:add_to_top_flow(authenticator)
|
||||
_C.error_if_runtime()
|
||||
if not self.name then error("Elements for the top flow must have a static name") end
|
||||
self.authenticator = authenticator or true
|
||||
table.insert(Gui.top_elements, self)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns true if the top flow has visible elements
|
||||
function Gui.top_flow_has_visible_elements(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
for _, child in pairs(top_flow.children) do
|
||||
if child.name ~= hide_top_flow then
|
||||
if child.visible then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
Gui._top_flow_order_src = "<default>"
|
||||
--- Get the order of elements in the top flow, first argument is player but is unused in the default method
|
||||
function Gui.get_top_flow_order(_)
|
||||
return Gui.top_elements
|
||||
end
|
||||
|
||||
--- Inject a custom top flow order provider, this should accept a player and return a list of elements definitions to draw
|
||||
function Gui.inject_top_flow_order(provider)
|
||||
Gui.get_top_flow_order = provider
|
||||
local debug_info = debug.getinfo(2, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or ("<anonymous:"..debug_info.linedefined..">")
|
||||
Gui._top_flow_order_src = file_name..":"..func_name
|
||||
end
|
||||
|
||||
--[[-- Updates the visible state of all the elements on the players top flow, uses authenticator
|
||||
@tparam LuaPlayer player the player that you want to update the top flow for
|
||||
|
||||
@usage-- Update your top flow
|
||||
Gui.update_top_flow(game.player)
|
||||
|
||||
]]
|
||||
function Gui.update_top_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_top_flow_order(player)
|
||||
if #flow_order ~= #Gui.top_elements then
|
||||
error(string.format("Top flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._top_flow_order_src, #Gui.top_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Set the visible state of all elements in the flow
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
-- Ensure the element exists
|
||||
local element = top_flow[element_define.name]
|
||||
if not element then
|
||||
element = element_define(top_flow)
|
||||
else
|
||||
top_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
|
||||
-- Set the visible state
|
||||
local allowed = element_define.authenticator
|
||||
if type(allowed) == 'function' then allowed = allowed(player) end
|
||||
element.visible = allowed or false
|
||||
|
||||
-- If its not visible and there is a left element, then hide it
|
||||
if element_define.left_flow_element and not element.visible and Gui.left_flow_loaded(player, element_define.left_flow_element) then
|
||||
Gui.toggle_left_element(player, element_define.left_flow_element, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if there are any visible elements in the top flow
|
||||
if not Gui.top_flow_has_visible_elements(player) then
|
||||
-- None are visible so hide the top_flow and its show button
|
||||
Gui.toggle_top_flow(player, false)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local show_button = left_flow.gui_core_buttons[show_top_flow]
|
||||
show_button.visible = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Reorder the top flow elements to match that returned by the provider, uses a method equivalent to insert sort
|
||||
function Gui.reorder_top_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_top_flow_order(player)
|
||||
if #flow_order ~= #Gui.top_elements then
|
||||
error(string.format("Top flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._top_flow_order_src, #Gui.top_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Reorder the elements, index 1 is the core ui buttons so +1 is required
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
local element = top_flow[element_define.name]
|
||||
top_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Toggles the visible state of all the elements on a players top flow, effects all elements
|
||||
@tparam LuaPlayer player the player that you want to toggle the top flow for
|
||||
@tparam[opt] boolean state if given then the state will be set to this
|
||||
@treturn boolean the new visible state of the top flow
|
||||
|
||||
@usage-- Toggle your flow
|
||||
Gui.toggle_top_flow(game.player)
|
||||
|
||||
@usage-- Open your top flow
|
||||
Gui.toggle_top_flow(game.player, true)
|
||||
|
||||
]]
|
||||
function Gui.toggle_top_flow(player, state)
|
||||
-- Get the top flow, we need the parent as we want to toggle the outer frame
|
||||
local top_flow = Gui.get_top_flow(player).parent
|
||||
if state == nil then state = not top_flow.visible end
|
||||
|
||||
-- Get the show button for the top flow
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local show_button = left_flow.gui_core_buttons[show_top_flow]
|
||||
|
||||
-- Change the visibility of the top flow and show top flow button
|
||||
show_button.visible = not state
|
||||
top_flow.visible = state
|
||||
|
||||
return state
|
||||
end
|
||||
|
||||
--[[-- Get the element define that is in the top flow, use in events without an element refrence
|
||||
@tparam LuaPlayer player the player that you want to get the element for
|
||||
@tparam table element_define the element that you want to get
|
||||
@treturn LuaGuiElement the gui element linked to this define for this player
|
||||
|
||||
@usage-- Get your top element
|
||||
local button = Gui.get_top_element(game.player, example_button)
|
||||
|
||||
]]
|
||||
function Gui.get_top_element(player, element_define)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
return assert(top_flow[element_define.name], "Top element failed to load")
|
||||
end
|
||||
|
||||
--[[-- Toggles the state of a toolbar button for a given player, can be used to set the visual state
|
||||
@tparam LuaPlayer player the player that you want to toggle the element for
|
||||
@tparam table element_define the element that you want to toggle
|
||||
@tparam[opt] boolean state with given will set the state, else state will be toggled
|
||||
@treturn boolean the new visible state of the element
|
||||
|
||||
@usage-- Toggle your example button
|
||||
Gui.toggle_toolbar_button(game.player, toolbar_button)
|
||||
|
||||
@usage-- Show your example button
|
||||
Gui.toggle_toolbar_button(game.player, toolbar_button, true)
|
||||
|
||||
]]
|
||||
function Gui.toggle_toolbar_button(player, element_define, state)
|
||||
local toolbar_button = Gui.get_top_element(player, element_define)
|
||||
if state == nil then state = toolbar_button.style.name ~= Gui.top_flow_button_toggled_style end
|
||||
Gui.toolbar_button_style(toolbar_button, state, toolbar_button.style.minimal_width)
|
||||
element_define:raise_event{
|
||||
name = Gui.events.on_toolbar_button_toggled,
|
||||
element = toolbar_button,
|
||||
player = player,
|
||||
state = state
|
||||
}
|
||||
return state
|
||||
end
|
||||
|
||||
--[[-- Creates a button on the top flow with consistent styling
|
||||
@tparam string sprite the sprite that you want to use on the button
|
||||
@tparam ?string|Concepts.LocalizedString tooltip the tooltip that you want the button to have
|
||||
@tparam[opt] function authenticator used to decide if the button should be visible to a player
|
||||
|
||||
@usage-- Add a button to the toolbar
|
||||
local toolbar_button =
|
||||
Gui.left_toolbar_button('entity/inserter', 'Nothing to see here', function(player)
|
||||
return player.admin
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui.toolbar_button(sprite, tooltip, authenticator)
|
||||
return Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = sprite,
|
||||
tooltip = tooltip,
|
||||
style = Gui.top_flow_button_style,
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
minimal_width = toolbar_button_size,
|
||||
height = toolbar_button_size,
|
||||
padding = -2
|
||||
}
|
||||
:add_to_top_flow(authenticator)
|
||||
end
|
||||
|
||||
--[[-- Creates a toggle button on the top flow with consistent styling
|
||||
@tparam string sprite the sprite that you want to use on the button
|
||||
@tparam ?string|Concepts.LocalizedString tooltip the tooltip that you want the button to have
|
||||
@tparam[opt] function authenticator used to decide if the button should be visible to a player
|
||||
|
||||
@usage-- Add a button to the toolbar
|
||||
local toolbar_button =
|
||||
Gui.toolbar_toggle_button('entity/inserter', 'Nothing to see here', function(player)
|
||||
return player.admin
|
||||
end)
|
||||
:on_event(Gui.events.on_toolbar_button_toggled, function(player, element, event)
|
||||
game.print(table.inspect(event))
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui.toolbar_toggle_button(sprite, tooltip, authenticator)
|
||||
local button =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = sprite,
|
||||
tooltip = tooltip,
|
||||
style = Gui.top_flow_button_style,
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
minimal_width = toolbar_button_size,
|
||||
height = toolbar_button_size,
|
||||
padding = -2
|
||||
}
|
||||
:add_to_top_flow(authenticator)
|
||||
|
||||
button:on_click(function(player, _, _)
|
||||
Gui.toggle_toolbar_button(player, button)
|
||||
end)
|
||||
|
||||
return button
|
||||
end
|
||||
358
exp_legacy/module/expcore/permission_groups.lua
Normal file
358
exp_legacy/module/expcore/permission_groups.lua
Normal file
@@ -0,0 +1,358 @@
|
||||
--[[-- Core Module - Permission Groups
|
||||
- Permission group making for factorio so you never have to make one by hand again
|
||||
@core Groups
|
||||
@alias Permissions_Groups
|
||||
|
||||
@usage--- Example Group (Allow All)
|
||||
-- here we will create an admin group however we do not want them to use the map editor or mess with the permission groups
|
||||
Permission_Groups.new_group('Admin') -- this defines a new group called "Admin"
|
||||
:allow_all() -- this makes the default to allow any input action unless set other wise
|
||||
:disallow{ -- here we disallow the input action we don't want them to use
|
||||
'add_permission_group',
|
||||
'delete_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor'
|
||||
}
|
||||
|
||||
@usage--- Example Group (Disallow All)
|
||||
-- here we will create a group that cant do anything but talk in chat
|
||||
Permission_Groups.new_group('Restricted') -- this defines a new group called "Restricted"
|
||||
:disallow_all() -- this makes the default to disallow any input action unless set other wise
|
||||
:allow('write_to_console') -- here we allow them to chat, {} can be used here if we had more than one action
|
||||
|
||||
]]
|
||||
|
||||
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Async = require 'expcore.async' --- @dep expcore.async
|
||||
|
||||
local Permissions_Groups = {
|
||||
groups={}, -- store for the different groups that are created
|
||||
_prototype={} -- stores functions that are used on group instances
|
||||
}
|
||||
|
||||
-- Async function to add players to permission groups
|
||||
local add_to_permission_group =
|
||||
Async.register(function(permission_group, player)
|
||||
permission_group.add_player(player)
|
||||
end)
|
||||
Permissions_Groups.async_token_add_to_permission_group = add_to_permission_group
|
||||
|
||||
-- Async function to remove players from permission groups
|
||||
local remove_from_permission_group =
|
||||
Async.register(function(permission_group, player)
|
||||
permission_group.remove_player(player)
|
||||
end)
|
||||
Permissions_Groups.async_token_remove_from_permission_group = remove_from_permission_group
|
||||
|
||||
--- Getters.
|
||||
-- Functions that get permission groups
|
||||
-- @section getters
|
||||
|
||||
--[[-- Defines a new permission group that can have it actions set in the config
|
||||
@tparam string name the name of the new group
|
||||
@treturn Permissions_Groups._prototype the new group made with function to allow and disallow actions
|
||||
|
||||
@usage-- Defining a new permission group
|
||||
Groups.new_group('Admin')
|
||||
|
||||
]]
|
||||
function Permissions_Groups.new_group(name)
|
||||
local group = setmetatable({
|
||||
name=name,
|
||||
actions={},
|
||||
allow_all_actions=true
|
||||
}, {
|
||||
__index= Permissions_Groups._prototype
|
||||
})
|
||||
Permissions_Groups.groups[name] = group
|
||||
return group
|
||||
end
|
||||
|
||||
--[[-- Returns the group with the given name, case sensitive
|
||||
@tparam string name the name of the group to get
|
||||
@treturn ?Permissions_Groups._prototype|nil the group with that name or nil if non found
|
||||
|
||||
@usage-- Getting a permision group
|
||||
local admin_group = Groups.get_group_by_name('Admin')
|
||||
|
||||
]]
|
||||
function Permissions_Groups.get_group_by_name(name)
|
||||
return Permissions_Groups.groups[name]
|
||||
end
|
||||
|
||||
--[[-- Returns the group that a player is in
|
||||
@tparam LuaPlayer player the player to get the group of can be name index etc
|
||||
@treturn ?Permissions_Groups._prototype|nil the group with that player or nil if non found
|
||||
|
||||
@usage-- Get your permission group
|
||||
local group = Groups.get_group_from_player(game.player)
|
||||
|
||||
]]
|
||||
function Permissions_Groups.get_group_from_player(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player then return end
|
||||
local group = player.permission_group
|
||||
if group then
|
||||
return Permissions_Groups.groups[group.name]
|
||||
end
|
||||
end
|
||||
|
||||
--- Setters.
|
||||
-- Functions that control all groups
|
||||
-- @section players
|
||||
|
||||
--[[-- Reloads/creates all permission groups and sets them to they configured state
|
||||
|
||||
@usage-- Reload the permission groups, used internally
|
||||
Groups.reload_permissions()
|
||||
|
||||
]]
|
||||
function Permissions_Groups.reload_permissions()
|
||||
for _, group in pairs(Permissions_Groups.groups) do
|
||||
group:create()
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Sets a player's group to the one given, a player can only have one group at a time
|
||||
@tparam LuaPlayer player the player to effect can be name index etc
|
||||
@tparam string group the name of the group to give to the player
|
||||
@treturn boolean true if the player was added successfully, false other wise
|
||||
|
||||
@usage-- Set your permission group
|
||||
Groups.set_player_group(game.player, 'Admin')
|
||||
|
||||
]]
|
||||
function Permissions_Groups.set_player_group(player, group)
|
||||
player = Game.get_player_from_any(player)
|
||||
group = Permissions_Groups.get_group_by_name(group)
|
||||
if not group or not player then return false end
|
||||
group:add_player(player)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Actions.
|
||||
-- Functions that control group actions
|
||||
-- @section actions
|
||||
|
||||
--[[-- Sets the allow state of an action for this group, used internally but is safe to use else where
|
||||
@tparam ?string|defines.input_action action the action that you want to set the state of
|
||||
@tparam boolean state the state that you want to set it to, true = allow, false = disallow
|
||||
@treturn Permissions_Groups._prototype returns self so function can be chained
|
||||
|
||||
@usage-- Set an action to be disallowed
|
||||
group:set_action('toggle_map_editor', false)
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:set_action(action, state)
|
||||
local input_action = defines.input_action[action]
|
||||
if input_action == nil then input_action = action end
|
||||
assert(type(input_action) == 'number', tostring(action)..' is not a valid input action')
|
||||
self.actions[input_action] = state
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Sets an action or actions to be allowed for this group even with disallow_all triggered, Do not use in runtime
|
||||
@tparam string|Array<string> actions the action or actions that you want to allow for this group
|
||||
@treturn Permissions_Groups._prototype returns self so function can be chained
|
||||
|
||||
@usage-- Allow some actions
|
||||
group:allow{
|
||||
'write_to_console'
|
||||
}
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:allow(actions)
|
||||
if type(actions) ~= 'table' then
|
||||
actions = {actions}
|
||||
end
|
||||
for _, action in pairs(actions) do
|
||||
self:set_action(action, true)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Sets an action or actions to be disallowed for this group even with allow_all triggered, Do not use in runtime
|
||||
@tparam string|Array<string> actions the action or actions that you want to disallow for this group
|
||||
@treturn Permissions_Groups._prototype returns self so function can be chained
|
||||
|
||||
@usage-- Disalow some actions
|
||||
group:disallow{
|
||||
'add_permission_group',
|
||||
'delete_permission_group',
|
||||
'import_permissions_string',
|
||||
'map_editor_action',
|
||||
'toggle_map_editor'
|
||||
}
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:disallow(actions)
|
||||
if type(actions) ~= 'table' then
|
||||
actions = {actions}
|
||||
end
|
||||
for _, action in pairs(actions) do
|
||||
self:set_action(action, false)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Sets the default state for any actions not given to be allowed, useful with :disallow
|
||||
@treturn Permissions_Groups._prototype returns self so function can be chained
|
||||
|
||||
@usage-- Allow all actions unless given by disallow
|
||||
group:allow_all()
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:allow_all()
|
||||
self.allow_all_actions = true
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Sets the default state for any action not given to be disallowed, useful with :allow
|
||||
@treturn Permissions_Groups._prototype returns self so function can be chained
|
||||
|
||||
@usage-- Disallow all actions unless given by allow
|
||||
group:disallow_all()
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:disallow_all()
|
||||
self.allow_all_actions = false
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Returns if an input action is allowed for this group
|
||||
@tparam ?string|defines.input_action action the action that you want to test for
|
||||
@treturn boolean true if the group is allowed the action, false other wise
|
||||
|
||||
@usage-- Test if a group is allowed an action
|
||||
local allowed = group:is_allowed('write_to_console')
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:is_allowed(action)
|
||||
if type(action) == 'string' then
|
||||
action = defines.input_action[action]
|
||||
end
|
||||
local state = self.actions[action]
|
||||
if state == nil then
|
||||
state = self.allow_all_actions
|
||||
end
|
||||
return state
|
||||
end
|
||||
|
||||
--- Players.
|
||||
-- Functions that control group players
|
||||
-- @section players
|
||||
|
||||
--[[-- Creates or updates the permission group with the configured actions, used internally
|
||||
@treturn LuaPermissionGroup the permission group that was created
|
||||
|
||||
@usage-- Create the permission group so players can be added, used internally
|
||||
group:create()
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:create()
|
||||
local group = self:get_raw()
|
||||
if not group then
|
||||
group = game.permissions.create_group(self.name)
|
||||
end
|
||||
for _, action in pairs(defines.input_action) do
|
||||
group.set_allows_action(action, self:is_allowed(action))
|
||||
end
|
||||
return group
|
||||
end
|
||||
|
||||
--[[-- Returns the LuaPermissionGroup that was created with this group object, used internally
|
||||
@treturn LuaPermissionGroup the raw lua permission group
|
||||
|
||||
@usage-- Get the factorio api permision group, used internally
|
||||
local permission_group = group:get_raw()
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:get_raw()
|
||||
return game.permissions.get_group(self.name)
|
||||
end
|
||||
|
||||
--[[-- Adds a player to this group
|
||||
@tparam LuaPlayer player LuaPlayer the player you want to add to this group can be name or index etc
|
||||
@treturn boolean true if the player was added successfully, false other wise
|
||||
|
||||
@usage-- Add a player to this permission group
|
||||
group:add_player(game.player)
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:add_player(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local group = self:get_raw()
|
||||
if not group or not player then return false end
|
||||
Async(add_to_permission_group, group, player)
|
||||
return true
|
||||
end
|
||||
|
||||
--[[-- Removes a player from this group
|
||||
@tparam LuaPlayer player LuaPlayer the player you want to remove from this group can be name or index etc
|
||||
@treturn boolean true if the player was removed successfully, false other wise
|
||||
|
||||
@usage-- Remove a player from this permission group
|
||||
group:remove_player(game.player)
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:remove_player(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local group = self:get_raw()
|
||||
if not group or not player then return false end
|
||||
Async(remove_from_permission_group, group, player)
|
||||
return true
|
||||
end
|
||||
|
||||
--[[-- Returns all player that are in this group with the option to filter to online/offline only
|
||||
@tparam[opt] boolean online if nil returns all players, if true online players only, if false returns online players only
|
||||
@treturn table a table of players that are in this group; filtered if online param is given
|
||||
|
||||
@usage-- Get all players in this group
|
||||
local online_players = group:get_players()
|
||||
|
||||
@usage-- Get all online players in this group
|
||||
local online_players = group:get_players(true)
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:get_players(online)
|
||||
local players = {}
|
||||
local group = self:get_raw()
|
||||
if group then
|
||||
if online == nil then
|
||||
return group.players
|
||||
else
|
||||
for _, player in pairs(group.players) do
|
||||
if player.connected == online then
|
||||
table.insert(player, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return players
|
||||
end
|
||||
|
||||
--[[-- Prints a message to every player in this group
|
||||
@tparam string message the message that you want to send to the players
|
||||
@treturn number the number of players that received the message
|
||||
|
||||
@usage-- Print a message to all players in thie group
|
||||
group:print('Hello, World!')
|
||||
|
||||
]]
|
||||
function Permissions_Groups._prototype:print(message)
|
||||
local players = self:get_players(true)
|
||||
for _, player in pairs(players) do
|
||||
player.print(message)
|
||||
end
|
||||
return #players
|
||||
end
|
||||
|
||||
-- when the game starts it will make the permission groups
|
||||
Event.on_init(function()
|
||||
Permissions_Groups.reload_permissions()
|
||||
end)
|
||||
|
||||
return Permissions_Groups
|
||||
152
exp_legacy/module/expcore/player_data.lua
Normal file
152
exp_legacy/module/expcore/player_data.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
--[[-- Core Module - PlayerData
|
||||
- A module used to store player data in a central datastore to minimize data requests and saves.
|
||||
@core PlayerData
|
||||
|
||||
@usage-- Adding a colour setting for players
|
||||
local PlayerData = require 'expcore.player_data'
|
||||
local PlayerColors = PlayerData.Settings:combine('Color')
|
||||
|
||||
-- Set the players color when their data is loaded
|
||||
PlayerColors:on_load(function(player_name, color)
|
||||
local player = game.players[player_name]
|
||||
player.color = color
|
||||
end)
|
||||
|
||||
-- Overwrite the saved color with the players current color
|
||||
PlayerColors:on_save(function(player_name, _)
|
||||
local player = game.players[player_name]
|
||||
return player.color -- overwrite existing data with the current color
|
||||
end)
|
||||
|
||||
@usage-- Add a playtime statistic for players
|
||||
local Event = require 'utils.event'
|
||||
local PlayerData = require 'expcore.player_data'
|
||||
local Playtime = PlayerData.Statistics:combine('Playtime')
|
||||
|
||||
-- When playtime reaches an hour interval tell the player and say thanks
|
||||
Playtime:on_update(function(player_name, playtime)
|
||||
if playtime % 60 == 0 then
|
||||
local hours = playtime / 60
|
||||
local player = game.players[player_name]
|
||||
player.print('Thanks for playing on our servers, you have played for '..hours..' hours!')
|
||||
end
|
||||
end)
|
||||
|
||||
-- Update playtime for players, data is only loaded for online players so update_all can be used
|
||||
Event.add_on_nth_tick(3600, function()
|
||||
Playtime:update_all(function(player_name, playtime)
|
||||
return playtime + 1
|
||||
end)
|
||||
end)
|
||||
|
||||
]]
|
||||
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Async = require 'expcore.async' --- @dep expcore.async
|
||||
local Datastore = require 'expcore.datastore' --- @dep expcore.datastore
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
require 'config.expcore.command_general_parse' --- @dep config.expcore.command_general_parse
|
||||
|
||||
--- Common player data that acts as the root store for player data
|
||||
local PlayerData = Datastore.connect('PlayerData', true) -- saveToDisk
|
||||
PlayerData:set_serializer(Datastore.name_serializer) -- use player name
|
||||
|
||||
--- Store and enum for the data saving preference
|
||||
local DataSavingPreference = PlayerData:combine('DataSavingPreference')
|
||||
local PreferenceEnum = { 'All', 'Statistics', 'Settings', 'Required' }
|
||||
for k,v in ipairs(PreferenceEnum) do PreferenceEnum[v] = k end
|
||||
DataSavingPreference:set_default('All')
|
||||
DataSavingPreference:set_metadata{
|
||||
name = {'expcore-data.preference'},
|
||||
tooltip = {'expcore-data.preference-tooltip'},
|
||||
value_tooltip ={'expcore-data.preference-value-tooltip'}
|
||||
}
|
||||
|
||||
--- Sets your data saving preference
|
||||
-- @command set-data-preference
|
||||
Commands.new_command('set-preference', 'Allows you to set your data saving preference')
|
||||
:add_param('option', false, 'string-options', PreferenceEnum)
|
||||
:register(function(player, option)
|
||||
DataSavingPreference:set(player, option)
|
||||
return {'expcore-data.set-preference', option}
|
||||
end)
|
||||
|
||||
--- Gets your data saving preference
|
||||
-- @command data-preference
|
||||
Commands.new_command('preference', 'Shows you what your current data saving preference is')
|
||||
:register(function(player)
|
||||
return {'expcore-data.get-preference', DataSavingPreference:get(player)}
|
||||
end)
|
||||
|
||||
--- Gets your data and writes it to a file
|
||||
Commands.new_command('save-data', 'Writes all your player data to a file on your computer')
|
||||
:register(function(player)
|
||||
player.print{'expcore-data.get-data'}
|
||||
game.write_file('expgaming_player_data.json', game.table_to_json(PlayerData:get(player, {})), false, player.index)
|
||||
end)
|
||||
|
||||
--- Async function called after 5 seconds with no player data loaded
|
||||
local check_data_loaded = Async.register(function(player)
|
||||
local player_data = PlayerData:get(player)
|
||||
if not player_data or not player_data.valid then
|
||||
player.print{'expcore-data.data-failed'}
|
||||
Datastore.ingest('request', 'PlayerData', player.name, '{"valid":false}')
|
||||
end
|
||||
end)
|
||||
|
||||
--- When player data loads tell the player if the load had failed previously
|
||||
PlayerData:on_load(function(player_name, player_data, existing_data)
|
||||
if not player_data or player_data.valid == false then return end
|
||||
if existing_data and existing_data.valid == false then
|
||||
game.players[player_name].print{'expcore-data.data-restore'}
|
||||
end
|
||||
player_data.valid = true
|
||||
end)
|
||||
|
||||
--- Remove data that the player doesnt want to have stored
|
||||
PlayerData:on_save(function(player_name, player_data)
|
||||
local dataPreference = DataSavingPreference:get(player_name)
|
||||
dataPreference = PreferenceEnum[dataPreference]
|
||||
if dataPreference == PreferenceEnum.All then
|
||||
player_data.valid = nil
|
||||
return player_data
|
||||
end
|
||||
|
||||
local saved_player_data = { PlayerRequired = player_data.PlayerRequired, DataSavingPreference = PreferenceEnum[dataPreference] }
|
||||
if dataPreference <= PreferenceEnum.Settings then saved_player_data.PlayerSettings = player_data.PlayerSettings end
|
||||
if dataPreference <= PreferenceEnum.Statistics then saved_player_data.PlayerStatistics = player_data.PlayerStatistics end
|
||||
|
||||
return saved_player_data
|
||||
end)
|
||||
|
||||
--- Display your data preference when your data loads
|
||||
DataSavingPreference:on_load(function(player_name, dataPreference)
|
||||
game.players[player_name].print{'expcore-data.get-preference', dataPreference or DataSavingPreference.default}
|
||||
end)
|
||||
|
||||
--- Load player data when they join
|
||||
Event.add(defines.events.on_player_joined_game, function(event)
|
||||
local player = game.players[event.player_index]
|
||||
Async.wait(300, check_data_loaded, player)
|
||||
PlayerData:raw_set(player.name)
|
||||
PlayerData:request(player)
|
||||
end)
|
||||
|
||||
--- Unload player data when they leave
|
||||
Event.add(defines.events.on_player_left_game, function(event)
|
||||
local player = game.players[event.player_index]
|
||||
local player_data = PlayerData:get(player)
|
||||
if player_data and player_data.valid == true then
|
||||
PlayerData:unload(player)
|
||||
else PlayerData:raw_set(player.name) end
|
||||
end)
|
||||
|
||||
----- Module Return -----
|
||||
return {
|
||||
All = PlayerData, -- Root for all of a players data
|
||||
Statistics = PlayerData:combine('Statistics'), -- Common place for stats
|
||||
Settings = PlayerData:combine('Settings'), -- Common place for settings
|
||||
Required = PlayerData:combine('Required'), -- Common place for required data
|
||||
DataSavingPreference = DataSavingPreference, -- Stores what data groups will be saved
|
||||
PreferenceEnum = PreferenceEnum -- Enum for the allowed options for data saving preference
|
||||
}
|
||||
1142
exp_legacy/module/expcore/roles.lua
Normal file
1142
exp_legacy/module/expcore/roles.lua
Normal file
File diff suppressed because it is too large
Load Diff
2
exp_legacy/module/locale/af/language.cfg
Normal file
2
exp_legacy/module/locale/af/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Afrikaans
|
||||
2
exp_legacy/module/locale/ar/language.cfg
Normal file
2
exp_legacy/module/locale/ar/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Arabic
|
||||
2
exp_legacy/module/locale/be/language.cfg
Normal file
2
exp_legacy/module/locale/be/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Belarusian
|
||||
2
exp_legacy/module/locale/bg/language.cfg
Normal file
2
exp_legacy/module/locale/bg/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Bulgarian
|
||||
2
exp_legacy/module/locale/ca/language.cfg
Normal file
2
exp_legacy/module/locale/ca/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Catalan
|
||||
2
exp_legacy/module/locale/cs/language.cfg
Normal file
2
exp_legacy/module/locale/cs/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Czech
|
||||
2
exp_legacy/module/locale/da/language.cfg
Normal file
2
exp_legacy/module/locale/da/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Danish
|
||||
2
exp_legacy/module/locale/de/language.cfg
Normal file
2
exp_legacy/module/locale/de/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=German
|
||||
2
exp_legacy/module/locale/el/language.cfg
Normal file
2
exp_legacy/module/locale/el/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Greek
|
||||
95
exp_legacy/module/locale/en/addons.cfg
Normal file
95
exp_legacy/module/locale/en/addons.cfg
Normal file
@@ -0,0 +1,95 @@
|
||||
[chat-popup]
|
||||
message=__1__: __2__
|
||||
ping=You have been mentioned in chat by __1__.
|
||||
|
||||
[damage-popup]
|
||||
player-health=__1__
|
||||
player-damage=__1__
|
||||
|
||||
[links]
|
||||
discord=https://discord.explosivegaming.nl
|
||||
website=https://www.explosivegaming.nl
|
||||
status=https://status.explosivegaming.nl
|
||||
github=https://github.com/explosivegaming/scenario
|
||||
patreon=https://www.patreon.com/ExpGaming
|
||||
|
||||
[info]
|
||||
players-online=There are __1__ players online
|
||||
total-map-time=This map has been on for __1__
|
||||
discord=Join us on our discord at: https://discord.explosivegaming.nl
|
||||
website=Please visit our website at: https://www.explosivegaming.nl
|
||||
status=Want to check if out servers are down? Visit: https://status.explosivegaming.nl
|
||||
github=Want to help improve our server with some extra features? Help us at: https://github.com/explosivegaming/scenario
|
||||
patreon=Consider supporting our server at: https://www.patreon.com/ExpGaming
|
||||
custom-commands=We use custom commands, such as /tag and /me, use /chelp for more info.
|
||||
read-readme=Make sure you have read the information gui (It can be found through the info mark on the top left)
|
||||
softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list.
|
||||
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
|
||||
lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this.
|
||||
|
||||
[warnings]
|
||||
received=You received a warning from __1__. You have __2__ warnings. __3__
|
||||
pre-kick=This is your last warning before you are kicked.
|
||||
kick=You were kicked for having too many warnings; you may rejoin if you wish.
|
||||
pre-pre-ban=You are close to receiving a ban; successful ban appeals are unlikely.
|
||||
pre-ban=This your LAST warning before you are BANNED! Successful ban appeals are unlikely.
|
||||
ban=You were banned for having too many warnings; visit __1__ to request a ban appeal.
|
||||
script-warning=You are receiving script warnings; if you recive too many you will receive a permanent warning (__1__/__2__)
|
||||
script-warning-removed=A script warning has expired (__1__/__2__)
|
||||
script-warning-limit=__1__ has received a permanent warning from the script.
|
||||
|
||||
[chat-bot]
|
||||
reply=[Chat Bot] __1__
|
||||
disallow=You can't use global chat commands
|
||||
players-online=There are __1__ players online
|
||||
players=There have been __1__ players on this map
|
||||
not-real-dev=Cooldude2606 is a dev for this server and makes the softmod and is not a factorio dev.
|
||||
softmod=A softmod is a custom scenario that runs on this server,an example is the player list.
|
||||
blame=Blame __1__ for what just happened!
|
||||
afk=You're afk? Look at __1__, that player has been afk for: __2__
|
||||
current-evolution=Current evolution factor is __1__
|
||||
magic=Fear the admin magic (ノ゚∀゚)ノ⌒・*:.。. .。.:*・゜゚・*☆
|
||||
aids=≖ ‿ ≖ Fear the aids of a public server ≖ ‿ ≖
|
||||
riot=(admins) ┬┴┬┴┤ᵒ_ᵒ)├┬┴┬┴ ‹ ‹\(´ω` )/››‹‹\ ( ´)/››‹‹\ ( ´ω`)/›› (rest of server)
|
||||
loops=NO LOOPS; LOOPS ARE BAD; JUST NO LOOPS!!!!!; IF YOU MAKE A LOOP.... IT WILL NOT END WELL!!!!!!!
|
||||
lenny=( ͡° ͜ʖ ͡°)
|
||||
hodor=Hodor
|
||||
get-popcorn-1=Heating the oil and waiting for the popping sound...
|
||||
get-popcorn-2=__1__ your popcorn is finished. Lean backwards and watch the drama unfold.
|
||||
get-snaps-1=Pouring the glasses and finding the correct song book...
|
||||
get-snaps-2=Singing a song...🎤🎶
|
||||
get-snaps-3=schkål, my friends!
|
||||
get-cocktail-1= 🍸 Inintiating mind reading unit... 🍸
|
||||
get-cocktail-2= 🍸 Mixing favourite ingredients of __1__ 🍸
|
||||
get-cocktail-3=🍸 __1__ your cocktail is done.🍸
|
||||
make-coffee-1= ☕ Boiling the water and grinding the coffee beans... ☕
|
||||
make-coffee-2= ☕ __1__ we ran out of coffe beans! Have some tea instead. ☕
|
||||
order-pizza-1= 🍕 Finding nearest pizza supplier... 🍕
|
||||
order-pizza-2= 🍕 Figuring out the favourite pizza of __1__ 🍕
|
||||
order-pizza-3= 🍕 __1__ your pizza is here! 🍕
|
||||
make-tea-1= ☕ Boiling the water... ☕
|
||||
make-tea-2= ☕ __1__ your tea is done! ☕
|
||||
get-mead-1= Filling the drinking horn
|
||||
get-mead-2= Skål!
|
||||
get-beer-1= 🍺 Pouring A Glass 🍺
|
||||
get-beer-2= 🍻 Chears Mate 🍻
|
||||
verify=Please return to our discord and type r!verify __1__
|
||||
|
||||
[afk-kick]
|
||||
message=All players were kicked because everyone was AFK.
|
||||
|
||||
[report-jail]
|
||||
jail=__1__ was jailed because they were reported too many times. Please wait for a moderator.
|
||||
|
||||
[protection-jail]
|
||||
jail=__1__ was jailed because they removed too many protected entities. Please wait for a moderator.
|
||||
|
||||
[nukeprotect]
|
||||
found=You cannot have __1__ in your inventory, so it was placed into the chests at spawn.
|
||||
|
||||
[logging]
|
||||
add-l=[RES] __1__ at level __2__ has been researched
|
||||
add-n=[RES] __1__ has been researched
|
||||
|
||||
[deconlog]
|
||||
decon=__1__ tried to deconstruct on __2__ from __3__ to __4__ which has __5__ items.
|
||||
245
exp_legacy/module/locale/en/commands.cfg
Normal file
245
exp_legacy/module/locale/en/commands.cfg
Normal file
@@ -0,0 +1,245 @@
|
||||
[expcom-admin-chat]
|
||||
description=Sends a message in chat that only admins can see.
|
||||
format=[Admin Chat] __1__: __2__
|
||||
|
||||
[expcom-admin-marker]
|
||||
description=Toggles admin marker mode, new markers can only be edited by admins
|
||||
exit=You have left admin marker mode, all new markers will not be protected.
|
||||
enter=You have entered admin marker mode, all new markers will be protected.
|
||||
place=You have placed an admin marker.
|
||||
edit=You have edited an admin marker.
|
||||
revert=You cannot edit admin markers.
|
||||
|
||||
[expcom-artillery]
|
||||
description=Artillery Target Remote
|
||||
|
||||
[expcom-bonus]
|
||||
description=Changes the amount of bonus you receive
|
||||
set=Your bonus has been set to __1__.
|
||||
perm=You dont have enough permission to set more than __1__.
|
||||
|
||||
[expcom-bot-queue]
|
||||
description-get=Get bot queue
|
||||
description-set=Set bot queue
|
||||
result=__1__ set the bot queue to __2__ successful attempts and __3__ failed attempts
|
||||
|
||||
[expcom-cheat]
|
||||
description-cheat=Toggles cheat mode for your player, or another player.
|
||||
description-res=Set all research for your force.
|
||||
description-day=Toggles always day in surface.
|
||||
res=__1__ has enabled all technologies
|
||||
day=__1__ set always day to __2__
|
||||
|
||||
[expcom-chelp]
|
||||
description=Searches for a keyword in all commands you are allowed to use.
|
||||
title=Help results for "__1__":
|
||||
footer=[__1__ results found: page __2__ of __3__]
|
||||
format=/__1__ __2__ - __3__ __4__
|
||||
alias=Alias: __1__
|
||||
out-of-range=__1__ is an invalid page number.
|
||||
|
||||
[expcom-clr-inv]
|
||||
description=Clears a players inventory
|
||||
|
||||
[expcom-connect]
|
||||
description=Connect to another server
|
||||
description-player=Send a player to a different server
|
||||
description-all=Connect all players to another server
|
||||
too-many-matching=Multiple server were found with the given name: __1__
|
||||
wrong-version=Servers were found but are on a different version: __1__
|
||||
same-server=You are already connected to the server: __1__
|
||||
offline=You cannot connect as the server is currently offline: __1__
|
||||
none-matching=No servers were found with that name, if you used an address please append true to the end of your command.
|
||||
|
||||
[expcom-debug]
|
||||
description=Opens the debug pannel for viewing tables.
|
||||
|
||||
[expcom-enemy]
|
||||
description-kill=Kill all biters only
|
||||
description-remove=Remove biters and prevent generation
|
||||
|
||||
[expcom-ff]
|
||||
description=Toggle friendly fire
|
||||
ff=__1__ set friendly fire to __2__
|
||||
|
||||
[expcom-find]
|
||||
description=Find a player on your map.
|
||||
|
||||
[expcom-home]
|
||||
description-home=Teleports you to your home location
|
||||
description-home-set=Sets your home location to your current position
|
||||
description-home-get=Returns your current home location
|
||||
description-return=Teleports you to previous location
|
||||
no-home=You have no home set.
|
||||
no-return=You can't return when home has not yet been used.
|
||||
home-set=Your home point has been set to x: __1__ y: __2__
|
||||
return-set=Your return point has been set to x: __1__ y: __2__
|
||||
home-get=Your home point is at x: __1__ y: __2__
|
||||
|
||||
[expcom-interface]
|
||||
description=Sends an invocation to be ran and returns the result.
|
||||
|
||||
[expcom-inv-search]
|
||||
description-ia=Display players sorted by the quantity of an item held
|
||||
description-ir=Display players who hold an item sorted by join time
|
||||
description-i=Display players sorted by the quantity of an item held and playtime
|
||||
description-io=Display online players sorted by the quantity of an item held and playtime
|
||||
reject-item=No item was found with internal name __1__; try using rich text selection.
|
||||
results-heading=Players found with [item=__1__]:
|
||||
results-item=__1__) __2__ has __3__ items. (__4__)
|
||||
results-none=No players have [item=__1__]
|
||||
|
||||
[expcom-jail]
|
||||
description-jail=Puts a player into jail and removes all other roles.
|
||||
description-unjail=Removes a player from jail.
|
||||
give=__1__ was jailed by __2__. Reason: __3__
|
||||
remove=__1__ was unjailed by __2__.
|
||||
already-jailed=__1__ is already in jail.
|
||||
not-jailed=__1__ is not currently in jail.
|
||||
|
||||
[expcom-join-message]
|
||||
description-msg=Sets your custom join message
|
||||
description-clr=Clear your join message
|
||||
|
||||
[expcom-kill]
|
||||
description=Kills yourself or another player.
|
||||
already-dead=You are already dead.
|
||||
|
||||
[expcom-lawnmower]
|
||||
description=Clean up biter corpse, decoratives and nuclear hole
|
||||
|
||||
[expcom-lastlocation]
|
||||
description=Sends you the last location of a player
|
||||
response=Last location of __1__ was [gps=__2__,__3__]
|
||||
|
||||
[expcom-me]
|
||||
description=Sends an action message in the chat
|
||||
|
||||
[expcom-personal-logistics]
|
||||
description=Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)
|
||||
|
||||
[expcom-pol]
|
||||
description-clr=Clear pollution
|
||||
description-off=Disable pollution
|
||||
clr=__1__ cleared the pollution.
|
||||
off=__1__ disabled the pollution.
|
||||
|
||||
[expcom-protection]
|
||||
description-pe=Toggles entity protection selection, hold shift to remove protection
|
||||
description-pa=Toggles area protection selection, hold shift to remove protection
|
||||
entered-entity-selection=Entered entity selection, select entites to protect, hold shift to remove protection.
|
||||
entered-area-selection=Entered area selection, select areas to protect, hold shift to remove protection.
|
||||
protected-entities=__1__ entities have been protected.
|
||||
unprotected-entities=__1__ entities have been unprotected.
|
||||
already-protected=This area is already protected.
|
||||
protected-area=This area is now protected.
|
||||
unprotected-area=This area is now unprotected.
|
||||
repeat-offence=__1__ has removed __2__ at [gps=__3__,__4__]
|
||||
|
||||
[expcom-quickbar]
|
||||
description=Saves your quickbar preset items to file
|
||||
|
||||
[expcom-rainbow]
|
||||
description=Sends an rainbow message in the chat
|
||||
|
||||
[expcom-ratio]
|
||||
description=This command will give the input and output ratios of the selected machine. Use the parameter for calculating the machines needed for that amount of items per second.
|
||||
notSelecting=Please select an entity with a recipe.
|
||||
item-in=You need __1__ per second of [item=__2__].
|
||||
fluid-in=You need __1__ per second of [fluid=__2__].
|
||||
item-out=This will result in: __1__ [item=__2__] per second.
|
||||
fluid-out=This will result in: __1__ [fluid=__2__] per second.
|
||||
machines=And you will need __1__ machines (with the same speed as this one) for this.
|
||||
|
||||
[expcom-repair]
|
||||
description=Repairs entities on your force around you
|
||||
result=__1__ entites were revived and __2__ were healed to max health.
|
||||
|
||||
[expcom-report]
|
||||
description-report=Reports a player and notifies moderators
|
||||
description-get-reports=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.
|
||||
description-clear-reports=Clears all reports from a player or just the report from one player.
|
||||
player-immune=This player can not be reported.
|
||||
self-report=You cannot report yourself.
|
||||
non-admin=__1__ was reported for __2__.
|
||||
admin=__1__ was reported by __2__ for __3__.
|
||||
already-reported=You can only report a player once, you can ask a moderator to clear this report.
|
||||
not-reported=The player had no reports on them.
|
||||
player-count-title=The following players have reports against them:
|
||||
player-report-title=__1__ has the following reports against them:
|
||||
list=__1__: __2__
|
||||
removed=__1__ has one or more reports removed by __2__.
|
||||
|
||||
[expcom-res]
|
||||
description-ares=Automatically queue up research
|
||||
res=__1__ set auto research to __2__
|
||||
msg=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color]
|
||||
inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color]
|
||||
inf-q=[color=255, 255, 255] Research added to queue - [technology=__1__] - __2__[/color]
|
||||
res-name=[technology=__1__] __2__
|
||||
name=Name
|
||||
target=Target
|
||||
attempt=Attempt
|
||||
difference=Diff
|
||||
main-tooltip=Research GUI
|
||||
|
||||
[expcom-roles]
|
||||
description-assign-role=Assigns a role to a player
|
||||
description-unassign-role=Unassigns a role from a player
|
||||
description-list-roles=Lists all roles in they correct order
|
||||
higher-role=The role you tried to assign is higher than your highest.
|
||||
list=All roles are: __1__
|
||||
list-player=__1__ has: __2__
|
||||
list-element=__1__, __2__
|
||||
|
||||
[expcom-server-ups]
|
||||
no-ext=No external source was found, cannot display server ups.
|
||||
|
||||
[expcom-spawn]
|
||||
description=Teleport to spawn
|
||||
unavailable=They was a problem getting you to spawn, please try again later.
|
||||
|
||||
[expcom-spectate]
|
||||
description-spectate=Toggles spectator mode
|
||||
description-follow=Start following a player in spectator
|
||||
follow-self=You can not follow yourself
|
||||
|
||||
[expcom-speed]
|
||||
description=Set game speed
|
||||
result=__1__ set the game speed to __2__
|
||||
|
||||
[expcom-surface-clearing]
|
||||
description-ci=Clear Item On Ground
|
||||
description-cb=Clear Blueprint
|
||||
|
||||
[expcom-tag]
|
||||
description=Sets your player tag.
|
||||
description-clear=Clears your tag. Or another player if you are admin.
|
||||
|
||||
[expcom-tp]
|
||||
description-tp=Teleports a player to another player.
|
||||
description-bring=Teleports a player to you.
|
||||
description-goto=Teleports you to a player.
|
||||
no-position-found=No position to teleport to was found, please try again later.
|
||||
to-self=Player can not be teleported to themselves.
|
||||
|
||||
[expcom-train]
|
||||
description=Set All Trains to Automatic
|
||||
manual-result=__1__ put __2__ trains into automatic mode
|
||||
|
||||
[expcom-warnings]
|
||||
description-give=Gives a warning to a player; may lead to automatic script action.
|
||||
description-get=Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.
|
||||
description-clear=Clears all warnings (and script warnings) from a player
|
||||
received=__1__ received a warning from __2__ for __3__.
|
||||
player=__1__ has __2__ warnings and __3__/__4__ script warnings.
|
||||
player-detail=__1__ gave warning for: __2__
|
||||
list-title=The following players have this many warnings (and this many script warnings):
|
||||
list=__1__: __2__ (__3__/__4__)
|
||||
cleared=__1__ had all their warnings cleared by __2__.
|
||||
|
||||
[expcom-waterfill]
|
||||
description=Change tile to water
|
||||
waterfill-distance=Too close to designated location
|
||||
waterfill-cliff=Not enough cliff explosive to create water
|
||||
entered-area-selection=Entered area selection, select areas to convert.
|
||||
3
exp_legacy/module/locale/en/config.cfg
Normal file
3
exp_legacy/module/locale/en/config.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
[command-auth]
|
||||
admin-only=This command is for (game) admins only!
|
||||
command-disabled=This command has been disabled by management!
|
||||
108
exp_legacy/module/locale/en/data.cfg
Normal file
108
exp_legacy/module/locale/en/data.cfg
Normal file
@@ -0,0 +1,108 @@
|
||||
[join-message]
|
||||
greet=[color=0,1,0] Welcome to explosive gaming community server! If you like the server join our discord: __1__ [/color]
|
||||
message-set=Your join message has been updated.
|
||||
message-cleared=Your join message has been cleared.
|
||||
|
||||
[quickbar]
|
||||
saved=Your quickbar filters have been saved.
|
||||
|
||||
[exp-required]
|
||||
Warnings=Warnings
|
||||
Warnings-tooltip=The total number of warnings you have received from staff
|
||||
Warnings-value-tooltip=The total number of warnings you have received from staff
|
||||
|
||||
[exp-settings]
|
||||
Colour=Colour
|
||||
Colour-tooltip=Your player colour
|
||||
Colour-value-tooltip=Change by using /color
|
||||
JoinMessage=Join Message
|
||||
JoinMessage-tooltip=The message displayed when you join
|
||||
JoinMessage-value-tooltip=Change by using /join-message
|
||||
QuickbarFilters=Quickbar Filters
|
||||
QuickbarFilters-tooltip=The filters on your quickbar
|
||||
QuickbarFilters-value-tooltip=Change by using /save-quickbar
|
||||
UsesAlt=Alt View
|
||||
UsesAlt-tooltip=Whether you use alt view when you play
|
||||
UsesAlt-value-tooltip=Change by pressing __CONTROL__show-info__
|
||||
UsesServerUps=Server UPS
|
||||
UsesServerUps-tooltip=Whether the current server UPS is shown
|
||||
UsesServerUps-value-tooltip=Change by using /server-ups
|
||||
Tag=Player Tag
|
||||
Tag-tooltip=The tag shown after your name
|
||||
Tag-value-tooltip=Change by using /tag
|
||||
TagColor=Player Tag color
|
||||
TagColor-tooltip=The color of the tag shown after your name
|
||||
TagColor-value-tooltip=Change by using /tag-color
|
||||
Bonus=Player Bonus
|
||||
Bonus-tooltip=The bonus given to your character
|
||||
Bonus-value-tooltip=Change by using /bonus
|
||||
HasEnabledDecon=Quick Tree Decon
|
||||
ToolbarState=Toolbox
|
||||
ToolbarState-tooltip=The order and favourites in your toolbox
|
||||
ToolbarState-value-tooltip=This value is calculated automatically when you leave the game
|
||||
|
||||
[exp-statistics]
|
||||
MapsPlayed=Maps Played
|
||||
MapsPlayed-tooltip=The number of unique maps you have played on
|
||||
JoinCount=Join Count
|
||||
JoinCount-tooltip=The number of times you have joined our servers
|
||||
Playtime=Playtime
|
||||
Playtime-tooltip=The amount of time you have spent on our servers
|
||||
AfkTime=AFK Time
|
||||
AfkTime-tooltip=The amount of time you have been AFK on our servers
|
||||
ChatMessages=Messages
|
||||
ChatMessages-tooltip=The number of messages you have sent in chat
|
||||
CommandsUsed=Commands
|
||||
CommandsUsed-tooltip=The number of commands you have used
|
||||
RocketsLaunched=Rockets Launched
|
||||
RocketsLaunched-tooltip=The number of rockets launched while you were online
|
||||
ResearchCompleted=Research Completed
|
||||
ResearchCompleted-tooltip=The number of research projects completed while you were online
|
||||
MachinesBuilt=Machines Built
|
||||
MachinesBuilt-tooltip=The number of machines you have built
|
||||
MachinesRemoved=Machines Removed
|
||||
MachinesRemoved-tooltip=The number of machines you have removed
|
||||
TilesBuilt=Tiles Placed
|
||||
TilesBuilt-tooltip=The number of tiles you have placed
|
||||
TilesRemoved=Tiles Removed
|
||||
TilesRemoved-tooltip=The number of tiles you have removed
|
||||
TreesDestroyed=Trees Destroyed
|
||||
TreesDestroyed-tooltip=The number of trees you have destroyed
|
||||
OreMined=Ore Mined
|
||||
OreMined-tooltip=The amount of ore you have mined
|
||||
ItemsCrafted=Items Crafted
|
||||
ItemsCrafted-tooltip=The number of items you have crafted
|
||||
ItemsPickedUp=Items Picked Up
|
||||
ItemsPickedUp-tooltip=The number of items you have picked up
|
||||
Kills=Kills
|
||||
Kills-tooltip=The number of biters and biter bases you have squished
|
||||
Deaths=Deaths
|
||||
Deaths-tooltip=The number of times you have died
|
||||
DamageDealt=Damage Dealt
|
||||
DamageDealt-tooltip=The amount of damage you have dealt to other forces
|
||||
DistanceTravelled=Distance Travelled
|
||||
DistanceTravelled-tooltip=The total distance in tiles that you have travelled
|
||||
CapsulesUsed=Capsules Used
|
||||
CapsulesUsed-tooltip=The number of capsules you have used
|
||||
EntityRepaired=Machines Repaired
|
||||
EntityRepaired-tooltip=The number of machines which you have repaired
|
||||
DeconstructionPlannerUsed=Decon Planner Used
|
||||
DeconstructionPlannerUsed-tooltip=The number of times you have used the deconstruction planner
|
||||
MapTagsMade=Map Tags Created
|
||||
MapTagsMade-tooltip=The number of map tags you have created
|
||||
DamageDeathRatio=Damage Death Ratio
|
||||
DamageDeathRatio-tooltip=Damage over Death
|
||||
KillDeathRatio=Kill Death Ratio
|
||||
KillDeathRatio-tooltip=Kill over Death
|
||||
SessionTime=Session Time
|
||||
SessionTime-tooltip=Session Time
|
||||
BuildRatio=Build Ratio
|
||||
BuildRatio-tooltip=Build over Remove
|
||||
RocketPerHour=Rocket Per Hour
|
||||
RocketPerHour-tooltip=Rocket Launched Over Play Time in Hour
|
||||
TreeKillPerMinute=Tree Kill Per Minute
|
||||
TreeKillPerMinute-tooltip=Tree Destroyed Per Minute
|
||||
NetPlayTime=Net Play Time
|
||||
NetPlayTime-tooltip=Net Play Time
|
||||
AFKTimeRatio=AFK Time Ratio
|
||||
AFKTimeRatio-tooltip=AFK Time over Play Time
|
||||
53
exp_legacy/module/locale/en/expcore.cfg
Normal file
53
exp_legacy/module/locale/en/expcore.cfg
Normal file
@@ -0,0 +1,53 @@
|
||||
time-symbol-days-short=__1__d
|
||||
color-tag=[color=__1__]__2__[/color]
|
||||
|
||||
[time-format]
|
||||
simple-format-tagged=__1__ __2__
|
||||
simple-format-div=__1__:__2__
|
||||
|
||||
[expcore-commands]
|
||||
unauthorized=Unauthorized, Access is denied due to invalid credentials
|
||||
reject-string-options=Invalid Option, Must be one of: __1__
|
||||
reject-string-max-length=Invalid Length, Max: __1__
|
||||
reject-number=Invalid Number.
|
||||
reject-number-range=Invalid Range, Min (inclusive): __1__, Max (inclusive): __2__
|
||||
reject-player=Invalid Player Name, __1__ ,try using tab key to auto-complete the name
|
||||
reject-player-online=Player is offline.
|
||||
reject-player-alive=Player is dead.
|
||||
reject-force=Invalid Force Name.
|
||||
reject-surface=Invalid Surface Name.
|
||||
reject-color=Invalid Color Name.
|
||||
invalid-inputs=Invalid Input, /__1__ __2__
|
||||
invalid-param=Invalid Param "__1__"; __2__
|
||||
command-help=__1__ - __2__
|
||||
command-ran=Command Complete
|
||||
command-fail=Command failed to run: __1__
|
||||
command-error-log-format=[ERROR] command/__1__ :: __2__
|
||||
|
||||
[expcore-roles]
|
||||
error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__
|
||||
error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__
|
||||
game-message-assign=__1__ has been assigned to __2__ by __3__
|
||||
game-message-unassign=__1__ has been unassigned from __2__ by __3__
|
||||
reject-role=Invalid Role Name.
|
||||
reject-player-role=Player has a higher role.
|
||||
|
||||
[gui_util]
|
||||
button_tooltip=Shows/hides the toolbar.
|
||||
|
||||
[expcore-gui]
|
||||
left-button-tooltip=Hide all open windows.
|
||||
|
||||
[expcore-data]
|
||||
set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin.
|
||||
get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data.
|
||||
get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json
|
||||
data-failed=Your player data has failed to load. Any changes to your data will not be saved.
|
||||
data-restore=Your player data has been restored and changes will now save when you leave.
|
||||
preference=Saving Preference
|
||||
preference-tooltip=Which categories will be saved when you leave the game
|
||||
preference-value-tooltip=Change by using /set-preference
|
||||
preference-All=All data will be saved
|
||||
preference-Statistics=Only statistics, settings, and required data will be saved
|
||||
preference-Settings=Only settings and required data will be saved
|
||||
preference-Required=Only required data will be saved
|
||||
321
exp_legacy/module/locale/en/gui.cfg
Normal file
321
exp_legacy/module/locale/en/gui.cfg
Normal file
@@ -0,0 +1,321 @@
|
||||
[player-list]
|
||||
main-tooltip=Player List
|
||||
open-action-bar=Options
|
||||
close-action-bar=Close Options
|
||||
reason-confirm=Confirm Reason
|
||||
reason-entry=Enter Reason
|
||||
goto-player=Goto player
|
||||
bring-player=Bring player
|
||||
report-player=Report player
|
||||
warn-player=Warn player
|
||||
jail-player=Jail player
|
||||
kick-player=Kick player
|
||||
ban-player=Ban player
|
||||
afk-time=__1__% of total map time\nLast moved __2__ ago
|
||||
open-map=__1__ __2__\n__3__\nClick to open map
|
||||
|
||||
[rocket-info]
|
||||
main-tooltip=Rocket Info
|
||||
launch-tooltip=Launch rocket
|
||||
launch-tooltip-disabled=Launch rocket (not ready)
|
||||
toggle-rocket-tooltip=Disable auto launch
|
||||
toggle-rocket-tooltip-disabled=Enable auto launch
|
||||
toggle-section-tooltip=Expand Section
|
||||
toggle-section-collapse-tooltip=Collapse Section
|
||||
section-caption-stats=Statistics
|
||||
section-tooltip-stats=Statistics about how rockets are launched
|
||||
section-caption-milestones=Milestones
|
||||
section-tooltip-milestones=The times when milestones were met
|
||||
section-caption-progress=Build Progress
|
||||
section-tooltip-progress=The progress for your rocket silos
|
||||
progress-no-silos=You have no rocket silos
|
||||
data-caption-first-launch=First Launch
|
||||
data-tooltip-first-launch=The time of the first launch
|
||||
data-caption-last-launch=Last Launch
|
||||
data-tooltip-last-launch=The time of the last launch
|
||||
data-caption-fastest-launch=Fastest Launch
|
||||
data-tooltip-fastest-launch=The time taken for the fastest launch
|
||||
data-caption-total-rockets=Total Launched
|
||||
data-tooltip-total-rockets=Total number of rockets launched by your force
|
||||
value-tooltip-total-rockets=__1__% of all rockets on this map
|
||||
data-caption-avg-launch=Average Time
|
||||
data-tooltip-avg-launch=The average amount of time taken to launch a rocket
|
||||
data-caption-avg-launch-n=Average Time __1__
|
||||
data-tooltip-avg-launch-n=The average amount of time taken to launch the last __1__ rockets
|
||||
data-caption-milestone-n=Milestone __1__
|
||||
data-tooltip-milestone-n=Time taken to each __1__ rockets
|
||||
data-caption-milestone-next=N/A
|
||||
data-tooltip-milestone-next=Not yet achieved
|
||||
progress-x-pos=X __1__
|
||||
progress-y-pos=Y __1__
|
||||
progress-label-tooltip=View on map
|
||||
progress-launched=Launched
|
||||
progress-caption=__1__%
|
||||
progress-tooltip=This silo has launched __1__ rockets
|
||||
launch-failed=Failed to launch rocket, please wait a few seconds and try again.
|
||||
|
||||
[science-info]
|
||||
main-caption=Science Packs
|
||||
main-tooltip=Science Info
|
||||
eta-caption=ETA:
|
||||
eta-tooltip=The estimated time left for the current research
|
||||
eta-time=T- __1__
|
||||
unit=__1__ spm
|
||||
pos-tooltip=Total made: __1__
|
||||
neg-tooltip=Total used: __1__
|
||||
net-tooltip=Total net: __1__
|
||||
no-packs=You have not made any science packs yet
|
||||
|
||||
[task-list]
|
||||
main-caption=Task List [img=info]
|
||||
main-tooltip=Task List
|
||||
sub-tooltip=Tasks that remain to be done\n- You can use richtext to include images [img=utility/not_enough_repair_packs_icon] or [color=blue]color[/color] your tasks.
|
||||
no-tasks=No tasks found!
|
||||
no-tasks-tooltip=Click on the plus button to the top right of this window to add a new task!
|
||||
last-edit=Last edited by __1__ at __2__
|
||||
add-tooltip=Add new task
|
||||
confirm=Confirm
|
||||
confirm-tooltip=Save task (minimum of 5 characters long)
|
||||
discard=Discard
|
||||
discard-tooltip=Discard task/changes
|
||||
delete=Delete
|
||||
delete-tooltip=Delete task
|
||||
close-tooltip=Close task details
|
||||
edit=Edit task
|
||||
edit-tooltip=Currently being edited by: __1__
|
||||
edit-tooltip-none=Currently being edited by: Nobody
|
||||
create-footer-header=Create task
|
||||
edit-footer-header=Edit task
|
||||
view-footer-header=Task details
|
||||
|
||||
[autofill]
|
||||
main-tooltip=Autofill settings
|
||||
toggle-section-caption=__1__ __2__
|
||||
toggle-section-tooltip=Expand Section
|
||||
toggle-section-collapse-tooltip=Collapse Section
|
||||
toggle-entity-tooltip=Toggle the autofill of __1__
|
||||
toggle-tooltip=Toggle the autofill of __1__ into __2__ slots
|
||||
amount-tooltip=Amount of items to insert into the __1__ slots
|
||||
invalid=Autofill set to maximum amount: __1__ __2__ for __3__
|
||||
inserted=Inserted __1__ __2__ into __3__
|
||||
|
||||
[warp-list]
|
||||
main-caption=Warp List [img=info]
|
||||
main-tooltip=Warp List
|
||||
sub-tooltip=Warps can only be used every __1__ seconds and when within __2__ tiles\n__3__\n__4__\n__5__\n__6__\n__7__\n__8__
|
||||
sub-tooltip-current= - __1__ This is your current warp point;
|
||||
sub-tooltip-connected= - __1__ You can travel to this warp point;
|
||||
sub-tooltip-different= - __1__ This warp is on a different network;
|
||||
sub-tooltip-cooldown= - __1__ You are currently on cooldown;
|
||||
sub-tooltip-not_available= - __1__ You are not in range of a warp point;
|
||||
sub-tooltip-bypass= - __1__ Your role allows you to travel here;
|
||||
too-close=Cannot create warp; too close to existing warp point: __1__
|
||||
too-close-to-water=Cannot create warp; too close to water, please move __1__ tiles away from the water body or landfill it
|
||||
too-close-to-entities=Cannot create warp; too close to other entities, please move __1__ tiles away from the entities or remove them
|
||||
last-edit=Last edited by __1__ at __2__\nClick to view on map
|
||||
add-tooltip=Add new warp
|
||||
confirm-tooltip=Save changes
|
||||
cancel-tooltip=Discard changes
|
||||
edit-tooltip=Currently being edited by: __1__
|
||||
edit-tooltip-none=Currently being edited by: Nobody
|
||||
remove-tooltip=Remove warp
|
||||
timer-tooltip=Please wait __1__ seconds before you can warp
|
||||
timer-tooltip-zero=After each warp you will need to wait __1__ seconds before you can warp again
|
||||
goto-tooltip=Go to x __1__ y __2__
|
||||
goto-bypass=Go to x __1__ y __2__, bypass mode
|
||||
goto-bypass-different-network=Go to x __1__ y __2__, bypass mode different network
|
||||
goto-same-warp=You are already on this warp
|
||||
goto-different-network=This warp is on a different network, use power poles to connect it
|
||||
goto-cooldown=You are on cooldown, wait for your cooldown to recharge
|
||||
goto-disabled=You are not on a warp point, walk to a warp point
|
||||
goto-edit=Edit warp icon
|
||||
|
||||
[readme]
|
||||
main-tooltip=Infomation
|
||||
welcome-tab=Welcome
|
||||
welcome-tooltip=Welcome to Explosive Gaming
|
||||
welcome-general=Welcome to Explosive Gaming; we host many factorio servers. While you are here, we ask you to follow our rules. You can find these in the tab above. You can also find our custom commands and links to our other servers. This map has been online for __2__.\nPlease note that our servers reset periodically, the next reset is: __1__
|
||||
welcome-roles=We run a custom role system to help protect the work of others. As a result you may not be able to use your deconstruction planner yet or drop item on the groud. Roles also give you access to some custom features such as adding tasks to our task list or making new warp points.\nYou have been assigned the roles: __1__
|
||||
welcome-chat=Chatting can be difficult for new players because it’s different than other games! It’s very simple, the button you need to press is the “GRAVE/TILDE” key (which is located under the “ESC key”) - If you would like to change the key, go to your Controls tab in options.\nThe setting you need to change is “Toggle chat (and Lua console)” you currently have it set to "__CONTROL__toggle-console__"
|
||||
rules-tab=Rules
|
||||
rules-tooltip=Rules for our server
|
||||
rules-general=By playing on our servers you accept the rules below. If you are supected of breaking a rule then you will be questioned by one of our moderators. If required you will be banned from our servers, appeals can be made by contacting an Administrator on our discord.
|
||||
rules-1=Hacking / cheating / abusing bugs will not be tolerated.
|
||||
rules-2=Any bugs or exploits found should be reported to our staff members.
|
||||
rules-3=Be respectful to other players in chat, this includes any other forms of communication.
|
||||
rules-4=Taking all items from a belt or logistics network is forbidden: sharing resources is mandatory.
|
||||
rules-5=Spamming of chat, bots, unlimited chests, or concrete is not allowed.
|
||||
rules-6=Before removing major parts of the factory tell other players why you are removing it.
|
||||
rules-7=Do not cause unnecessary lag by placing/removing tiles with bots or using active provider chests, if think some thing might cause lag please ask staff first.
|
||||
rules-8=Do not walk in random directions with no reason, this is to reduce map download times.
|
||||
rules-9=Do not use speakers on global or with alerts without prior permission, no one wants to hear your music at full volume without knowing where the off switch is.
|
||||
rules-10=Do not rotate belts, deactivate belts with wires, or cause production to stop without good reason, this goes for inserters and spliters as well.
|
||||
rules-11=Do not make train roundabouts. Other loops such as RoRo stations are allowed.
|
||||
rules-12=When using trains, use the same size other players have used, many players use 1-2-1, 2-4-2, or 3-8-3, meaning 1 engine 2 cargo 1 engine.
|
||||
rules-13=Trains are Left Hand Drive (LHD) only, this means trains drive on the left side of the tracks.
|
||||
rules-14=Do not beg for roles, advertise other servers, or link to harmful sites.
|
||||
rules-15=Use common sense, report rule breakers, and Administrators have the final word.
|
||||
commands-tab=Commands
|
||||
commands-tooltip=Commands which you are able to use
|
||||
commands-general=We have lots of custom commands which you are able to use. Below you can find a list of all the commands that you are allowed to use and what they do. If you need more information or want to search for a command you can use our /search-help command.
|
||||
servers-tab=Servers
|
||||
servers-tooltip=Links to our other servers and sites
|
||||
servers-general=This is only one of our servers for factorio, we host many of others as well. Below you can find details about all the servers that we host as well as links to our external services such as discord or github.
|
||||
servers-factorio=Factorio Servers
|
||||
servers-1=S1 Public
|
||||
servers-d1=This is our 48 hour reset server.
|
||||
servers-2=S2 Off
|
||||
servers-d2=This server is closed.
|
||||
servers-3=S3 Weekly
|
||||
servers-d3=This is our weekly reset server.
|
||||
servers-4=S4 Monthly
|
||||
servers-d4=This is our monthly reset server.
|
||||
servers-5=S5 Modded
|
||||
servers-d5=This is our modded server, see discord for details.
|
||||
servers-6=S6 Donator
|
||||
servers-d6=This is our donator only server, online when requested.
|
||||
servers-7=S7 Event
|
||||
servers-d7=This is our event server, we try to run events at least once per week.
|
||||
servers-8=S8 T̷-̶s̶-̴:̷
|
||||
servers-d8=N̵o̴ ̶o̷-̶e̵ ̴k̸n̷-̶w̵s̸ ̴w̷h̷a̶-̶ ̷h̴a̴p̷p̴e̷n̷s̸ ̷o̶n̴ ̷t̶h̴-̶s̶ ̷s̷e̶r̸v̸e̴r̷,̶ ̸i̸t̴ ̷m̶-̸g̴h̶t̷ ̸n̸-̶t̵ ̷e̴v̸e̸n̶t̷ ̵-̷x̴i̵s̶t̸.̸
|
||||
servers-connect-Offline=Server is currently offline
|
||||
servers-connect-Current=This is your current server
|
||||
servers-connect-Version=Server is on a different version: __1__
|
||||
servers-connect-Password=Server requires a password
|
||||
servers-connect-Modded=Server requires mods to be downloaded
|
||||
servers-connect-Online=Server is online
|
||||
servers-external=External Links
|
||||
servers-open-in-browser=Open in your browser
|
||||
backers-tab=Backers
|
||||
backers-tooltip=People who have helped make our server
|
||||
backers-general=We would like to thank all our staff and backers who have helped our community grow. Our staff have helped to keep our servers safe from trolls and a fun place to play. Our backers have helped us to cover our running costs and provide a great community for us all to enjoy together.
|
||||
backers-management=Administrators
|
||||
backers-board=Board Members and Senior Backers
|
||||
backers-staff=Staff Members
|
||||
backers-backers=Sponsors and Supporters
|
||||
backers-active=Active Players
|
||||
data-tab=Data
|
||||
data-tooltip=All of your stored player data
|
||||
data-general=Our servers will save your player data so that we can sync it between servers. All of your data can be found below, if you wish to save a copy locally then use /save-data. If you want to change what data is saved then use /set-preference.
|
||||
data-settings=Settings
|
||||
data-statistics=Statistics
|
||||
data-required=Required
|
||||
data-misc=Miscellaneous
|
||||
data-format=__1____2__
|
||||
|
||||
[tree-decon]
|
||||
main-tooltip=Toggle fast tree decon
|
||||
enabled=enabled
|
||||
disabled=disabled
|
||||
toggle-msg=Fast decon has been __1__
|
||||
|
||||
[bonus]
|
||||
main-tooltip=Bonus
|
||||
control-pts-a=Points available
|
||||
control-pts-n=Points needed
|
||||
control-pts-r=Points remaining
|
||||
control-reset=Reset
|
||||
control-apply=Apply
|
||||
control-pts-exceed=Points allocated exceeded allowance
|
||||
display-cmms=Mining
|
||||
display-cmms-tooltip=Character manual mining speed
|
||||
display-crs=Running
|
||||
display-crs-tooltip=Character running speed
|
||||
display-ccs=Crafting
|
||||
display-ccs-tooltip=Character crafting speed
|
||||
display-cisb=Inventory
|
||||
display-cisb-tooltip=Character inventory slots bonus
|
||||
display-chb=Health
|
||||
display-chb-tooltip=Character health bonus
|
||||
display-crdb=Reach
|
||||
display-crdb-tooltip=Character reach distance bonus
|
||||
display-personal-battery-recharge=Battery
|
||||
display-personal-battery-recharge-tooltip=Player battery recharge
|
||||
display-fmms=Mining
|
||||
display-fmms-tooltip=Force manual mining speed
|
||||
display-frs=Running
|
||||
display-frs-tooltip=Force running speed
|
||||
display-fcs=Crafting
|
||||
display-fcs-tooltip=Force crafting speed
|
||||
display-fisb=Inventory
|
||||
display-fisb-tooltip=Force inventory slots bonus
|
||||
display-fhb=Health
|
||||
display-fhb-tooltip=Force health bonus
|
||||
display-frdb=Reach
|
||||
display-frdb-tooltip=Force reach distance bonus
|
||||
display-fwrsm=Robot Speed
|
||||
display-fwrsm-tooltip=Force worker robots speed modifier
|
||||
display-fwrbm=Robot Battery
|
||||
display-fwrbm-tooltip=Force worker robots battery modifier
|
||||
display-fwrsb=Robot Storage
|
||||
display-fwrsb-tooltip=Force worker robots storage bonus
|
||||
display-ffrlm=Robot Lifetime
|
||||
display-ffrlm-tooltip=Force following robots lifetime modifier
|
||||
|
||||
[vlayer]
|
||||
main-tooltip=Vlayer GUI
|
||||
description-pbr=Recharge Player Battery upto a portion with vlayer
|
||||
description-vi=Vlayer Info
|
||||
pbr-not-running=vlayer need to be running
|
||||
display-item-solar=[img=entity/solar-panel] Solar Panel
|
||||
display-item-accumulator=[img=entity/accumulator] Accumulator
|
||||
display-current-production=[virtual-signal=signal-P] Current Production
|
||||
display-sustained-production=[virtual-signal=signal-S] Sustained Production
|
||||
display-max-capacity=[virtual-signal=signal-C] Battery Capacity
|
||||
display-current-capacity=[virtual-signal=signal-E] Battery Charge
|
||||
display-remaining-surface-area=[virtual-signal=signal-R] Remaining Surface
|
||||
display-item-solar-tooltip=The amount of Solar Panel
|
||||
display-item-accumulator-tooltip=The amount of Accumulator
|
||||
display-current-production-tooltip=Current Power Production
|
||||
display-sustained-production-tooltip=Sustained Power Production
|
||||
display-max-capacity-tooltip=Battery Max Capacity
|
||||
display-current-capacity-tooltip=Battery Current Charge
|
||||
display-remaining-surface-area-tooltip=Remaining Surface. Insert Landfill to increase
|
||||
steel-chest-detect=No steel chest detected
|
||||
steel-chest-empty=Chest is not emptied
|
||||
control-refresh=Refresh List
|
||||
control-see=See Interface
|
||||
control-build=Build Interface
|
||||
control-remove=Remove Interface
|
||||
result-build=built
|
||||
result-remove=removed
|
||||
result-interface-location=__1__ interface was located at __2__
|
||||
interface-result=__1__ __2__ __4__ interface at __3__
|
||||
result-unable=Unable to build __1__ interface, because of __2__
|
||||
result-multiple=Multiple steel chest detected
|
||||
result-limit=Max limit exceeded
|
||||
result-space=Not enough space
|
||||
control-type-energy=Energy
|
||||
control-type-circuit=Circuit
|
||||
control-type-storage-input=Storage Input
|
||||
control-type-storage-output=Storage Output
|
||||
|
||||
[module]
|
||||
main-tooltip=Module GUI
|
||||
|
||||
[landfill]
|
||||
main-tooltip=Blueprint Landfill GUI
|
||||
cursor-none=You need to hold the blueprint in cursor
|
||||
|
||||
[production]
|
||||
main-tooltip=Production GUI
|
||||
label-prod=Production
|
||||
label-con=Consumption
|
||||
label-bal=Balance (sec)
|
||||
|
||||
[surveillance]
|
||||
main-tooltip=Surveillance GUI
|
||||
status-enable=Enable
|
||||
status-disable=Disable
|
||||
func-set=Set
|
||||
type-player=Player
|
||||
type-static=Static
|
||||
type-player-loop=Player loop
|
||||
|
||||
[toolbar]
|
||||
main-caption=Toolbox
|
||||
main-tooltip=Toolbox Settings\nUse the checkboxs to select facourites
|
||||
reset=Reset All
|
||||
toggle=Toggle Favourites
|
||||
move-up=Move Up
|
||||
move-down=Move Down
|
||||
2
exp_legacy/module/locale/en/language.cfg
Normal file
2
exp_legacy/module/locale/en/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=English
|
||||
2
exp_legacy/module/locale/eo/language.cfg
Normal file
2
exp_legacy/module/locale/eo/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Esperanto
|
||||
2
exp_legacy/module/locale/es-ES/language.cfg
Normal file
2
exp_legacy/module/locale/es-ES/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Spanish (Spain)
|
||||
2
exp_legacy/module/locale/et/language.cfg
Normal file
2
exp_legacy/module/locale/et/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Estonian
|
||||
2
exp_legacy/module/locale/eu/language.cfg
Normal file
2
exp_legacy/module/locale/eu/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Basque
|
||||
2
exp_legacy/module/locale/fa/language.cfg
Normal file
2
exp_legacy/module/locale/fa/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Persian
|
||||
2
exp_legacy/module/locale/fi/language.cfg
Normal file
2
exp_legacy/module/locale/fi/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Finnish
|
||||
2
exp_legacy/module/locale/fil/language.cfg
Normal file
2
exp_legacy/module/locale/fil/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Filipino
|
||||
2
exp_legacy/module/locale/fr/language.cfg
Normal file
2
exp_legacy/module/locale/fr/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=French
|
||||
2
exp_legacy/module/locale/fy-NL/language.cfg
Normal file
2
exp_legacy/module/locale/fy-NL/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Frysian (Netherlands)
|
||||
2
exp_legacy/module/locale/ga-IE/language.cfg
Normal file
2
exp_legacy/module/locale/ga-IE/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Irish (Ireland)
|
||||
2
exp_legacy/module/locale/he/language.cfg
Normal file
2
exp_legacy/module/locale/he/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Hebrew
|
||||
2
exp_legacy/module/locale/hr/language.cfg
Normal file
2
exp_legacy/module/locale/hr/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Croatian
|
||||
2
exp_legacy/module/locale/hu/language.cfg
Normal file
2
exp_legacy/module/locale/hu/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Hungarian
|
||||
2
exp_legacy/module/locale/id/language.cfg
Normal file
2
exp_legacy/module/locale/id/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Indonesian
|
||||
2
exp_legacy/module/locale/is/language.cfg
Normal file
2
exp_legacy/module/locale/is/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Icelandic
|
||||
2
exp_legacy/module/locale/it/language.cfg
Normal file
2
exp_legacy/module/locale/it/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Italian
|
||||
2
exp_legacy/module/locale/ja/language.cfg
Normal file
2
exp_legacy/module/locale/ja/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Japanese
|
||||
2
exp_legacy/module/locale/ka/language.cfg
Normal file
2
exp_legacy/module/locale/ka/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Georgian
|
||||
2
exp_legacy/module/locale/kk/language.cfg
Normal file
2
exp_legacy/module/locale/kk/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Kazakh
|
||||
2
exp_legacy/module/locale/ko/language.cfg
Normal file
2
exp_legacy/module/locale/ko/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Korean
|
||||
2
exp_legacy/module/locale/lt/language.cfg
Normal file
2
exp_legacy/module/locale/lt/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Lithuanian
|
||||
2
exp_legacy/module/locale/lv/language.cfg
Normal file
2
exp_legacy/module/locale/lv/language.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[language]
|
||||
local-language=Latvian
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user