diff --git a/FactorioSoftmodManager.lua b/FactorioSoftmodManager.lua deleted file mode 100644 index 5b41c12417..0000000000 --- a/FactorioSoftmodManager.lua +++ /dev/null @@ -1,754 +0,0 @@ ---- Factorio Softmod Manager --- @module FSM --- @alias Manager --- @author Cooldude2606 --- @usage Manager = require("FactorioSoftmodManager") -local moduleIndex = require("/modules/index") -local Manager = {} - --- this is a constant that is used to represent the server -SERVER = setmetatable({index=0,name='',online_time=0,afk_time=0,print=print,admin=true,valid=true,__self={}},{__index=function(tbl,key) if type(game.players[1][key]) == 'function' then return function() end else return nil end end}) - ---- Setup for metatable of the Manager to force read only nature --- @usage Manager() -- runs Manager.loadModdules() --- @usage Manager[name] -- returns module by that name --- @usage tostring(Manager) -- returns formated list of loaded modules -local ReadOnlyManager = setmetatable({},{ - __metatable=false, - __index=function(tbl,key) - -- first looks in manager and then looks in mander.loadModules - return rawget(Manager,key) ~= nil and rawget(Manager,key) or rawget(Manager.loadModules,key) - end, - __call=function(tbl) - -- if there are no modules loaded then it loads them - if #tbl.loadModules == 0 then - tbl.loadModules() - end - end, - __newindex=function(tbl,key,value) - -- provents the changing of any key that is not currentState - if key == 'currentState' then - -- provides a verbose that is always emited describing the change in state - Manager.verbose(string.rep('__',10)..'| Start: '..value..' |'..string.rep('__',10),true) - Manager.verbose('The verbose state is now: '..tostring(Manager.setVerbose[value]),true) - rawset(Manager,key,value) - else error('Manager is read only please use included methods',2) end - end, - __tostring=function(tbl) - -- acts as a redirect - return tostring(Manager.loadModules) - end -}) - -local function setupModuleName(name) - -- creates a table that acts like a string but is read only - return setmetatable({},{ - __index=function(tbl,key) return name end, - __newindex=function(tbl,key,value) error('Module Name Is Read Only') end, - __tostring=function(tbl) return name end, - __concat=function(val1,val2) return type(val1) == 'string' and val1..name or name..val2 end, - __metatable=false, - }) -end - -Manager.currentState = 'selfInit' --- selfInit > moduleLoad > moduleInit > modulePost > moduleEnv - ---- Default output for the verbose --- @usage Manager.verbose('Hello, World!') --- @tparam string rtn the value that will be returned though verbose output -Manager._verbose = function(rtn) - -- creates one file per game, ie clears file on reset - if game and Manager.setVerbose._output ~= true then Manager.setVerbose._output=true game.write_file('verbose.log',rtn) - elseif game then game.write_file('verbose.log','\n'..rtn,true) end - -- standard print and log, _log is a version of log which is ln1 of control.lua for shorter log lines - if print then print(rtn) end - if _log then _log(rtn) end -end - ---- Used to call the output of the verbose when the current state allows it --- @usage Manager.verbose('Hello, World!') --- @tparam string rtn the value that will be returned though verbose output --- @tparam string action is used to decide which verbose this is error || event etc -Manager.verbose = function(rtn,action) - local settings = Manager.setVerbose - local state = Manager.currentState - if Manager.error and state == Manager.error.__crash then return end - -- if ran in a module the the global moduleName is present - local rtn = type(rtn) == table and serpent.line(rtn) or tostring(rtn) - if moduleName then rtn='['..moduleName..'] '..rtn - else rtn='[FSM] '..rtn end - -- module_verbose is a local override for a file, action is used in the manager to describe an extra type, state is the current state - -- if action is true then it will always trigger verbose - if module_verbose or (action and (action == true or settings[action])) or (not action and settings[state]) then - if type(settings.output) == 'function' then - -- calls the output function, not pcalled as if this fails some thing is very wrong - settings.output(rtn) - else - error('Verbose set for: '..state..' but output can not be called',2) - end - end -end - ---- Main logic for allowing verbose at different stages though out the script --- @function Manager.setVerbose --- @usage Manager.setVerbose{output=log} --- @tparam newTbl settings the table that will be searched for settings to be updated --- @usage Manager.setVerbose[setting] -- returns the value of that setting --- @usage tostring(Manager.setVerbose) -- returns a formated list of the current settings -Manager.setVerbose = setmetatable( - --- Different verbose settings used for setVerbose - -- @table Manager.verboseSettings - -- @tfield boolean selfInit called while the manager is being set up - -- @tfield boolean moduleLoad when a module is required by the manager - -- @tfield boolean moduleInit when and within the initation of a module - -- @tfield boolean modulePost when and within the post of a module - -- @tfield boolean moduleEnv during module runtime, this is a global option set within each module(module_verbose=true ln:1) for fine control - -- @tfield boolean eventRegistered when a module registers its event handlers - -- @tfield boolean errorCaught when an error is caught during runtime - -- @tfield function output can be: print || log || or other function - -- @field _output a constant value that can used to store output data - { - selfInit=true, - moduleLoad=false, - moduleInit=false, - modulePost=false, - moduleEnv=false, - eventRegistered=false, - errorCaught=true, - output=Manager._verbose, - _output={} - }, - { - __metatable=false, - __call=function(tbl,settings) - -- does not allow any new keys, but will override any existing ones - for key,value in pairs(settings) do - if rawget(tbl,key) ~= nil then - Manager.verbose('Verbose for: "'..key..'" has been set to: '..tostring(value)) - rawset(tbl,key,value) - end - end - end, - __newindex=function(tbl,key,value) - -- stops creationg of new keys - error('New settings cannot be added during runtime',2) - end, - __index=function(tbl,key) - -- will always return a value, never nil - return rawget(tbl,key) or false - end, - __tostring=function(tbl) - -- a simple concat function for the settings - local rtn = '' - for key,value in pairs(tbl) do - if type(value) == 'boolean' then - rtn=rtn..key..': '..tostring(value)..', ' - end - end - return rtn:sub(1,-3) - end - } -) --- call to verbose to show start up, will always be present -Manager.verbose(string.rep('__',10)..'| Start: selfInit |'..string.rep('__',10),true) -Manager.verbose('The verbose state is: '..tostring(Manager.setVerbose.selfInit),true) - ---- Used to avoid conflicts in the global table --- @usage global[key] -- used like the normal global table --- @usage global{'foo','bar'} -- sets the default value --- @usage global(true) -- restores global to default --- @usage global(mopdule_name) -- returns that module's global --- @tparam[opt={}] ?table|string|true if table then the default for the global, if a string then the module to get the global of, if true then reset the global to default --- @treturn table the new global table for that module -Manager.global=setmetatable({__defaults={},__global={ - __call=function(tbl,default) return Manager.global(default) end, - __index=function(tbl,key) return rawget(Manager.global(),key) or tbl(key) end, - __newindex=function(tbl,key,value) rawset(Manager.global(),key,value) end, - __pairs=function(tbl) - local tbl = Manager.global() - local function next_pair(tbl,k) - k, v = next(tbl, k) - if type(v) ~= nil then return k,v end - end - return next_pair, tbl, nil - end -}},{ - __call=function(tbl,default,metatable_src) - -- creates varible link to global and module information, use of a metatable is for already formed globals - local Global = _G.global - local metatable = getmetatable(metatable_src) - local moduleName = type(default) == 'string' and default or metatable and metatable._moduleName or moduleName - local module_path = type(default) == 'string' and Manager.loadModules.__load[default] or metatable and metatable._module_path or module_path - -- if there is no name or path then it will return and unedited version of global - if not module_path or not moduleName then return _G.global end - -- edits the link to global to be the corrected dir, path varible is also created - local path = 'global' - for dir in module_path:gmatch('%a+') do - path = path..'.'..dir - if not rawget(Global,dir) then Manager.verbose('Added Global Dir: '..path) rawset(Global,dir,{}) end - Global = rawget(Global,dir) - end - -- the default value is set if there was a default given - if type(default) == 'table' then Manager.verbose('Default global has been set for: global'..string.sub(module_path:gsub('/','.')),2) rawset(rawget(tbl,'__defaults'),tostring(moduleName),default) end - -- if the default value is true then it will reset the global to its default - if default == true and rawget(rawget(tbl,'__defaults'),tostring(moduleName)) then - Manager.verbose('Reset Global Dir to default: '..path) - -- cant set it to be equle otherwise it will lose its global propeity - local function deepcopy(tbl) if type(tbl) ~= 'table' then return tbl end local rtn = {} for key,value in pairs(tbl) do rtn[key] = deepcopy(value) end return rtn end - for key,value in pairs(Global) do rawset(Global,key,nil) end - for key,value in pairs(rawget(rawget(tbl,'__defaults'),tostring(moduleName))) do rawset(Global,key,deepcopy(value)) end - end - -- the metatable is remade if not already present - metatable = metatable or { - __call=function(tbl,default) return Manager.global(default,tbl) end, - __index=function(tbl,key) return rawget(Manager.global(nil,tbl),key) or moduleIndex[key] and Manager.global(key) end, - __newindex=function(tbl,key,value) rawset(Manager.global(nil,tbl),key,value) end, - __pairs=function(tbl) - local tbl = Manager.global(nil,tbl) - local function next_pair(tbl,k) - k, v = next(tbl, k) - if type(v) ~= nil then return k,v end - end - return next_pair, tbl, nil - end, - _module_path=module_path,_moduleName=moduleName - } - return setmetatable(Global,metatable) - end, - __index=function(tbl,key) return rawget(tbl(),key) or rawget(_G.global,key) or moduleIndex[key] and Manager.global(key) end, - __newindex=function(tbl,key,value) rawset(tbl(),key,value) end, - __pairs=function(tbl) - local tbl = Manager.global() - local function next_pair(tbl,k) - k, v = next(tbl, k) - if type(v) ~= nil then return k,v end - end - return next_pair, tbl, nil - end -}) -setmetatable(global,Manager.global.__global) - ---- Creates a sand box envorment and runs a callback in that sand box; provents global pollution --- @function Manager.sandbox --- @usage Manager.sandbox(callback) -- return sandbox, success, other returns from callback --- @tparam function callback the function that will be ran in the sandbox --- @param[opt] env any other params that the function will use --- @usage Manager.sandbox() -- returns and empty sandbox --- @usage Manager.sandbox[key] -- returns the sand box value in that key -Manager.sandbox = setmetatable({ - -- can not use existing keys of _G - verbose=Manager.verbose, - loaded_modules={}, -- this is over riden later - module_verbose=false, - module_exports=false, - _no_error_verbose=true -},{ - __metatable=false, - __index=ReadOnlyManager, - __call=function(tbl,callback,env,...) - if type(callback) == 'function' then - -- creates a new sandbox env - local sandbox = tbl() - local env = type(env) == 'table' and env or {} - local _G_mt = getmetatable(_G) - -- creates a new ENV where it will look in the provided env then the sand box and then _G, new indexes saved to sandbox - local tmp_env = setmetatable({},{__index=function(tbl,key) return env[key] or sandbox[key] or rawget(_G,key) end,newindex=sandbox}) - tmp_env._ENV = tmp_env - tmp_env._G_mt = _G_mt - -- sets the upvalues for the function - local i = 1 - while true do - local name, value = debug.getupvalue(callback,i) - if not name then break else if not value and tmp_env[name] then debug.setupvalue(callback,i,tmp_env[name]) end end - i=i+1 - end - -- runs the callback - setmetatable(_G,{__index=tmp_env,newindex=sandbox}) - local rtn = {pcall(callback,...)} - local success = table.remove(rtn,1) - setmetatable(_G,_G_mt) - -- this is to allow modules to be access with out the need of using Mangaer[name] also keeps global clean - if success then return success, rtn, sandbox - else return success, rtn[1], sandbox end - else return setmetatable({},{__index=tbl}) end - end -}) - ---- Allows access to modules via require and collections are returned as one object --- @function Manager.require --- @usage local Module = Manager.require(ModuleName) --- @usage local Module = Manager.require[ModuleName] --- @usage local SrcData = Manager.require(path) --- @treturn table the module that was required, one object containg submodules for a -Manager.require = setmetatable({ - __require=require -},{ - __metatable=false, - __index=function(tbl,key) return tbl(key,nil,true) end, - __call=function(tbl,path,env,mute,noLoad) - local raw_require = rawget(tbl,'__require') - local env = env or {} - -- runs in a sand box becuase sandbox everything - local success, data = Manager.sandbox(raw_require,env,path) - -- if there was no error then it assumed the path existed and returns the data - if success then return unpack(data) - else - if type(path) ~= 'string' then error('Path supplied must be a string; got: '..type(path),2) return end - local override = {} - local softmod = override - local path = path:find('@') and path:sub(1,path:find('@')-1) or path - -- tries to load the module from the modeul index - if moduleIndex[path] and not noLoad or Manager.loadModules.__load[path] then softmod = Manager.loadModules[path] end - -- will then look for any submodules if there are any; only once every module is loaded - for moduleName,subpath in pairs(moduleIndex) do - if moduleName:find(path) == 1 and moduleName ~= path then - local start, _end = moduleName:find(path) - local subname = moduleName:sub(_end+2) - -- does not add the module if it is a subsubmodule; or the key already exitsts - if not softmod then softmod = {} end - if not subname:find('.',nil,true) and not softmod[subname] then softmod[subname] = Manager.require(moduleName,nil,true,true) end - end - end - -- if there is any keys in the softmod it is returned else the errors with the require error - if override ~= softmod then return softmod end - if mute then return false else error(data,2) end - end - end -}) -require = Manager.require - ---- Loads the modules that are present in the index list --- @function Manager.loadModules --- @usage Manager.loadModules() -- loads all moddules in the index list --- @usage #Manager.loadModules -- returns the number of modules loaded --- @usage tostring(Manager.loadModules) -- returns a formatted list of all modules loaded --- @usage pairs(Manager.loadModules) -- loops over the loaded modules moduleName, module -Manager.loadModules = setmetatable({ - __load=setmetatable({},{__call=function(self,moduleName) - -- check to provent multiple calls - if self[moduleName] then return end - self[moduleName] = true - self = Manager.loadModules - -- loads the module and its dependices if there are not loaded - local load = moduleIndex[moduleName] - if not load then return end - local path = table.remove(load,1) - Manager.verbose('Loading module: "'..moduleName..'"; path: '..path) - -- loads the parent module - if moduleName:find('.',nil,true) then - local revModuleName = moduleName:reverse() - local start, _end = revModuleName:find('.',nil,true) - local parentName = revModuleName:sub(_end+1):reverse() - Manager.verbose('Loading module parent: "'..parentName..'" for: "'..moduleName..'"; path: '..path) - self.__load(parentName) - end - -- loads the dependices - Manager.verbose('Loading module dependices for: "'..moduleName..'"; path: '..path) - for _,depName in pairs(load) do self.__load(depName) end - self.__load[moduleName] = path - -- runs the module in a sandbox env - local success, module, sandbox = Manager.sandbox(Manager.require.__require,{moduleName=setupModuleName(moduleName),module_path=path},path..'/control') - -- extracts the module into a global index table for later use - if success then - -- verbose to notifie of any globals that were attempted to be created - local globals = '' - for key,value in pairs(sandbox) do globals = globals..key..', ' end - if globals ~= '' then Manager.verbose('Globals caught in "'..moduleName..'": '..globals:sub(1,-3),'errorCaught') end - Manager.verbose('Successfully loaded: "'..moduleName..'"; path: '..path) - -- if it is not a table or nil then it will set up a metatable on it - local currentType = type(rawget(self,moduleName)) - if currentType ~= 'nil' and currentType ~= 'table' then - -- if it is a function then it is still able to be called even if more keys are going to be added - -- if it is a string then it will act like one; if it is a number well thats too many metatable indexs - self[moduleName] = setmetatable({__old=self[moduleName]},{ - __call=function(self,...) if type(self.__old) == 'function' then self.__old(...) else return self.__old end end, - __tostring=function(self) return self.__old end, - __concat=function(self,val) return self.__old..val end - }) - end - -- if you prefere module_exports can be used rather than returning the module - local appendAs = sandbox.module_exports or table.remove(module,1) - if not self[moduleName] then self[moduleName] = appendAs -- if nil it just sets the value - else for key,value in pairs(appendAs) do self[moduleName][key] = value end end -- else it appends the new values - -- if there is a module by this name in _G ex table then it will be indexed to the new module - if rawget(_G,moduleName) and type(rawget(self,moduleName)) == 'table' then setmetatable(rawget(_G,moduleName),{__index=self[moduleName]}) end - if type(rawget(self,moduleName)) == 'table' then self[moduleName]._module_path = path self[moduleName]._moduleName = moduleName end - -- loads the submodule for this softmod - Manager.verbose('Loading submodules for: "'..moduleName..'"; path: '..path) - for subModName,_ in pairs(moduleIndex) do - if subModName:find(moduleName) == 1 and subModName ~= moduleName then self.__load(subModName) end - end - else - Manager.verbose('Failed load: "'..moduleName..'"; path: '..path..' ('..module..')','errorCaught') - for event_name,callbacks in pairs(Manager.event) do Manager.verbose('Removed Event Handler: "'..moduleName..'/'..Manager.event.names[event_name],'eventRegistered') callbacks[moduleName] = nil end - end - end}), - __init=setmetatable({},{__call=function(self,moduleName) - -- check to provent multiple calls - if self[moduleName] or not Manager.loadModules.__load[moduleName] then return end - self[moduleName] = true - self = Manager.loadModules - -- calls on_init for each module - -- looks for init so that init or on_init can be used - local data = self[moduleName] - if type(data) == 'table' and data.init and data.on_init == nil then data.on_init = data.init data.init = nil end - if type(data) == 'table' and data.on_init and type(data.on_init) == 'function' then - Manager.verbose('Initiating module: "'..moduleName..'"') - local success, err = Manager.sandbox(data.on_init,{moduleName=setupModuleName(moduleName),module_path=Manager.loadModules.__load[tostring(moduleName)]},data) - if success then - Manager.verbose('Successfully Initiated: "'..moduleName..'"') - else - Manager.verbose('Failed Initiation: "'..moduleName..'" ('..err..')','errorCaught') - end - -- clears the init function so it cant be used in runtime - data.on_init = nil - end - end}), - __post=setmetatable({},{__call=function(self,moduleName) - -- check to provent multiple calls - if self[moduleName] or not Manager.loadModules.__init[moduleName] then return end - self[moduleName] = true - self = Manager.loadModules - -- calls on_post for each module - -- looks for post so that post or on_post can be used - local data = self[moduleName] - if type(data) == 'table' and data.post and data.on_post == nil then data.on_post = data.post data.post = nil end - if type(data) == 'table' and data.on_post and type(data.on_post) == 'function' then - Manager.verbose('Post for module: "'..moduleName..'"') - local success, err = Manager.sandbox(data.on_post,{moduleName=setupModuleName(moduleName),module_path=Manager.loadModules.__load[tostring(moduleName)]},data) - if success then - Manager.verbose('Successful post: "'..moduleName..'"') - else - Manager.verbose('Failed post: "'..moduleName..'" ('..err..')','errorCaught') - end - -- clears the post function so it cant be used in runtime - data.on_post = nil - end - end}) - }, - { - __metatable=false, - __index=function(self,moduleName) - -- will load one module if it is not already loaded, will not init during load state or post - self.__load(moduleName) - if (ReadOnlyManager.currentState == 'moduleLoad') then return end - self.__init(moduleName) - if (ReadOnlyManager.currentState == 'moduleInit') then return end - self.__post(moduleName) - return rawget(self,moduleName) - end, - __call=function(self) - -- goes though the index looking for modules to load - ReadOnlyManager.currentState = 'moduleLoad' - for moduleName,path in pairs(moduleIndex) do self.__load(moduleName) end - -- runs though all loaded modules looking for on_init function; all other modules have been loaded use this to load extra code based on opttial dependies - ReadOnlyManager.currentState = 'moduleInit' - for moduleName,path in pairs(self) do - if moduleName ~= '__load' and moduleName ~= '__init' and moduleName ~= '__post' then self.__init(moduleName) end - end - -- runs though all loaded modules looking for on_post function; all other modules have been loaded and inited, do not load extra code in this time only altar your own data - ReadOnlyManager.currentState = 'modulePost' - for moduleName,path in pairs(self) do - if moduleName ~= '__load' and moduleName ~= '__init' and moduleName ~= '__post' then self.__post(moduleName) end - end - ReadOnlyManager.currentState = 'moduleEnv' - end, - __len=function(tbl) - -- counts the number of loaded modules - local rtn = 0 - for key,value in pairs(tbl) do - rtn = rtn + 1 - end - return rtn-3 - end, - __tostring=function(tbl) - -- a concat of all the loaded modules - local rtn = 'Load Modules: ' - for key,value in pairs(tbl) do - if key ~= '__load' and key ~= '__init' and key ~= '__post' then rtn=rtn..key..', ' end - end - return rtn:sub(1,-3) - end - } -) -Manager.sandbox.loaded_modules = Manager.loadModules - ---- A more detailed replacement for the lua error function to allow for handlers to be added; repleaces default error so error can be used instead of Manager.error --- @function Manager.error --- @usage Manager.error(err) -- calls all error handlers that are set or if none then prints to game and if that fails crashs game --- @usage Manager.error() -- returns an error constant that can be used to crash game --- @usage Manager.error(Manager.error()) -- crashs the game --- @usage Manager.error.addHandler(name,callback) -- adds a new handler if handler returns Manager.error() then game will crash --- @tparam[2] ?string|fucntion err the string to be passed to handlers; if a function it will register a handler --- @tparam[2] function callback if given the err param will be used to given the handler a name --- @usage Manager.error[name] -- returns the handler of that name if present --- @usage #Manager.error -- returns the number of error handlers that are present --- @usage pairs(Manager.error) -- loops over only the error handlers handler_name,hander -Manager.error = setmetatable({ - __crash=false, - __error_call=error, - __error_const={}, - __error_handler=function(handler_name,callback) - -- when handler_name is a string it is expeced that callback is a function; other wise handler_name must be a function - if type(handler_name) == 'string' and type(callback) == 'function' then Manager.error[handler_name]=callback - elseif type(handler_name) == 'function' then table.insert(Manager.error,handler_name) - else Manager.error('Handler is not a function',2) end - end, - in_pcall=function(level) - local level = level and level+1 or 2 - while true do - if not debug.getinfo(level) then return false end - if debug.getinfo(level).name == 'pcall' then return level end - level=level+1 - end - end -},{ - __metatalbe=false, - __call=function(tbl,err,...) - -- if no params then return the error constant - if err == nil then return rawget(tbl,'__error_const') end - -- if the error constant is given crash game - if err == rawget(tbl,'__error_const') then Manager.verbose('Force Crash','errorCaught') rawset(tbl,'__crash',true) rawget(tbl,'__error_call')('Force Crash',2) end - -- other wise treat the call as if its been passed an err string - if not _no_error_verbose or Manager.currentState ~= 'moduleEnv' then Manager.verbose('An error has occurred: '..err,'errorCaught') end - if #tbl > 0 then - -- there is at least one error handler loaded; loops over the error handlers - for handler_name,callback in pairs(tbl) do - local success, err = pcall(callback,err,...) - if not success then Manager.verbose('Error handler: "'..handler_name..'" failed to run ('..err..')','errorCaught') end - -- if the error constant is returned from the handler then crash the game - if err == rawget(tbl,'__error_const') then Manager.verbose('Force Stop by: '..handler_name,'errorCaught') rawset(tbl,'__crash',true) rawget(tbl,'__error_call')('Force Stop by: '..handler_name) end - end - elseif game then - -- there are no handlers loaded so it will print to the game if loaded - Manager.verbose('No error handlers loaded; Default game print used','errorCaught') - game.print(err) - else - -- all else fails it will crash the game with the error code - Manager.verbose('No error handlers loaded; Game not loaded; Forced crash: '..err,'errorCaught') - rawset(tbl,'__crash',true) - rawget(tbl,'__error_call')(err,2) - end - local args = {...} - local trace = args[1] and type(args[1]) == 'number' and args[1]+1 or 2 - if tbl.in_pcall(2) then rawget(tbl,'__error_call')(err,trace) end - end, - __index=function(tbl,key) - -- this allows the __error_handler to be called from many different names - if type(key) ~= 'string' then return end - if key:lower() == 'addhandler' or key:lower() == 'sethandler' or key:lower() == 'handler' or key:lower() == 'register' then return rawget(tbl,'__error_handler') - else rawget(tbl,'__error_call')('Invalid index for error handler; please use build in methods.') end - end, - __newindex=function(tbl,key,value) - -- making a new index adds it as a handler - if type(value) == 'function' then - Manager.verbose('Added Error Handler: "'..key..'"','eventRegistered') - rawset(tbl,key,value) - end - end, - __len=function(tbl) - -- counts the number of handlers there are - local rtn=0 - for handler_name,callback in pairs(tbl) do - rtn=rtn+1 - end - return rtn - end, - __pairs=function(tbl) - -- will not return any of the three core values as part of pairs - local function next_pair(tbl,k) - local v - k, v = next(tbl, k) - if k == '__error_call' or k == '__error_const' or k == '__error_handler' or k == '__crash' or k == 'in_pcall' then return next_pair(tbl,k) end - if type(v) == 'function' then return k,v end - end - return next_pair, tbl, nil - end -}) --- overrides the default error function -error=Manager.error - --- event does work a bit differnt from error, and if event breaks error is the fallback - ---- Event handler that modules can use, each module can register one function per event --- @function Manager.event --- @usage Manager.event[event_name] = callback -- sets the callback for that event --- @usage Manager.event[event_name] = nil -- clears the callback for that event --- @usage Manager.event(event_name,callback) -- sets the callback for that event --- @usage Manager.event[event_name] -- returns the callback for that event or the event id if not registered --- @usage Manager.event(event_name) -- runs all the call backs for that event --- @tparam ?int|string event_name that referes to an event --- @tparam function callback the function that will be set for that event --- @usage Manager.event() -- returns the stop value for the event proccessor, if returned during an event will stop all other callbacks --- @usage #Manager.event -- returns the number of callbacks that are registered --- @usage pairs(Manager.events) -- returns event_id,table of callbacks -Manager.event = setmetatable({ - __stop={}, - __events={}, - __event=script.on_event, - __generate=script.generate_event_name, - __get_handler=script.get_event_handler, - __raise=script.raise_event, - __init=script.on_init, - __load=script.on_load, - __config=script.on_configuration_changed, - events=defines.events, - error_cache={} -},{ - __metatable=false, - __call=function(tbl,event_name,new_callback,...) - if Manager.error.__crash then Manager.error.__error_call('No error handlers loaded; Game not loaded; Forced crash: '..tostring(Manager.error.__crash)) end - -- if no params then return the stop constant - if event_name == nil then return rawget(tbl,'__stop') end - -- if the event name is a table then loop over each value in that table - if type(event_name) == 'table' then - for key,_event_name in pairs(event_name) do tbl(_event_name,new_callback,...) end return - end - -- convert the event name to a number index - event_name = tonumber(event_name) or tbl.names[event_name] - -- if there is a callback present then set new callback rather than raise the event - if type(new_callback) == 'function' then - Manager.event[event_name] = new_callback return - end - -- other wise raise the event and call every callback; no use of script.raise_event due to override - local event_functions = tbl.__events[event_name] - if type(event_functions) == 'table' then - for moduleName,callback in pairs(event_functions) do - -- loops over the call backs and which module it is from - if type(callback) ~= 'function' then error('Invalid Event Callback: "'..event_name..'/'..moduleName..'"') end - local success, err = Manager.sandbox(callback,{moduleName=setupModuleName(moduleName),module_path=Manager.loadModules.__load[tostring(moduleName)]},new_callback,...) - if not success then - local cache = tbl.error_cache - local error_message = 'Event Failed: "'..moduleName..'/'..tbl.names[event_name]..'" ('..err..')' - if not cache[error_message] then Manager.verbose(error_message,'errorCaught') error(error_message) end - if tbl.names[event_name] == 'on_tick' then - if not cache[error_message] then cache[error_message] = {game.tick,1} end - if cache[error_message][1] >= game.tick-10 then cache[error_message] = {game.tick,cache[error_message][2]+1} - else cache[error_message] = nil end - if cache[error_message] and cache[error_message][2] > 100 then - Manager.verbose('There was an error happening every tick for 100 ticks, the event handler has been removed!','errorCaught') - event_functions[moduleName] = nil - end - end - end - -- if stop constant is returned then stop further processing - if err == rawget(tbl,'__stop') then Manager.verbose('Event Haulted By: "'..moduleName..'"','errorCaught') break end - end - end - end, - __newindex=function(tbl,key,value) - -- handles the creation of new event handlers - if type(value) ~= 'function' and type(value) ~= nil then error('Attempted to set a non function value to an event',2) end - -- checks for a global module name that is present - local moduleName = moduleName or 'FSM' - -- converts the key to a number index for the event - Manager.verbose('Added Handler: "'..tbl.names[key]..'"','eventRegistered') - -- checks that the event has a valid table to store callbacks; if its not valid it will creat it and register a real event handler - if not rawget(rawget(tbl,'__events'),key) then - if key == -1 or key == -2 then -- this already has a handler - elseif key < 0 then rawget(tbl,tbl.names[key])(function(...) tbl(key,...) end) - else rawget(tbl,'__event')(key,function(...) tbl(key,...) end) end - rawset(rawget(tbl,'__events'),key,{}) end - -- adds callback to Manager.event.__events[event_id][moduleName] - rawset(rawget(rawget(tbl,'__events'),key),tostring(moduleName),value) - end, - __index=function(tbl,key) - -- few redirect key - local redirect={register=tbl,dispatch=tbl,remove=function(event_id) tbl[event_name]=nil end} - if rawget(redirect,key) then return rawget(redirect,key) end - -- proforms different look ups depentding weather the current module has an event handler registered - if moduleName then - -- first looks for the event callback table and then under the module name; does same but converts the key to a number; no handler regisered so returns the converted event id - return rawget(rawget(tbl,'__events'),key) and rawget(rawget(rawget(tbl,'__events'),key),tostring(moduleName)) - or rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]) and rawget(rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]),tostring(moduleName)) - or rawget(tbl,'names')[key] - else - -- if there is no module present then it will return the full list of regisered handlers; or other wise the converted event id - return rawget(rawget(tbl,'__events'),key) or rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]) or rawget(tbl,'names')[key] - end - end, - __len=function(tbl) - -- counts every handler that is regised not just the the number of events with handlers - local rtn=0 - for event,callbacks in pairs(tbl) do - for module,callback in pairs(callbacks) do - rtn=rtn+1 - end - end - return rtn - end, - __pairs=function(tbl) - -- will loops over the event handlers and not Manager.event - local function next_pair(tbl,k) - k, v = next(rawget(tbl,'__events'), k) - if type(v) == 'table' then return k,v end - end - return next_pair, tbl, nil - end -}) - ---- Sub set to Manger.event and acts as a coverter between event_name and event_id --- @table Manager.event.names --- @usage Manager.event[event_name] -rawset(Manager.event,'names',setmetatable({},{ - __index=function(tbl,key) - if type(key) == 'number' or tonumber(key) then - -- if it is a number then it will first look in the cache - if rawget(tbl,key) then return rawget(tbl,key) end - -- if it is a core event then it will simply return - if key == -1 then rawset(tbl,key,'__init') - elseif key == -2 then rawset(tbl,key,'__load') - elseif key == -3 then rawset(tbl,key,'__config') - else - -- if it is not a core event then it does a value look up on Manager.events aka defines.events - for event,id in pairs(rawget(Manager.event,'events')) do - if id == key then rawset(tbl,key,event) end - end - end - -- returns the value from the cache after being loaded in - return rawget(tbl,key) - -- if it is a string then no reverse look up is required - else - if key == 'on_init' or key == 'init' or key == '__init' then return -1 - elseif key == 'on_load' or key == 'load' or key == '__load' then return -2 - elseif key == 'on_configuration_changed' or key == 'configuration_changed' or key == '__config' then return -3 - else return rawget(rawget(Manager.event,'events'),key) end - end - end -})) - -script.on_init(function(...) - Manager.verbose('____________________| SubStart: script.on_init |____________________') - setmetatable(global,Manager.global.__global) - local names = {} - for name,default in pairs(Manager.global.__defaults) do table.insert(names,name) end - Manager.verbose('Global Tables: '..table.concat(names,', ')) - for name,default in pairs(Manager.global.__defaults) do global(name)(true) end - Manager.event(-1,...) - Manager.verbose('____________________| SubStop: script.on_init |____________________') -end) - -script.on_load(function(...) - Manager.verbose('____________________| SubStart: script.on_load |____________________') - setmetatable(global,Manager.global.__global) - local names = {} - for name,default in pairs(Manager.global.__defaults) do table.insert(names,name) end - Manager.verbose('Global Tables: '..table.concat(names,', ')) - --for name,default in pairs(Manager.global.__defaults) do Manager.verbose('Global '..name..' = '..serpent.line(Manager.global(name))) end - Manager.event(-2,...) - Manager.verbose('____________________| SubStop: script.on_load |____________________') -end) ---over rides for the base values; can be called though Event -Event=setmetatable({},{__call=Manager.event,__index=function(tbl,key) return Manager.event[key] or script[key] or error('Invalid Index To Table Event') end}) -script.mod_name = setmetatable({},{__index=_G.moduleName}) -script.on_event=Manager.event -script.raise_event=Manager.event -script.on_init=function(callback) Manager.event(-1,callback) end -script.on_load=function(callback) Manager.event(-2,callback) end -script.on_configuration_changed=function(callback) Manager.event(-3,callback) end -script.get_event_handler=function(event_name) return type(Manager.event[event_name]) == 'function' and Manager.event[event_name] or nil end -script.generate_event_name=function(event_name) local event_id = Manager.event.__generate() local event_name = event_name or event_id Manager.event.events[event_name]=event_id return event_id end --- to do set up nth tick - -return ReadOnlyManager \ No newline at end of file diff --git a/control.lua b/control.lua index 1c352a55df..5c7db20b12 100644 --- a/control.lua +++ b/control.lua @@ -1,14 +1,45 @@ --- not_luadoc=true -function _log(...) log(...) end -- do not remove this is used for smaller verbose lines -Manager = require("FactorioSoftmodManager") -Manager.setVerbose{ - selfInit=true, -- called while the manager is being set up - moduleLoad=false, -- when a module is required by the manager - moduleInit=false, -- when and within the initation of a module - modulePost=false, -- when and within the post of a module - moduleEnv=false, -- during module runtime, this is a global option set within each module for fine control - eventRegistered=false, -- when a module registers its event handlers - errorCaught=true, -- when an error is caught during runtime - output=Manager._verbose -- can be: can be: print || log || other function +-- If you're looking to configure anything, you want config.lua. Nearly everything in this file is dictated by the config. + +-- Info on the data lifecycle and how we use it: https://github.com/Refactorio/RedMew/wiki/The-data-lifecycle +require 'resources.data_stages' +_LIFECYCLE = _STAGE.control -- Control stage + +-- Overrides the _G.print function +require 'utils.print_override' + +-- Omitting the math library is a very bad idea +require 'utils.math' + +-- Global Debug and make sure our version file is registered +Debug = require 'utils.debug' +require 'resources.version' + +local files = { + 'modules.commands.me', + 'modules.commands.kill', + 'modules.commands.admin-chat', + 'modules.commands.tag', + 'modules.commands.teleport', + 'modules.commands.cheat-mode', + 'modules.commands.interface', + 'modules.commands.help', } -Manager() -- can be Manager.loadModules() if called else where \ No newline at end of file + +-- Loads all files in array above and logs progress +local total_files = string.format('%3d',#files) +local errors = {} +for index,path in pairs(files) do + log(string.format('[INFO] Loading files %3d/%s',index,total_files)) + local success,file = pcall(require,path) + -- error checking + if not success then + log('[ERROR] Failed to load file: '..path) + log('[ERROR] '..file) + table.insert(errors,'[ERROR] '..path..' :: '..file) + elseif type(file) == 'string' and file:find('not found') then + log('[ERROR] File not found: '..path) + table.insert(errors,'[ERROR] '..path..' :: Not Found') + end +end +log('[INFO] All files loaded with '..#errors..' errors:') +for _,error in pairs(errors) do log(error) end -- logs all errors again to make it make it easy to find \ No newline at end of file diff --git a/expcore/commands.lua b/expcore/commands.lua new file mode 100644 index 0000000000..432e2680c0 --- /dev/null +++ b/expcore/commands.lua @@ -0,0 +1,677 @@ +--- Factorio command making module that makes commands with better parse and more modularity +-- @author Cooldude2606 +-- @module Commands +--[[ +>>>>Example Authenticator: + + -- adds an admin only authenticator where if a command has the tag admin_only: true + -- then will only allow admins to use this command + Commands.add_authenticator(function(player,command,tags,reject) + if tags.admin_only then -- the command has the tag admin_only set to true + if player.admin then -- the player is an admin + return true -- no return is needed for success but is useful to include + else -- the player is not admin + -- you must return to block a command, they are a few ways to do this: + -- return false -- most basic and has no custom error message + -- return reject -- sill no error message and is here in case people dont know its a function + -- reject() -- rejects the player, return not needed but please return if possible + -- return reject() -- rejects the player and has a failsafe return to block command + -- reject('This command is for admins only!') -- reject but with custom error message, return not needed but please return if possible + return reject('This command is for admins only!') -- reject but with custom error message and has return failsafe + end + else -- command does not require admin + return true -- no return is needed for success but is useful to include + end + end) + +>>>>Example Parse: + + -- adds a parse that will cover numbers within the given range + -- input, player and reject are common to all parse functions + -- range_min and range_max are passed to the function from add_param + 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 -- check if it is nil or out of the range + -- invalid input for we will reject the input, they are a few ways to do this: + -- dont return anything -- will print generic input error + -- return false -- this WILL NOT reject the input as false can be a valid output + -- return reject -- will print generic input error + -- return reject() -- will print generic input error with no please check type message + -- reject() -- if you do not return the value then they will be a duplicate message + return reject('Number entered is not in range: '..range_min..', '..range_max) -- reject with custom error + else + return rtn -- returns the number value this will be passed to the command callback + end + end) + +>>>>Example Command: + + -- adds a command that will print the players name a given number of times + -- and can only be used by admin to show how auth works + Commands.new_command('repeat-name','Will repeat you name a number of times in chat.') -- creates the new command with the name "repeat-name" and a help message + :add_param('repeat-count',false,'number-range-int',1,5) -- adds a new param called "repeat-count" that is required and is type "number_range_int" the name can be used here as add_parse was used + :add_param('smiley',true,function(input,player,reject) -- this param is optional and has a custom parse function where add_parse was not used before hand + if not input then return end -- when they is an optional param input may be nil, you can return a default value here, but using nil will allow add_defaults to pick a default + if input:lower() == 'true' or input:lower() == 'yes' then + return true -- the value is truthy so true is returned + else + -- it should be noted that this function will be ran even when the param is not present + -- in this case input is nil and so a default can be returned, see above + return false -- false is returned other wise + end + end) + :add_defaults{smiley=false} -- adds false as the default for smiley + :add_tag('admin_only',true) -- adds the tag admin_only: true which because of the above authenticator means you must be added to use this command + :add_alias('name','rname') -- adds two aliases "name" and "rname" for this command which will work as if the ordinal name was used + --:enable_auto_concat() -- cant be used due to optional param here, but this will make all user input params after the last expected one be added to the last expected one + :register(function(player,repeat_count,smiley,raw) -- this registers the command to the game, notice the params are what were defined above + -- prints the raw input to show that it can be used + game.print(player.name..' used a command with input: '..raw) + -- some smiley logic + local msg + if smiley then + msg = ':) '..player.name + else + msg = ') '..player.name + end + -- prints your name alot + for i = 1,repeat_count do + Commands.print(i..msg) -- this command is an alias for ("expcore.common").player_return it will print any value to the player/server not just strings + end + -- if you wanted to you can return some values here + -- no return -- only success message is printed + -- Commands.error('optional message here') -- prints an error message + -- return Commands.error('optional message here') -- prints an error message, and stops success message being printed + -- Commands.success('optional message here') -- same as below but success message is printed twice DONT DO this + -- return Commands.success('optional message here') -- prints your message and then the success message + end) + +>>>>Examples With No Comments (for example formatting): + + Commands.add_authenticator(function(player,command,tags,reject) + if tags.admin_only then + if player.admin then + return true + else + return reject('This command is for admins only!') + end + else + return true + end + end) + + 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 + if not rtn or rtn < range_min or rtn > range_max then + return reject('Number entered is not in range: '..range_min..', '..range_max) + else + return rtn + end + end) + + Commands.new_command('repeat-name','Will repeat you name a number of times in chat.') + :add_param('repeat-count',false,'number_range_int',1,5) + :add_param('smiley',true,function(input,player,reject) + if not input then return end + if input:lower() == 'true' or input:lower() == 'yes' then + return true + else + return false + end + end) + :add_defaults{smiley=false} + :add_tag('admin_only',true) + :add_alias('name','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 i = 1,repeat_count do + Commands.print(i..msg) + end + end) + +>>>>Functions List (see function for more detail): + Commands.add_authenticator(callback) --- Adds an authorization callback, function used to check if a player if allowed to use a command + Commands.remove_authenticator(callback) --- Removes an authorization callback, see add_authenticator for adding them + Commands.authorize(player,command_name) --- Mostly used internally, calls all authorization callbacks, returns if the player is authorized + + Commands.get(player) --- Gets all commands that a player is allowed to use, game commands not included + Commands.search(keyword,allowed_player) --- Searches command names and help messages to find possible commands, game commands included + + Commands.add_parse(name,callback) --- Adds a parse function which can be called by name rather than callback (used in add_param) + Commands.remove_parse(name) --- Removes a parse function, see add_parse for adding them + Commands.parse(name,input,player,reject,...) --- Intended to be used within other parse functions, runs a parse and returns success and new value + + Commands.add_command(name,help) --- Creates a new command object to added details to, note this does not register the command to the game + Commands._prototype:add_param(name,optional,parse,...) --- Adds a new param to the command this will be displayed in the help and used to parse the input + Commands._prototype:add_defaults(defaults) --- Adds default values to params only matters if the param is optional + Commands._prototype:add_tag(name,value) --- Adds a tag to the command which is passed via the tags param to the authenticators, can be used to assign command roles or type + Commands._prototype:add_alias(...) --- Adds an alias or multiple that will also be registered with the same callback, eg /teleport can be /tp with both working + Commands._prototype:enable_auto_concat() --- Enables auto concatenation of any params on the end so quotes are not needed for last param + Commands._prototype:register(callback) --- Adds the callback to the command and registers all aliases, params and help message with the game + + Commands.error(error_message,play_sound) --- Sends an error message to the player and returns a constant to return to command handler to exit execution + Commands.internal_error(success,command_name,error_message) --- Sends an error to the player and logs the error, used with pcall within command handler please avoid direct use + Commands.success(value) --- Sends a value to the player, followed by a command complete message + Commands.print(value) --- Short cut for player_return, will return any value given to it (not just strings) in a string format to the player/server + + Commands.run_command(command_event) --- Main event function that is ran for all commands, used internally please avoid direct use +]] + +local Game = require 'utils.game' +local player_return = require('expcore.common').player_return + +local Commands = { + defines={ -- common values are stored error like signals + error='CommandError', + unauthorized='CommandErrorUnauthorized', + success='CommandSuccess' + }, + commands={}, -- custom command data will be stored here + authorization_fail_on_error=false, -- set true to have authorize fail if a callback fails to run, more secure + authorization={}, -- custom function are stored here which control who can use what commands + parse_functions={}, -- used to store default functions which are common parse function such as player or number in range + print=player_return, -- short cut so player_return does not need to be required in every module + _prototype={}, -- used to store functions which gets added to new custom commands +} + +--- Adds an authorization callback, function used to check if a player if allowed to use a command +-- @see Commands.authorize +-- @tparam callback function the callback you want to register as an authenticator +-- callback param - player: LuaPlayer - the player who is trying to use the command +-- callback param - command: string - the name of the command which is being used +-- callback param - tags: table - any tags which have been set for the command +-- callback param - reject: function(error_message?: string) - call to fail authorize with optional error message +-- @treturn number the index it was inserted at use to remove the callback, if anon function used +function Commands.add_authenticator(callback) + table.insert(Commands.authorization,callback) + return #Commands.authorization +end + +--- Removes an authorization callback +-- @see Commands.add_authenticator +-- @tparam callback function|number the callback to remove, an index returned by add_authenticator can be passed +-- @treturn boolean was the callback found and removed +function Commands.remove_authenticator(callback) + if type(callback) == 'number' then + -- if a number is passed then it is assumed to be the index + if Commands.authorization[callback] then + table.remove(Commands.authorization,callback) + return true + end + else + -- will search the array and remove the key + local index + for key,value in pairs(Commands.authorization) do + if value == callback then + index = key + break + end + end + -- if the function was found it is removed + if index then + table.remove(Commands.authorization,index) + return true + end + end + return false +end + +--- Mostly used internally, calls all authorization callbacks, returns if the player is authorized +-- @tparam player LuaPlayer the player that is using the command, passed to callbacks +-- @tparam command_name string the command that is being used, passed to callbacks +-- @treturn[1] boolean true player is authorized +-- @treturn[1] string commands const for success +-- @treturn[2] boolean false player is unauthorized +-- @treturn[2] string|locale_string the reason given by the authenticator +function Commands.authorize(player,command_name) + local failed + if not player then return true end + local command_data = Commands.commands[command_name] + if not command_data then return false end + + -- function passed to authorization callback to make it simpler to use + local auth_fail = function(error_message) + failed = error_message or {'expcore-commands.unauthorized'} + return Commands.defines.unauthorized + end + + -- loops over each authorization callback if any return false or unauthorized command will fail + for _,callback in pairs(Commands.authorization) do + -- callback(player: LuaPlayer, command: string, tags: table, reject: function(error_message?: string)) + local success, rtn = pcall(callback,player,command_name,command_data.tags,auth_fail) + -- error handler + if not success then + -- the callback failed to run + log('[ERROR] Authorization failed: '..rtn) + if Commands.authorization_fail_on_error then + failed = 'Internal Error' + end + elseif rtn == false or rtn == Commands.defines.unauthorized or rtn == auth_fail or failed then + -- the callback returned unauthorized, failed be now be set if no value returned + failed = failed or {'expcore-commands.unauthorized'} + break + end + end + + -- checks if the authorization failed + if failed then + return false, failed + else + return true, Commands.defines.success + end +end + +--- Gets all commands that a player is allowed to use, game commands not included +-- @tparam[opt] player LuaPlayer 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 +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 included +-- @tparam keyword string the word which you are trying to find +-- @tparam[opt] allowed_player LuaPlayer 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 player if player given +function Commands.search(keyword,allowed_player) + local custom_commands = Commands.get(allowed_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',name,command_data.help,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 formated + matches[name] = { + name=name, + help=description, + description='', + aliases={} + } + end + end + return matches +end + +--- Adds a parse function which can be called by name rather than callback (used in add_param) +-- nb: this is not needed as you can use the callback directly this just allows it to be called by name +-- @tparam name string the name of the parse, should be the type like player or player_alive, must be unique +-- @tparam callback function the callback that is ran to parse the input +-- parse param - input: string - the input given by the user for this param +-- parse param - player: LuaPlayer - the player who is using the command +-- parse param - reject: function(error_message) - use this function to send a error to the user and fail running +-- parse return - the value that will be passed to the command callback, must not be nil and if reject then command is not run +-- @treturn boolean was the parse added will be false if the name is already used +function Commands.add_parse(name,callback) + if Commands.parse_functions[name] then + return false + else + Commands.parse_functions[name] = callback + return true + end +end + +--- Removes a parse function, see add_parse for adding them +-- @tparam name string the name of the parse to remove +function Commands.remove_parse(name) + Commands.parse_functions[name] = nil +end + +--- Intended to be used within other parse functions, runs a parse and returns success and new value +-- @tparam name string the name of the parse to call, must be registered and cant be a function +-- @tparam input string the input to pass to the parse, will always be a string but might not be the orginal input +-- @treturn any the new value for the input, may be nil, if nil then either there was an error or input was nil +function Commands.parse(name,input,player,reject,...) + if not Commands.parse_functions[name] then return end + local success,rtn = pcall(Commands.parse_functions[name],input,player,reject,...) + if not success then error(rtn,2) return end + if not rtn then return end + if rtn == Commands.defines.error then return end + return rtn +end + +--- Creates a new command object to added details to, note this does not register the command to the game +-- @tparam name string the name of the command to be created +-- @tparam help string the help message for the command +-- @treturn Commands._prototype this will be used with other functions to generate the command functions +function Commands.new_command(name,help) + local command = setmetatable({ + name=name, + help=help, + callback=function() Commands.internal_error(false,name,'No callback registered') end, + auto_concat=false, + min_param_count=0, + max_param_count=0, + tags={}, -- stores tags that can be used by auth + aliases={}, -- n = name: string + 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 name string the name of the new param that is being added to the command +-- @tparam[opt=true] optional is this param required for this command, these must be after all required params +-- @tparam[opt=pass through] parse function this function will take the input and return a new (or same) value +-- @param[opt] ... extra args you want to pass to the parse function; for example if the parse is general use +-- parse param - input: string - the input given by the user for this param +-- parse param - player: LuaPlayer - the player who is using the command +-- parse param - reject: function(error_message) - use this function to send a error to the user and fail running +-- parse return - the value that will be passed to the command callback, must not be nil and if reject then command is not run +-- @treturn Commands._prototype pass through to allow more functions to be called +function Commands._prototype:add_param(name,optional,parse,...) + if optional ~= false then optional = true end + parse = parse or function(string) return string end + self.params[name] = { + optional=optional, + parse=parse, + 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 + +--- Adds default values to params only matters if the param is optional, if default value is a function it is called with param player +-- @tparam defaults table a table keyed by the name of the param with the value as the default value {paramName=defaultValue} +-- callback param - player: LuaPlayer - the player using the command, default value does not need to be a function callback +-- @treturn Commands._prototype pass through to allow more functions to be called +function Commands._prototype:add_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 tag to the command which is passed via the tags param to the authenticators, can be used to assign command roles or type +-- @tparam name string the name of the tag to be added; used to keep tags separate +-- @tparam value any the tag that you want can be anything that the authenticators are expecting +-- nb: if value is nil then name will be assumed as the value and added at a numbered index +-- @treturn Commands._prototype pass through to allow more functions to be called +function Commands._prototype:add_tag(name,value) + if not value then + -- value not given so name is the value + table.insert(self.tags,name) + else + -- name is given so its key: value + self.tags[name] = value + end + return self +end + +--- Adds an alias or multiple that will also be registered with the same callback, eg /teleport can be /tp with both working +-- @usage command:add_alias('aliasOne','aliasTwo','etc') +-- @tparam ... string any amount of aliases that you want this command to be callable with +-- @treturn Commands._prototype pass through to allow more functions to be called +function Commands._prototype:add_alias(...) + for _,alias in pairs({...}) do + table.insert(self.aliases,alias) + --Commands.alias_map[alias] = self.name + end + return self +end + +--- Enables auto concatenation of any params on the end so quotes are not needed for last param +-- nb: this will disable max param checking as they will be concated onto the end of that last param +-- this can be useful for reasons or longs text, can only have one per command +-- @treturn Commands._prototype pass through to allow more functions to be called +function Commands._prototype:enable_auto_concat() + self.auto_concat = true + return self +end + +--- Adds the callback to the command and registers all aliases, params and help message with the game +-- nb: this must be the last function ran on the command and must be done for the command to work +-- @tparam callback function the callback for the command, will receive the player running command, and params added with add_param +-- callback param - player: LuaPlayer - the player who used the command +-- callback param - ... - any params which were registered with add_param in the order they where registered +-- callback param - raw: string - the raw input from the user, comes after every param added with add_param +function Commands._prototype:register(callback) + -- generates a description to be used + self.callback = callback + 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 + -- registers the command under its own name + commands.add_command(self.name,{'expcore-commands.command-help',description,self.help},function(command_event) + local success, err = pcall(Commands.run_command,command_event) + if not success then log('[ERROR] command/'..self.name..' :: '..err) end + end) + -- 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,{'expcore-commands.command-help',description,self.help},function(command_event) + command_event.name = self.name + local success, err = pcall(Commands.run_command,command_event) + Commands.internal_error(success,self.name,err) + end) + end + end +end + +--- Sends an error message to the player and returns a constant to return to command handler to exit execution +-- nb: this is for non fatal errors meaning there is no log of this event +-- nb: if reject is giving as a param to the callback use that instead +-- @usage return Commands.error() +-- @tparam[opt] error_message string an optional error message that can be sent to the user +-- @tparam[opt] play_sound string the sound to play for the error +-- @treturn Commands.defines.error return this to command handler to exit execution +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 with pcall within command handler please avoid direct use +-- nb: use error(error_message) within your callback to trigger do not trigger directly as the handler may still continue +-- @tparam success boolean the success value returned from pcall, or just false to trigger error +-- @tparam command_name string the name of the command this is used within the log +-- @tparam error_message string 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 +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 + +--- Sends a value to the player, followed by a command complete message +-- nb: either return a value from your callback to trigger or return the return of this to prevent two messages +-- @tparam[opt] value any the value to return to the player, if nil then only success message returned +-- @treturn Commands.defines.success return this to the command handler to prevent two success messages +function Commands.success(value) + if value then player_return(value) end + player_return({'expcore-commands.command-ran'},'cyan') + return Commands.defines.success +end + +-- logs command usage to file +local function command_log(player,command,comment,params,raw,details) + game.write_file('log/commands.log',game.table_to_json{ + player_name=player.name, + command_name=command.name, + comment=comment, + details=details, + params=params, + raw=raw + }..'\n',true,0) +end + +--- Main event function that is ran for all commands, used internally please avoid direct use +-- @tparam command_event table passed directly from command event from the add_command function +function Commands.run_command(command_event) + local command_data = Commands.commands[command_event.name] + local player = Game.get_player_by_index(command_event.player_index) + + -- checks if 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 + + -- null param check + 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 + + -- splits the arguments + local input_string = command_event.parameter or '' + local quote_params = {} -- stores any " " params + input_string = input_string:gsub('"[^"]-"',function(w) + -- finds all " " params are removes spaces for the next part + local no_spaces = w:gsub('%s','_') + local no_quotes = w:sub(2,-2) + quote_params[no_spaces]=no_quotes + if command_data.auto_concat then + -- if auto concat then dont remove quotes as it should be included later + quote_params[no_spaces]=w + end + return no_spaces + end) + + local raw_params = {} -- stores all params + local param_number = 0 + local last_index = 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,input_string) + Commands.error({'expcore-commands.invalid-inputs',command_data.name,command_data.description}) + return + else + -- concat to the last param + if quote_params[word] then + -- if it was a " " param then the spaces are re added now + 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 + -- all words are added to an array + if quote_params[word] then + -- if it was a " " param then the spaces are re added now + table.insert(raw_params,quote_params[word]) + last_index = last_index + 1 + else + table.insert(raw_params,word) + last_index = last_index + 1 + end + end + end + + -- checks 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,input_string) + Commands.error({'expcore-commands.invalid-inputs',command_data.name,command_data.description}) + return + end + + -- parses 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 type(parse_callback) == 'string' then + -- if its a string this allows it to be pulled from the common store + parse_callback = Commands.parse_functions[parse_callback] + end + if not type(parse_callback) == 'function' then + -- if its not a function throw and error + 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,command_event.parameter,tostring(param_data.parse)) + return + end + -- used below as the reject function + local parse_fail = function(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,parse_fail,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,command_event.parameter,param_parsed) + end + if param_data.optional == true and param_parsed == nil then + -- if it is optional and param is nil then it is set to default + param_parsed = param_data.default + if type(param_parsed) == 'function' then + -- player: LuaPlayer + 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,command_event.parameter,param_parsed) + end + end + elseif param_parsed == nil or param_parsed == Commands.defines.error or param_parsed == parse_fail then + -- no value was returned or error was returned, if nil then give generic error + if not param_parsed == Commands.defines.error then + command_log(player,command_data,'Invalid Param Given',raw_params,input_string,param_name) + Commands.error{'expcore-commands.command-error-param-format',param_name,'please make sure it is the correct type'} + end + return + end + -- adds the param to the table to be passed to the command callback + table.insert(params,param_parsed) + index=index+1 + end + + -- runs the command + -- player: LuaPlayer, ... command params, raw: string + table.insert(params,input_string) + local success, err = pcall(command_data.callback,player,unpack(params)) + if Commands.internal_error(success,command_data.name,err) then + return command_log(player,command_data,'Internal Error: Command Callback Fail',params,command_event.parameter,err) + end + if err ~= Commands.defines.error and err ~= Commands.defines.success and err ~= Commands.error and err ~= Commands.success then + Commands.success(err) + end + command_log(player,command_data,'Success',raw_params,input_string) +end + +return Commands \ No newline at end of file diff --git a/expcore/common.lua b/expcore/common.lua new file mode 100644 index 0000000000..23d3678d09 --- /dev/null +++ b/expcore/common.lua @@ -0,0 +1,57 @@ +local Colours = require 'resources.color_presets' +local Game = require 'utils.game' + +local Public = {} + +--- Compare types faster for faster validation of prams +-- @usage is_type('foo','string') -- return true +-- @usage is_type('foo') -- return false +-- @param v 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 +function Public.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 + +--- Will return a value of any type to the player/server console, allows colour for in-game players +-- @usage player_return('Hello, World!') -- returns 'Hello, World!' to game.player or server console +-- @usage player_return('Hello, World!','green') -- returns 'Hello, World!' to game.player with colour green or server console +-- @usage player_return('Hello, World!',nil,player) -- returns 'Hello, World!' to the given player +-- @param value any 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 +function Public.player_return(value,colour,player) + colour = Public.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 Public.type_check(value,'table') then + if Public.type_check(value.__self,'userdata') then + -- value is userdata + returnAsString = 'Cant Display Userdata' + elseif Public.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 = serpent.block(value) + end + elseif Public.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 + +return Public \ No newline at end of file diff --git a/expcore/common_parse.lua b/expcore/common_parse.lua new file mode 100644 index 0000000000..8c71999635 --- /dev/null +++ b/expcore/common_parse.lua @@ -0,0 +1,142 @@ +local Commands = require 'expcore.commands' +local Game = require 'utils.game' + +--[[ +>>>>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 +]] + +Commands.add_parse('boolean',function(input,player,reject) + 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 + input = input:lower() + for option in options do + if input == option:lower() then + return true + end + end + return reject{'reject-string-options',options:concat(', ')} +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.get_player_from_any(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) \ No newline at end of file diff --git a/expcore/locale/de.cfg b/expcore/locale/de.cfg new file mode 100644 index 0000000000..e872b32599 --- /dev/null +++ b/expcore/locale/de.cfg @@ -0,0 +1,9 @@ +[expcore-commands] +unauthorized=401 - Unbefugt: Zugang verweigert. Du hast keinen Zugriff auf diese Befehle! +reject-number-range=ungültige Reichweite, Min: __1__, Max: __2__ +reject-string-max-length=ungültige Länge, Max: __1__ +reject-player=ungültiger Spieler Name, __1__ , Versuche "Tab" zu benutzen, damit sich der Name automatisch vervollständigt. +reject-player-online=Der betroffene Spieler ist offline, Befehl konnte nicht ausgeführt werden. +reject-player-alive=Der betroffene Spieler ist Tod, Befehl konnte nicht ausgeführt werden. +invalid-inputs=ungültige Eingabe, /__1__ __2__ +command-ran=Befehl ausgeführt. \ No newline at end of file diff --git a/expcore/locale/en.cfg b/expcore/locale/en.cfg new file mode 100644 index 0000000000..b33e7ee3f3 --- /dev/null +++ b/expcore/locale/en.cfg @@ -0,0 +1,17 @@ +[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=Invaild 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=Invaild Force Name +reject-surface=Invaild surface 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__ \ No newline at end of file diff --git a/expcore/locale/nl.cfg b/expcore/locale/nl.cfg new file mode 100644 index 0000000000..21e1ed5865 --- /dev/null +++ b/expcore/locale/nl.cfg @@ -0,0 +1,9 @@ +[expcore-commands] +unauthorized=401 - Onbevoegd: toegang wordt geweigerd vanwege ongeldige inloggegevens +reject-number-range=Onjuiste radius, Min: __1__, Max: __2__ +reject-string-max-length=Onjuiste lengte, Max: __1__ +reject-player=Onjuiste naam, __1__ , probeer tab te gebruiken om de naam automatisch in te vullen +reject-player-online=Speler is offline. +reject-player-alive=Speler is dood. +invalid-inputs=Onjuiste invoer, /__1__ __2__ +command-ran=Commando uitgevoerd. diff --git a/expcore/locale/sv-SE.cfg b/expcore/locale/sv-SE.cfg new file mode 100644 index 0000000000..078b7f17e2 --- /dev/null +++ b/expcore/locale/sv-SE.cfg @@ -0,0 +1,9 @@ +[expcore-commands] +unauthorized=401 - Otillåten: Tillgång nekas på grund av otillräcklig säkerhetsprövning. +reject-number-range=Invalid räckvid, Min: __1__, Max: __2__ +reject-string-max-length=ogiltig längd, Max: __1__ +reject-player=Ogiltigt spelarnamn, __1__ , försök använda tab-tangenten för att auto-slutföra namn. +reject-player-online=Spelare är offline. Kommando misslyckades med att köras. +reject-player-alive=Spelare är död. Kommando misslyckades med att köras. +invalid-inputs=Igiltig inmatning, /__1__ __2__ +command-ran=Kommandot slutfört diff --git a/locale/en/commands-local.cfg b/locale/en/commands-local.cfg new file mode 100644 index 0000000000..ddf4213b18 --- /dev/null +++ b/locale/en/commands-local.cfg @@ -0,0 +1,10 @@ +[exp-commands] +kill-already-dead=You are already dead. +admin-chat-format=[Admin Chat] [color=__3__]__1__: __2__ +tp-no-position-found=No position to teleport to was found, please try again later. +tp-to-self=Player can not be teleported to themselves. +chelp-title=Help results for "__1__": +chelp-footer=(__1__ results found; page __2__ of __3__) +chelp-format=/__1__ __2__ - __3__ __4__ +chelp-alias=Alias: __1__ +chelp-out-of-range=__1__ is an invalid page number. \ No newline at end of file diff --git a/locale/en/expcore.cfg b/locale/en/expcore.cfg new file mode 100644 index 0000000000..b33e7ee3f3 --- /dev/null +++ b/locale/en/expcore.cfg @@ -0,0 +1,17 @@ +[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=Invaild 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=Invaild Force Name +reject-surface=Invaild surface 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__ \ No newline at end of file diff --git a/modules/ExpGamingCore/Command/locale/de.cfg b/modules/ExpGamingCore/Command/locale/de.cfg deleted file mode 100644 index 1ea17d9b4a..0000000000 --- a/modules/ExpGamingCore/Command/locale/de.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[ExpGamingCore_Command] -unauthorized=401 - Unbefugt: Zugang verweigert. Du hast keinen Zugriff auf diese Befehle! -invalid-inputs=ungültige Eingabe, /__1__ __2__ -invalid-range=ungültige Reichweite, Min: __1__, Max: __2__ -invalid-length=ungültige Länge, Max: __1__ -invalid-player=ungültiger Spieler Name, __1__ , Versuche "Tab" zu benutzen, damit sich der Name automatisch vervollständigt. -offline-player=Der betroffene Spieler ist offline, Befehl konnte nicht ausgeführt werden. -dead-player=Der betroffene Spieler ist Tod, Befehl konnte nicht ausgeführt werden. -command-ran=Befehl ausgeführt. \ No newline at end of file diff --git a/modules/ExpGamingCore/Command/locale/en.cfg b/modules/ExpGamingCore/Command/locale/en.cfg deleted file mode 100644 index bdc9fb418a..0000000000 --- a/modules/ExpGamingCore/Command/locale/en.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[ExpGamingCore_Command] -unauthorized=Unauthorized, Access is denied due to invalid credentials -error-string-list=Invalid Option, Must be one of: __1__ -error-string-len=Invalid Length, Max: __1__ -error-number=Invalid Number -error-number-range=Invalid Range, Min (exclusive): __1__, Max (inclusive): __2__ -error-player=Invaild Player Name, __1__ ,try using tab key to auto-complete the name -error-player-online=Player is offline. -error-player-alive=Player is dead. -error-player-rank=Player is of Higher Rank. -invalid-inputs=Invalid Input, /__1__ __2__ -invalid-parse=Invalid Input, There was a problem prasing the paramaters -command-ran=Command Complete -command-fail=Command failed to run: __1__ \ No newline at end of file diff --git a/modules/ExpGamingCore/Command/locale/fr.cfg b/modules/ExpGamingCore/Command/locale/fr.cfg deleted file mode 100644 index 5d271090dd..0000000000 --- a/modules/ExpGamingCore/Command/locale/fr.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[ExpGamingCore_Command] -unauthorized=401 - Unauthorized: Access is denied due to invalid credentials -invalid-inputs=Invalid Input, /__1__ __2__ -invalid-range=Invalid Range, Min: __1__, Max: __2__ -invalid-length=Invalid Length, Max: __1__ -invalid-player=Invaild Player Name, __1__ ,try using tab key to auto-complete the name -offline-player=Player is offline, Command Failed To Run -dead-player=Player is dead, Command Failed To Run -command-ran=Command Complete \ No newline at end of file diff --git a/modules/ExpGamingCore/Command/locale/nl.cfg b/modules/ExpGamingCore/Command/locale/nl.cfg deleted file mode 100644 index 3742ef49b0..0000000000 --- a/modules/ExpGamingCore/Command/locale/nl.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[ExpGamingCore_Command] -unauthorized=401 - Onbevoegd: toegang wordt geweigerd vanwege ongeldige inloggegevens -invalid-inputs=Onjuiste invoer, /__1__ __2__ -invalid-range=Onjuiste radius, Min: __1__, Max: __2__ -invalid-length=Onjuiste lengte, Max: __1__ -invalid-player=Onjuiste naam, __1__ , probeer tab te gebruiken om de naam automatisch in te vullen -offline-player=Speler is offline. -dead-player=Speler is dood. -command-ran=Commando uitgevoerd. diff --git a/modules/ExpGamingCore/Command/locale/sv-SE.cfg b/modules/ExpGamingCore/Command/locale/sv-SE.cfg deleted file mode 100644 index 5ee344f0bc..0000000000 --- a/modules/ExpGamingCore/Command/locale/sv-SE.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[ExpGamingCore_Command] -unauthorized=401 - Otillåten: Tillgång nekas på grund av otillräcklig säkerhetsprövning. -invalid-inputs=Igiltig inmatning, /__1__ __2__ -invalid-range=Invalid räckvid, Min: __1__, Max: __2__ -invalid-length=ogiltig längd, Max: __1__ -invalid-player=Ogiltigt spelarnamn, __1__ , försök använda tab-tangenten för att auto-slutföra namn. -offline-player=Spelare är offline. Kommando misslyckades med att köras. -dead-player=Spelare är död. Kommando misslyckades med att köras. -command-ran=Kommandot slutfört diff --git a/modules/commands/admin-chat.lua b/modules/commands/admin-chat.lua new file mode 100644 index 0000000000..a178349cfb --- /dev/null +++ b/modules/commands/admin-chat.lua @@ -0,0 +1,19 @@ +local Commands = require 'expcore.commands' +require 'expcore.common_parse' +require 'modules.commands.admin-only-auth' + +Commands.new_command('admin-chat','Sends a message in chat that only admins can see.') +:add_param('message',false) -- the message to send in the admin chat +:enable_auto_concat() +:add_tag('admin_only',true) +:add_alias('ac') +:register(function(player,message,raw) + local pcc = player.chat_color + local colour = string.format('%s,%s,%s',pcc.r,pcc.g,pcc.b) + for _,return_player in pairs(game.connected_players) do + if return_player.admin then + return_player.print{'exp-commands.admin-chat-format',player.name,message,colour} + end + end + return Commands.success -- prevents command complete message from showing +end) \ No newline at end of file diff --git a/modules/commands/admin-only-auth.lua b/modules/commands/admin-only-auth.lua new file mode 100644 index 0000000000..e5b5baf1c0 --- /dev/null +++ b/modules/commands/admin-only-auth.lua @@ -0,0 +1,13 @@ +local Commands = require 'expcore.commands' + +Commands.add_authenticator(function(player,command,tags,reject) + if tags.admin_only then + if player.admin then + return true + else + return reject('This command is for admins only!') + end + else + return true + end +end) \ No newline at end of file diff --git a/modules/commands/cheat-mode.lua b/modules/commands/cheat-mode.lua new file mode 100644 index 0000000000..c2a1b206b1 --- /dev/null +++ b/modules/commands/cheat-mode.lua @@ -0,0 +1,13 @@ +local Commands = require 'expcore.commands' +require 'expcore.common_parse' +require 'modules.commands.admin-only-auth' + +Commands.new_command('toggle-cheat-mode','Toggles cheat mode for your player, or another player.') +:add_param('player',true,'player') -- player to toggle chest mode of, can be nil for self +:add_defaults{player=function(player) + return player -- default is the user using the command +end} +:add_tag('admin_only',true) +:register(function(player,action_player,raw) + action_player.cheat_mode = not action_player.cheat_mode +end) \ No newline at end of file diff --git a/modules/commands/commands-local.cfg b/modules/commands/commands-local.cfg new file mode 100644 index 0000000000..ddf4213b18 --- /dev/null +++ b/modules/commands/commands-local.cfg @@ -0,0 +1,10 @@ +[exp-commands] +kill-already-dead=You are already dead. +admin-chat-format=[Admin Chat] [color=__3__]__1__: __2__ +tp-no-position-found=No position to teleport to was found, please try again later. +tp-to-self=Player can not be teleported to themselves. +chelp-title=Help results for "__1__": +chelp-footer=(__1__ results found; page __2__ of __3__) +chelp-format=/__1__ __2__ - __3__ __4__ +chelp-alias=Alias: __1__ +chelp-out-of-range=__1__ is an invalid page number. \ No newline at end of file diff --git a/modules/commands/help.lua b/modules/commands/help.lua new file mode 100644 index 0000000000..432560f682 --- /dev/null +++ b/modules/commands/help.lua @@ -0,0 +1,74 @@ +local Commands = require 'expcore.commands' +local Global = require 'utils.global' +require 'expcore.common_parse' + +local results_per_page = 5 + +local search_cache = {} +Global.register(search_cache,function(tbl) + search_cache = tbl +end) + +Commands.new_command('chelp','Searches for a keyword in all commands you are allowed to use.') +:add_param('keyword',true) -- the keyword that will be looked for +:add_param('page',true,'integer') -- the keyword that will be looked for +:add_defaults{keyword='',page=1} +:register(function(player,keyword,page,raw) + -- if keyword is a number then treat it as page number + if tonumber(keyword) then + page = math.floor(tonumber(keyword)) + keyword = '' + end + -- gets a value for pages, might have result in cache + local pages + local found = 0 + if search_cache[player.index] and search_cache[player.index].keyword == keyword:lower() then + pages = search_cache[player.index].pages + found = search_cache[player.index].found + else + pages = {{}} + local current_page = 1 + local page_count = 0 + local commands = Commands.search(keyword,player) + -- loops other all commands returned by search, includes game commands + for _,command_data in pairs(commands) do + -- if the number of results if greater than the number already added then it moves onto a new page + if page_count >= results_per_page then + page_count = 0 + current_page = current_page + 1 + table.insert(pages,{}) + end + -- adds the new command to the page + page_count = page_count + 1 + found = found + 1 + local alias_format = #command_data.aliases > 0 and {'exp-commands.chelp-alias',table.concat(command_data.aliases,', ')} or '' + table.insert(pages[current_page],{ + 'exp-commands.chelp-format', + command_data.name, + command_data.description, + command_data.help, + alias_format + }) + end + -- adds the result to the cache + search_cache[player.index] = { + keyword=keyword:lower(), + pages=pages, + found=found + } + end + -- print the requested page + keyword = keyword == '' and '' or keyword + Commands.print({'exp-commands.chelp-title',keyword},'cyan') + if pages[page] then + for _,command in pairs(pages[page]) do + Commands.print(command) + end + Commands.print({'exp-commands.chelp-footer',found,page,#pages},'cyan') + else + Commands.print({'exp-commands.chelp-footer',found,page,#pages},'cyan') + return Commands.error{'exp-commands.chelp-out-of-range',page} + end + -- blocks command complete message + return Commands.success +end) \ No newline at end of file diff --git a/modules/commands/interface.lua b/modules/commands/interface.lua new file mode 100644 index 0000000000..43306a41e4 --- /dev/null +++ b/modules/commands/interface.lua @@ -0,0 +1,90 @@ +local Commands = require 'expcore.commands' +local Global = require 'utils.global' +local Common = require 'expcore.common' +require 'modules.commands.admin-only-auth' + +-- modules that are loaded into the interface env to be accessed +local interface_modules = { + ['Game']='utils.game', + ['Commands']=Commands, + ['output']=Common.player_return +} + +-- loads all the modules given in the above table +for key,value in pairs(interface_modules) do + if type(value) == 'string' then + interface_modules[key] = require(value) + end +end + +local interface_env = {} -- used as a persistent sandbox for interface commands +local interface_callbacks = {} -- saves callbacks which can load new values per use +Global.register({interface_env,interface_callbacks},function(tbl) + interface_env = tbl[1] + interface_callbacks = tbl[2] +end) + +--- Adds a callback function when the interface command is used +-- nb: returned value is saved in the env that the interface uses +-- @tparam name string the name that the value is loaded under, cant use upvalues +-- @tparam callback function the function that will run whent he command is used +-- callback param - player: LuaPlayer - the player who used the command +local function add_interface_callback(name,callback) + if type(callback) == 'function' then + interface_callbacks[name] = callback + end +end + +-- this is a meta function for __index when self[key] is nil +local function get_index(self,key) + if interface_env[key] then + return interface_env[key] + elseif interface_modules[key] then + return interface_modules[key] + end +end + +Commands.new_command('interface','Sends an innovation to be ran and returns the result.') +:add_param('innovation',false) -- the message to send in the admin chat +:enable_auto_concat() +:add_tag('admin_only',true) +:register(function(player,innovation,raw) + if not innovation:find('%s') and not innovation:find('return') then + -- if there are no spaces and return is not present then return is appended to the start + innovation='return '..innovation + end + -- temp_env will index to interface_env and interface_modules if value not found + local temp_env = setmetatable({},{__index=get_index}) + for name,callback in pairs(interface_callbacks) do + -- loops over callbacks and loads the values returned + local success, rtn = pcall(callback,player) + temp_env[name]=rtn + end + -- sets the global metatable to prevent new values being made + -- global will index to temp_env and new indexs saved to interface_sandbox + local old_mt = getmetatable(_G) + setmetatable(_G,{__index=temp_env,__newindex=interface_env}) + -- runs the innovation and returns values to the player + innovation = loadstring(innovation) + local success, rtn = pcall(innovation) + setmetatable(_G,old_mt) + if not success then + if type(rtn) == 'string' then + -- there may be stack trace that must be removed to avoid desyncs + rtn = rtn:gsub('%.%.%..-/temp/currently%-playing','') + end + return Commands.error(rtn) + else + return Commands.success(rtn) + end +end) + +-- adds some basic callbacks for the interface +add_interface_callback('player',function(player) return player end) +add_interface_callback('surface',function(player) return player.surface end) +add_interface_callback('force',function(player) return player.force end) +add_interface_callback('position',function(player) return player.position end) +add_interface_callback('entity',function(player) return player.selected end) +add_interface_callback('tile',function(player) return player.surface.get_tile(player.position) end) + +return add_interface_callback \ No newline at end of file diff --git a/modules/commands/kill.lua b/modules/commands/kill.lua new file mode 100644 index 0000000000..a5c990c313 --- /dev/null +++ b/modules/commands/kill.lua @@ -0,0 +1,20 @@ +local Commands = require 'expcore.commands' +require 'expcore.common_parse' +require 'modules.commands.admin-only-auth' + +Commands.new_command('kill','Kills yourself or another player.') +:add_param('player',true,'player-alive') -- the player to kill, must be alive to be valid +:add_defaults{player=function(player) + -- default is the player unless they are dead + if player.character and player.character.health > 0 then + return player + end +end} +:add_tag('admin_only',true) +:register(function(player,action_player,raw) + if not action_player then + -- can only be nil if no player given and the user is dead + return Commands.error{'exp-commands.kill-already-dead'} + end + action_player.character.die() +end) \ No newline at end of file diff --git a/modules/commands/me.lua b/modules/commands/me.lua new file mode 100644 index 0000000000..47c1285a8e --- /dev/null +++ b/modules/commands/me.lua @@ -0,0 +1,8 @@ +local Commands = require 'expcore.commands' + +Commands.new_command('me','Sends an action message in the chat') +:add_param('action',false) -- action that is done by the player, just text its meaningless +:enable_auto_concat() +:register(function(player,action,raw) + game.print(string.format('* %s %s *',player.name,action),player.chat_color) +end) \ No newline at end of file diff --git a/modules/commands/tag.lua b/modules/commands/tag.lua new file mode 100644 index 0000000000..126ff5dbd3 --- /dev/null +++ b/modules/commands/tag.lua @@ -0,0 +1,27 @@ +local Commands = require 'expcore.commands' +require 'expcore.common_parse' + +Commands.new_command('tag','Sets your player tag.') +:add_param('tag',false,'string-max-length',20) -- new tag for your player max 20 char +:enable_auto_concat() +:register(function(player,tag,raw) + player.tag = ' - '..tag +end) + +Commands.new_command('tag-clear','Clears your tag. Or another player if you are admin.') +:add_param('player',true,'player') -- player to remove the tag of, nil to apply to self +:add_defaults{player=function(player) + return player -- default is the user using the command +end} +:register(function(player,action_player,raw) + if action_player.index == player.index then + -- no player given so removes your tag + action_player.tag = '' + elseif player.admin then + -- player given and user is admin so clears that player's tag + action_player.tag = '' + else + -- user is not admin and tried to clear another users tag + return Commands.error{'expcore-commands.unauthorized'} + end +end) \ No newline at end of file diff --git a/modules/commands/teleport.lua b/modules/commands/teleport.lua new file mode 100644 index 0000000000..bcb64ee840 --- /dev/null +++ b/modules/commands/teleport.lua @@ -0,0 +1,56 @@ +local Commands = require 'expcore.commands' +require 'expcore.common_parse' +require 'modules.commands.admin-only-auth' + +local function teleport(from_player,to_player) + local surface = to_player.surface + local position = surface.find_non_colliding_position('player',to_player.position,32,1) + if not position then return false end -- return false if no new position + from_player.teleport(position,surface) + return true +end + +Commands.new_command('teleport','Teleports a player to another player.') +:add_param('from_player',false,'player-alive') -- player that will be teleported, must be alive +:add_param('to_player',false,'player-online') -- player to teleport to, must be online (if dead goes to where they died) +:add_alias('tp') +:add_tag('admin_only',true) +:register(function(player,from_player,to_player,raw) + if from_player.index == to_player.index then + -- return if attempting to teleport to self + return Commands.error{'exp-commands.tp-to-self'} + end + if not teleport(from_player,to_player) then + -- return if the teleport failed + return Commands.error{'exp-commands.tp-no-position-found'} + end +end) + +Commands.new_command('bring','Teleports a player to you.') +:add_param('player',false,'player-alive') -- player that will be teleported, must be alive +:add_tag('admin_only',true) +:register(function(player,from_player,raw) + if from_player.index == player.index then + -- return if attempting to teleport to self + return Commands.error{'exp-commands.tp-to-self'} + end + if not teleport(from_player,player) then + -- return if the teleport failed + return Commands.error{'exp-commands.tp-no-position-found'} + end +end) + +Commands.new_command('goto','Teleports you to a player.') +:add_param('player',false,'player-online') -- player to teleport to, must be online (if dead goes to where they died) +:add_alias('tp-me','tpme') +:add_tag('admin_only',true) +:register(function(player,to_player,raw) + if to_player.index == player.index then + -- return if attempting to teleport to self + return Commands.error{'exp-commands.tp-to-self'} + end + if not teleport(player,to_player) then + -- return if the teleport failed + return Commands.error{'exp-commands.tp-no-position-found'} + end +end) \ No newline at end of file diff --git a/locale/en/DeconControl.cfg b/old/locale/en/DeconControl.cfg similarity index 100% rename from locale/en/DeconControl.cfg rename to old/locale/en/DeconControl.cfg diff --git a/locale/en/ExpGamingAdmin.AdminLib.cfg b/old/locale/en/ExpGamingAdmin.AdminLib.cfg similarity index 100% rename from locale/en/ExpGamingAdmin.AdminLib.cfg rename to old/locale/en/ExpGamingAdmin.AdminLib.cfg diff --git a/locale/en/ExpGamingAdmin.Warnings.cfg b/old/locale/en/ExpGamingAdmin.Warnings.cfg similarity index 100% rename from locale/en/ExpGamingAdmin.Warnings.cfg rename to old/locale/en/ExpGamingAdmin.Warnings.cfg diff --git a/locale/en/ExpGamingAdmin.cfg b/old/locale/en/ExpGamingAdmin.cfg similarity index 100% rename from locale/en/ExpGamingAdmin.cfg rename to old/locale/en/ExpGamingAdmin.cfg diff --git a/locale/en/ExpGamingBot.autoChat.cfg b/old/locale/en/ExpGamingBot.autoChat.cfg similarity index 100% rename from locale/en/ExpGamingBot.autoChat.cfg rename to old/locale/en/ExpGamingBot.autoChat.cfg diff --git a/locale/en/ExpGamingBot.autoMessage.cfg b/old/locale/en/ExpGamingBot.autoMessage.cfg similarity index 100% rename from locale/en/ExpGamingBot.autoMessage.cfg rename to old/locale/en/ExpGamingBot.autoMessage.cfg diff --git a/locale/en/ExpGamingCommands.home.cfg b/old/locale/en/ExpGamingCommands.home.cfg similarity index 100% rename from locale/en/ExpGamingCommands.home.cfg rename to old/locale/en/ExpGamingCommands.home.cfg diff --git a/locale/en/ExpGamingCore.Command.cfg b/old/locale/en/ExpGamingCore.Command.cfg similarity index 96% rename from locale/en/ExpGamingCore.Command.cfg rename to old/locale/en/ExpGamingCore.Command.cfg index bdc9fb418a..66af8ae2dd 100644 --- a/locale/en/ExpGamingCore.Command.cfg +++ b/old/locale/en/ExpGamingCore.Command.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=Unauthorized, Access is denied due to invalid credentials error-string-list=Invalid Option, Must be one of: __1__ error-string-len=Invalid Length, Max: __1__ diff --git a/locale/en/ExpGamingCore.Gui.cfg b/old/locale/en/ExpGamingCore.Gui.cfg similarity index 100% rename from locale/en/ExpGamingCore.Gui.cfg rename to old/locale/en/ExpGamingCore.Gui.cfg diff --git a/locale/en/ExpGamingCore.Ranking.cfg b/old/locale/en/ExpGamingCore.Ranking.cfg similarity index 100% rename from locale/en/ExpGamingCore.Ranking.cfg rename to old/locale/en/ExpGamingCore.Ranking.cfg diff --git a/locale/en/ExpGamingCore.Role.cfg b/old/locale/en/ExpGamingCore.Role.cfg similarity index 100% rename from locale/en/ExpGamingCore.Role.cfg rename to old/locale/en/ExpGamingCore.Role.cfg diff --git a/locale/en/ExpGamingCore.Server.cfg b/old/locale/en/ExpGamingCore.Server.cfg similarity index 100% rename from locale/en/ExpGamingCore.Server.cfg rename to old/locale/en/ExpGamingCore.Server.cfg diff --git a/locale/en/ExpGamingInfo.Readme.cfg b/old/locale/en/ExpGamingInfo.Readme.cfg similarity index 100% rename from locale/en/ExpGamingInfo.Readme.cfg rename to old/locale/en/ExpGamingInfo.Readme.cfg diff --git a/locale/en/ExpGamingInfo.Rockets.cfg b/old/locale/en/ExpGamingInfo.Rockets.cfg similarity index 100% rename from locale/en/ExpGamingInfo.Rockets.cfg rename to old/locale/en/ExpGamingInfo.Rockets.cfg diff --git a/locale/en/ExpGamingInfo.Science.cfg b/old/locale/en/ExpGamingInfo.Science.cfg similarity index 100% rename from locale/en/ExpGamingInfo.Science.cfg rename to old/locale/en/ExpGamingInfo.Science.cfg diff --git a/locale/en/ExpGamingInfo.Tasklist.cfg b/old/locale/en/ExpGamingInfo.Tasklist.cfg similarity index 100% rename from locale/en/ExpGamingInfo.Tasklist.cfg rename to old/locale/en/ExpGamingInfo.Tasklist.cfg diff --git a/locale/en/ExpGamingPlayer.inventorySearch.cfg b/old/locale/en/ExpGamingPlayer.inventorySearch.cfg similarity index 100% rename from locale/en/ExpGamingPlayer.inventorySearch.cfg rename to old/locale/en/ExpGamingPlayer.inventorySearch.cfg diff --git a/locale/en/ExpGamingPlayer.playerInfo.cfg b/old/locale/en/ExpGamingPlayer.playerInfo.cfg similarity index 100% rename from locale/en/ExpGamingPlayer.playerInfo.cfg rename to old/locale/en/ExpGamingPlayer.playerInfo.cfg diff --git a/locale/en/ExpGamingPlayer.playerList.cfg b/old/locale/en/ExpGamingPlayer.playerList.cfg similarity index 100% rename from locale/en/ExpGamingPlayer.playerList.cfg rename to old/locale/en/ExpGamingPlayer.playerList.cfg diff --git a/locale/en/ExpGamingPlayer.polls.cfg b/old/locale/en/ExpGamingPlayer.polls.cfg similarity index 100% rename from locale/en/ExpGamingPlayer.polls.cfg rename to old/locale/en/ExpGamingPlayer.polls.cfg diff --git a/locale/en/GameSettingsGui.cfg b/old/locale/en/GameSettingsGui.cfg similarity index 100% rename from locale/en/GameSettingsGui.cfg rename to old/locale/en/GameSettingsGui.cfg diff --git a/locale/en/GuiAnnouncements.cfg b/old/locale/en/GuiAnnouncements.cfg similarity index 100% rename from locale/en/GuiAnnouncements.cfg rename to old/locale/en/GuiAnnouncements.cfg diff --git a/locale/en/WarpPoints.cfg b/old/locale/en/WarpPoints.cfg similarity index 100% rename from locale/en/WarpPoints.cfg rename to old/locale/en/WarpPoints.cfg diff --git a/locale/fr/DeconControl.cfg b/old/locale/fr/DeconControl.cfg similarity index 100% rename from locale/fr/DeconControl.cfg rename to old/locale/fr/DeconControl.cfg diff --git a/locale/fr/ExpGamingAdmin.AdminLib.cfg b/old/locale/fr/ExpGamingAdmin.AdminLib.cfg similarity index 100% rename from locale/fr/ExpGamingAdmin.AdminLib.cfg rename to old/locale/fr/ExpGamingAdmin.AdminLib.cfg diff --git a/locale/fr/ExpGamingAdmin.Warnings.cfg b/old/locale/fr/ExpGamingAdmin.Warnings.cfg similarity index 100% rename from locale/fr/ExpGamingAdmin.Warnings.cfg rename to old/locale/fr/ExpGamingAdmin.Warnings.cfg diff --git a/locale/fr/ExpGamingAdmin.cfg b/old/locale/fr/ExpGamingAdmin.cfg similarity index 100% rename from locale/fr/ExpGamingAdmin.cfg rename to old/locale/fr/ExpGamingAdmin.cfg diff --git a/locale/fr/ExpGamingBot.autoChat.cfg b/old/locale/fr/ExpGamingBot.autoChat.cfg similarity index 100% rename from locale/fr/ExpGamingBot.autoChat.cfg rename to old/locale/fr/ExpGamingBot.autoChat.cfg diff --git a/locale/fr/ExpGamingBot.autoMessage.cfg b/old/locale/fr/ExpGamingBot.autoMessage.cfg similarity index 100% rename from locale/fr/ExpGamingBot.autoMessage.cfg rename to old/locale/fr/ExpGamingBot.autoMessage.cfg diff --git a/locale/fr/ExpGamingCore.Command.cfg b/old/locale/fr/ExpGamingCore.Command.cfg similarity index 94% rename from locale/fr/ExpGamingCore.Command.cfg rename to old/locale/fr/ExpGamingCore.Command.cfg index 5d271090dd..2fbd4aeed1 100644 --- a/locale/fr/ExpGamingCore.Command.cfg +++ b/old/locale/fr/ExpGamingCore.Command.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Unauthorized: Access is denied due to invalid credentials invalid-inputs=Invalid Input, /__1__ __2__ invalid-range=Invalid Range, Min: __1__, Max: __2__ diff --git a/locale/fr/ExpGamingCore.Commands.cfg b/old/locale/fr/ExpGamingCore.Commands.cfg similarity index 94% rename from locale/fr/ExpGamingCore.Commands.cfg rename to old/locale/fr/ExpGamingCore.Commands.cfg index 5d271090dd..2fbd4aeed1 100644 --- a/locale/fr/ExpGamingCore.Commands.cfg +++ b/old/locale/fr/ExpGamingCore.Commands.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Unauthorized: Access is denied due to invalid credentials invalid-inputs=Invalid Input, /__1__ __2__ invalid-range=Invalid Range, Min: __1__, Max: __2__ diff --git a/locale/fr/ExpGamingCore.Gui.cfg b/old/locale/fr/ExpGamingCore.Gui.cfg similarity index 100% rename from locale/fr/ExpGamingCore.Gui.cfg rename to old/locale/fr/ExpGamingCore.Gui.cfg diff --git a/locale/fr/ExpGamingCore.Ranking.cfg b/old/locale/fr/ExpGamingCore.Ranking.cfg similarity index 100% rename from locale/fr/ExpGamingCore.Ranking.cfg rename to old/locale/fr/ExpGamingCore.Ranking.cfg diff --git a/locale/fr/ExpGamingInfo.Readme.cfg b/old/locale/fr/ExpGamingInfo.Readme.cfg similarity index 100% rename from locale/fr/ExpGamingInfo.Readme.cfg rename to old/locale/fr/ExpGamingInfo.Readme.cfg diff --git a/locale/fr/ExpGamingInfo.Rockets.cfg b/old/locale/fr/ExpGamingInfo.Rockets.cfg similarity index 100% rename from locale/fr/ExpGamingInfo.Rockets.cfg rename to old/locale/fr/ExpGamingInfo.Rockets.cfg diff --git a/locale/fr/ExpGamingInfo.Science.cfg b/old/locale/fr/ExpGamingInfo.Science.cfg similarity index 100% rename from locale/fr/ExpGamingInfo.Science.cfg rename to old/locale/fr/ExpGamingInfo.Science.cfg diff --git a/locale/fr/ExpGamingInfo.Tasklist.cfg b/old/locale/fr/ExpGamingInfo.Tasklist.cfg similarity index 100% rename from locale/fr/ExpGamingInfo.Tasklist.cfg rename to old/locale/fr/ExpGamingInfo.Tasklist.cfg diff --git a/locale/fr/ExpGamingPlayer.inventorySearch.cfg b/old/locale/fr/ExpGamingPlayer.inventorySearch.cfg similarity index 100% rename from locale/fr/ExpGamingPlayer.inventorySearch.cfg rename to old/locale/fr/ExpGamingPlayer.inventorySearch.cfg diff --git a/locale/fr/ExpGamingPlayer.playerInfo.cfg b/old/locale/fr/ExpGamingPlayer.playerInfo.cfg similarity index 100% rename from locale/fr/ExpGamingPlayer.playerInfo.cfg rename to old/locale/fr/ExpGamingPlayer.playerInfo.cfg diff --git a/locale/fr/ExpGamingPlayer.playerList.cfg b/old/locale/fr/ExpGamingPlayer.playerList.cfg similarity index 100% rename from locale/fr/ExpGamingPlayer.playerList.cfg rename to old/locale/fr/ExpGamingPlayer.playerList.cfg diff --git a/locale/fr/ExpGamingPlayer.polls.cfg b/old/locale/fr/ExpGamingPlayer.polls.cfg similarity index 100% rename from locale/fr/ExpGamingPlayer.polls.cfg rename to old/locale/fr/ExpGamingPlayer.polls.cfg diff --git a/locale/fr/GameSettingsGui.cfg b/old/locale/fr/GameSettingsGui.cfg similarity index 100% rename from locale/fr/GameSettingsGui.cfg rename to old/locale/fr/GameSettingsGui.cfg diff --git a/locale/fr/GuiAnnouncements.cfg b/old/locale/fr/GuiAnnouncements.cfg similarity index 100% rename from locale/fr/GuiAnnouncements.cfg rename to old/locale/fr/GuiAnnouncements.cfg diff --git a/locale/fr/WarpPoints.cfg b/old/locale/fr/WarpPoints.cfg similarity index 100% rename from locale/fr/WarpPoints.cfg rename to old/locale/fr/WarpPoints.cfg diff --git a/locale/nl/DeconControl.cfg b/old/locale/nl/DeconControl.cfg similarity index 100% rename from locale/nl/DeconControl.cfg rename to old/locale/nl/DeconControl.cfg diff --git a/locale/nl/ExpGamingAdmin.AdminLib.cfg b/old/locale/nl/ExpGamingAdmin.AdminLib.cfg similarity index 100% rename from locale/nl/ExpGamingAdmin.AdminLib.cfg rename to old/locale/nl/ExpGamingAdmin.AdminLib.cfg diff --git a/locale/nl/ExpGamingAdmin.Warnings.cfg b/old/locale/nl/ExpGamingAdmin.Warnings.cfg similarity index 100% rename from locale/nl/ExpGamingAdmin.Warnings.cfg rename to old/locale/nl/ExpGamingAdmin.Warnings.cfg diff --git a/locale/nl/ExpGamingAdmin.cfg b/old/locale/nl/ExpGamingAdmin.cfg similarity index 100% rename from locale/nl/ExpGamingAdmin.cfg rename to old/locale/nl/ExpGamingAdmin.cfg diff --git a/locale/nl/ExpGamingBot.autoChat.cfg b/old/locale/nl/ExpGamingBot.autoChat.cfg similarity index 100% rename from locale/nl/ExpGamingBot.autoChat.cfg rename to old/locale/nl/ExpGamingBot.autoChat.cfg diff --git a/locale/nl/ExpGamingBot.autoMessage.cfg b/old/locale/nl/ExpGamingBot.autoMessage.cfg similarity index 100% rename from locale/nl/ExpGamingBot.autoMessage.cfg rename to old/locale/nl/ExpGamingBot.autoMessage.cfg diff --git a/locale/nl/ExpGamingCore.Command.cfg b/old/locale/nl/ExpGamingCore.Command.cfg similarity index 94% rename from locale/nl/ExpGamingCore.Command.cfg rename to old/locale/nl/ExpGamingCore.Command.cfg index 3742ef49b0..77ad98b93c 100644 --- a/locale/nl/ExpGamingCore.Command.cfg +++ b/old/locale/nl/ExpGamingCore.Command.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Onbevoegd: toegang wordt geweigerd vanwege ongeldige inloggegevens invalid-inputs=Onjuiste invoer, /__1__ __2__ invalid-range=Onjuiste radius, Min: __1__, Max: __2__ diff --git a/locale/nl/ExpGamingCore.Commands.cfg b/old/locale/nl/ExpGamingCore.Commands.cfg similarity index 94% rename from locale/nl/ExpGamingCore.Commands.cfg rename to old/locale/nl/ExpGamingCore.Commands.cfg index 3742ef49b0..77ad98b93c 100644 --- a/locale/nl/ExpGamingCore.Commands.cfg +++ b/old/locale/nl/ExpGamingCore.Commands.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Onbevoegd: toegang wordt geweigerd vanwege ongeldige inloggegevens invalid-inputs=Onjuiste invoer, /__1__ __2__ invalid-range=Onjuiste radius, Min: __1__, Max: __2__ diff --git a/locale/nl/ExpGamingCore.Gui.cfg b/old/locale/nl/ExpGamingCore.Gui.cfg similarity index 100% rename from locale/nl/ExpGamingCore.Gui.cfg rename to old/locale/nl/ExpGamingCore.Gui.cfg diff --git a/locale/nl/ExpGamingCore.Ranking.cfg b/old/locale/nl/ExpGamingCore.Ranking.cfg similarity index 100% rename from locale/nl/ExpGamingCore.Ranking.cfg rename to old/locale/nl/ExpGamingCore.Ranking.cfg diff --git a/locale/nl/ExpGamingInfo.Readme.cfg b/old/locale/nl/ExpGamingInfo.Readme.cfg similarity index 100% rename from locale/nl/ExpGamingInfo.Readme.cfg rename to old/locale/nl/ExpGamingInfo.Readme.cfg diff --git a/locale/nl/ExpGamingInfo.Rockets.cfg b/old/locale/nl/ExpGamingInfo.Rockets.cfg similarity index 100% rename from locale/nl/ExpGamingInfo.Rockets.cfg rename to old/locale/nl/ExpGamingInfo.Rockets.cfg diff --git a/locale/nl/ExpGamingInfo.Science.cfg b/old/locale/nl/ExpGamingInfo.Science.cfg similarity index 100% rename from locale/nl/ExpGamingInfo.Science.cfg rename to old/locale/nl/ExpGamingInfo.Science.cfg diff --git a/locale/nl/ExpGamingInfo.Tasklist.cfg b/old/locale/nl/ExpGamingInfo.Tasklist.cfg similarity index 100% rename from locale/nl/ExpGamingInfo.Tasklist.cfg rename to old/locale/nl/ExpGamingInfo.Tasklist.cfg diff --git a/locale/nl/ExpGamingPlayer.inventorySearch.cfg b/old/locale/nl/ExpGamingPlayer.inventorySearch.cfg similarity index 100% rename from locale/nl/ExpGamingPlayer.inventorySearch.cfg rename to old/locale/nl/ExpGamingPlayer.inventorySearch.cfg diff --git a/locale/nl/ExpGamingPlayer.playerInfo.cfg b/old/locale/nl/ExpGamingPlayer.playerInfo.cfg similarity index 100% rename from locale/nl/ExpGamingPlayer.playerInfo.cfg rename to old/locale/nl/ExpGamingPlayer.playerInfo.cfg diff --git a/locale/nl/ExpGamingPlayer.playerList.cfg b/old/locale/nl/ExpGamingPlayer.playerList.cfg similarity index 100% rename from locale/nl/ExpGamingPlayer.playerList.cfg rename to old/locale/nl/ExpGamingPlayer.playerList.cfg diff --git a/locale/nl/ExpGamingPlayer.polls.cfg b/old/locale/nl/ExpGamingPlayer.polls.cfg similarity index 100% rename from locale/nl/ExpGamingPlayer.polls.cfg rename to old/locale/nl/ExpGamingPlayer.polls.cfg diff --git a/locale/nl/GameSettingsGui.cfg b/old/locale/nl/GameSettingsGui.cfg similarity index 100% rename from locale/nl/GameSettingsGui.cfg rename to old/locale/nl/GameSettingsGui.cfg diff --git a/locale/nl/GuiAnnouncements.cfg b/old/locale/nl/GuiAnnouncements.cfg similarity index 100% rename from locale/nl/GuiAnnouncements.cfg rename to old/locale/nl/GuiAnnouncements.cfg diff --git a/locale/nl/WarpPoints.cfg b/old/locale/nl/WarpPoints.cfg similarity index 100% rename from locale/nl/WarpPoints.cfg rename to old/locale/nl/WarpPoints.cfg diff --git a/locale/sv-SE/DeconControl.cfg b/old/locale/sv-SE/DeconControl.cfg similarity index 100% rename from locale/sv-SE/DeconControl.cfg rename to old/locale/sv-SE/DeconControl.cfg diff --git a/locale/sv-SE/ExpGamingAdmin.AdminLib.cfg b/old/locale/sv-SE/ExpGamingAdmin.AdminLib.cfg similarity index 100% rename from locale/sv-SE/ExpGamingAdmin.AdminLib.cfg rename to old/locale/sv-SE/ExpGamingAdmin.AdminLib.cfg diff --git a/locale/sv-SE/ExpGamingAdmin.Warnings.cfg b/old/locale/sv-SE/ExpGamingAdmin.Warnings.cfg similarity index 100% rename from locale/sv-SE/ExpGamingAdmin.Warnings.cfg rename to old/locale/sv-SE/ExpGamingAdmin.Warnings.cfg diff --git a/locale/sv-SE/ExpGamingAdmin.cfg b/old/locale/sv-SE/ExpGamingAdmin.cfg similarity index 100% rename from locale/sv-SE/ExpGamingAdmin.cfg rename to old/locale/sv-SE/ExpGamingAdmin.cfg diff --git a/locale/sv-SE/ExpGamingBot.autoChat.cfg b/old/locale/sv-SE/ExpGamingBot.autoChat.cfg similarity index 100% rename from locale/sv-SE/ExpGamingBot.autoChat.cfg rename to old/locale/sv-SE/ExpGamingBot.autoChat.cfg diff --git a/locale/sv-SE/ExpGamingBot.autoMessage.cfg b/old/locale/sv-SE/ExpGamingBot.autoMessage.cfg similarity index 100% rename from locale/sv-SE/ExpGamingBot.autoMessage.cfg rename to old/locale/sv-SE/ExpGamingBot.autoMessage.cfg diff --git a/locale/sv-SE/ExpGamingCore.Command.cfg b/old/locale/sv-SE/ExpGamingCore.Command.cfg similarity index 95% rename from locale/sv-SE/ExpGamingCore.Command.cfg rename to old/locale/sv-SE/ExpGamingCore.Command.cfg index 5ee344f0bc..99b1c6f4a4 100644 --- a/locale/sv-SE/ExpGamingCore.Command.cfg +++ b/old/locale/sv-SE/ExpGamingCore.Command.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Otillåten: Tillgång nekas på grund av otillräcklig säkerhetsprövning. invalid-inputs=Igiltig inmatning, /__1__ __2__ invalid-range=Invalid räckvid, Min: __1__, Max: __2__ diff --git a/locale/sv-SE/ExpGamingCore.Commands.cfg b/old/locale/sv-SE/ExpGamingCore.Commands.cfg similarity index 95% rename from locale/sv-SE/ExpGamingCore.Commands.cfg rename to old/locale/sv-SE/ExpGamingCore.Commands.cfg index 5ee344f0bc..99b1c6f4a4 100644 --- a/locale/sv-SE/ExpGamingCore.Commands.cfg +++ b/old/locale/sv-SE/ExpGamingCore.Commands.cfg @@ -1,4 +1,4 @@ -[ExpGamingCore_Command] +[expcore-commands] unauthorized=401 - Otillåten: Tillgång nekas på grund av otillräcklig säkerhetsprövning. invalid-inputs=Igiltig inmatning, /__1__ __2__ invalid-range=Invalid räckvid, Min: __1__, Max: __2__ diff --git a/locale/sv-SE/ExpGamingCore.Gui.cfg b/old/locale/sv-SE/ExpGamingCore.Gui.cfg similarity index 100% rename from locale/sv-SE/ExpGamingCore.Gui.cfg rename to old/locale/sv-SE/ExpGamingCore.Gui.cfg diff --git a/locale/sv-SE/ExpGamingCore.Ranking.cfg b/old/locale/sv-SE/ExpGamingCore.Ranking.cfg similarity index 100% rename from locale/sv-SE/ExpGamingCore.Ranking.cfg rename to old/locale/sv-SE/ExpGamingCore.Ranking.cfg diff --git a/locale/sv-SE/ExpGamingInfo.Readme.cfg b/old/locale/sv-SE/ExpGamingInfo.Readme.cfg similarity index 100% rename from locale/sv-SE/ExpGamingInfo.Readme.cfg rename to old/locale/sv-SE/ExpGamingInfo.Readme.cfg diff --git a/locale/sv-SE/ExpGamingInfo.Rockets.cfg b/old/locale/sv-SE/ExpGamingInfo.Rockets.cfg similarity index 100% rename from locale/sv-SE/ExpGamingInfo.Rockets.cfg rename to old/locale/sv-SE/ExpGamingInfo.Rockets.cfg diff --git a/locale/sv-SE/ExpGamingInfo.Science.cfg b/old/locale/sv-SE/ExpGamingInfo.Science.cfg similarity index 100% rename from locale/sv-SE/ExpGamingInfo.Science.cfg rename to old/locale/sv-SE/ExpGamingInfo.Science.cfg diff --git a/locale/sv-SE/ExpGamingInfo.Tasklist.cfg b/old/locale/sv-SE/ExpGamingInfo.Tasklist.cfg similarity index 100% rename from locale/sv-SE/ExpGamingInfo.Tasklist.cfg rename to old/locale/sv-SE/ExpGamingInfo.Tasklist.cfg diff --git a/locale/sv-SE/ExpGamingPlayer.inventorySearch.cfg b/old/locale/sv-SE/ExpGamingPlayer.inventorySearch.cfg similarity index 100% rename from locale/sv-SE/ExpGamingPlayer.inventorySearch.cfg rename to old/locale/sv-SE/ExpGamingPlayer.inventorySearch.cfg diff --git a/locale/sv-SE/ExpGamingPlayer.playerInfo.cfg b/old/locale/sv-SE/ExpGamingPlayer.playerInfo.cfg similarity index 100% rename from locale/sv-SE/ExpGamingPlayer.playerInfo.cfg rename to old/locale/sv-SE/ExpGamingPlayer.playerInfo.cfg diff --git a/locale/sv-SE/ExpGamingPlayer.playerList.cfg b/old/locale/sv-SE/ExpGamingPlayer.playerList.cfg similarity index 100% rename from locale/sv-SE/ExpGamingPlayer.playerList.cfg rename to old/locale/sv-SE/ExpGamingPlayer.playerList.cfg diff --git a/locale/sv-SE/ExpGamingPlayer.polls.cfg b/old/locale/sv-SE/ExpGamingPlayer.polls.cfg similarity index 100% rename from locale/sv-SE/ExpGamingPlayer.polls.cfg rename to old/locale/sv-SE/ExpGamingPlayer.polls.cfg diff --git a/locale/sv-SE/GameSettingsGui.cfg b/old/locale/sv-SE/GameSettingsGui.cfg similarity index 100% rename from locale/sv-SE/GameSettingsGui.cfg rename to old/locale/sv-SE/GameSettingsGui.cfg diff --git a/locale/sv-SE/GuiAnnouncements.cfg b/old/locale/sv-SE/GuiAnnouncements.cfg similarity index 100% rename from locale/sv-SE/GuiAnnouncements.cfg rename to old/locale/sv-SE/GuiAnnouncements.cfg diff --git a/locale/sv-SE/WarpPoints.cfg b/old/locale/sv-SE/WarpPoints.cfg similarity index 100% rename from locale/sv-SE/WarpPoints.cfg rename to old/locale/sv-SE/WarpPoints.cfg diff --git a/modules/AdvancedStartingItems/control.lua b/old/modules/AdvancedStartingItems/control.lua similarity index 97% rename from modules/AdvancedStartingItems/control.lua rename to old/modules/AdvancedStartingItems/control.lua index 31c1e71805..c97ebec29f 100644 --- a/modules/AdvancedStartingItems/control.lua +++ b/old/modules/AdvancedStartingItems/control.lua @@ -28,7 +28,7 @@ local module_verbose = false local ThisModule = {} -- Event Handlers Define -script.on_event(defines.events.on_player_created, function(event) +Event.add(defines.events.on_player_created, function(event) local player = game.players[event.player_index] if event.player_index == 1 then player.force.friendly_fire = false diff --git a/modules/AdvancedStartingItems/softmod.json b/old/modules/AdvancedStartingItems/softmod.json similarity index 100% rename from modules/AdvancedStartingItems/softmod.json rename to old/modules/AdvancedStartingItems/softmod.json diff --git a/modules/ChatPopup/control.lua b/old/modules/ChatPopup/control.lua similarity index 96% rename from modules/ChatPopup/control.lua rename to old/modules/ChatPopup/control.lua index 6ab99fd3bf..992fcda806 100644 --- a/modules/ChatPopup/control.lua +++ b/old/modules/ChatPopup/control.lua @@ -31,7 +31,7 @@ function ChatPopup.sendFlyingText(player, text) end end -script.on_event(defines.events.on_console_chat, function(event) +Event.add(defines.events.on_console_chat, function(event) if not event.player_index then return end local player = game.players[event.player_index] if not player then return end diff --git a/modules/ChatPopup/softmod.json b/old/modules/ChatPopup/softmod.json similarity index 100% rename from modules/ChatPopup/softmod.json rename to old/modules/ChatPopup/softmod.json diff --git a/modules/DamagePopup/control.lua b/old/modules/DamagePopup/control.lua similarity index 95% rename from modules/DamagePopup/control.lua rename to old/modules/DamagePopup/control.lua index b75b2003f9..d172b8e345 100644 --- a/modules/DamagePopup/control.lua +++ b/old/modules/DamagePopup/control.lua @@ -9,7 +9,7 @@ local Color = require('FactorioStdLib.Color') local DamagePopup = {} -script.on_event(defines.events.on_entity_damaged, function(event) +Event.add(defines.events.on_entity_damaged, function(event) local entity = event.entity local cause = event.cause local damage = event.original_damage_amount diff --git a/modules/DamagePopup/softmod.json b/old/modules/DamagePopup/softmod.json similarity index 100% rename from modules/DamagePopup/softmod.json rename to old/modules/DamagePopup/softmod.json diff --git a/modules/DeathMarkers/control.lua b/old/modules/DeathMarkers/control.lua similarity index 88% rename from modules/DeathMarkers/control.lua rename to old/modules/DeathMarkers/control.lua index 051e5eb3e7..3e0e9004b6 100644 --- a/modules/DeathMarkers/control.lua +++ b/old/modules/DeathMarkers/control.lua @@ -9,12 +9,13 @@ local module_verbose = false local ThisModule = {} -- Global Define -local global = global{ +local global = { corpses={} } +Global.register(global,function(tbl) global = tbl end) -- Event Handlers Define -script.on_event(defines.events.on_player_died, function(event) +Event.add(defines.events.on_player_died, function(event) local player = game.players[event.player_index] local tag = player.force.add_chart_tag(player.surface,{ position=player.position, @@ -24,7 +25,7 @@ script.on_event(defines.events.on_player_died, function(event) table.insert(global.corpses,tag) end) -script.on_event(defines.events.on_tick, function(event) +Event.add(defines.events.on_tick, function(event) if (game.tick%3600) ~= 0 then return end if not global.corpses then global.corpses = {} end local key = 1 diff --git a/modules/DeathMarkers/softmod.json b/old/modules/DeathMarkers/softmod.json similarity index 100% rename from modules/DeathMarkers/softmod.json rename to old/modules/DeathMarkers/softmod.json diff --git a/modules/DeconControl/control.lua b/old/modules/DeconControl/control.lua similarity index 100% rename from modules/DeconControl/control.lua rename to old/modules/DeconControl/control.lua diff --git a/modules/DeconControl/locale/de.cfg b/old/modules/DeconControl/locale/de.cfg similarity index 100% rename from modules/DeconControl/locale/de.cfg rename to old/modules/DeconControl/locale/de.cfg diff --git a/modules/DeconControl/locale/en.cfg b/old/modules/DeconControl/locale/en.cfg similarity index 100% rename from modules/DeconControl/locale/en.cfg rename to old/modules/DeconControl/locale/en.cfg diff --git a/modules/DeconControl/locale/fr.cfg b/old/modules/DeconControl/locale/fr.cfg similarity index 100% rename from modules/DeconControl/locale/fr.cfg rename to old/modules/DeconControl/locale/fr.cfg diff --git a/modules/DeconControl/locale/nl.cfg b/old/modules/DeconControl/locale/nl.cfg similarity index 100% rename from modules/DeconControl/locale/nl.cfg rename to old/modules/DeconControl/locale/nl.cfg diff --git a/modules/DeconControl/locale/sv-SE.cfg b/old/modules/DeconControl/locale/sv-SE.cfg similarity index 100% rename from modules/DeconControl/locale/sv-SE.cfg rename to old/modules/DeconControl/locale/sv-SE.cfg diff --git a/modules/DeconControl/softmod.json b/old/modules/DeconControl/softmod.json similarity index 100% rename from modules/DeconControl/softmod.json rename to old/modules/DeconControl/softmod.json diff --git a/modules/ExpGamingAdmin/Ban/control.lua b/old/modules/ExpGamingAdmin/Ban/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Ban/control.lua rename to old/modules/ExpGamingAdmin/Ban/control.lua diff --git a/modules/ExpGamingAdmin/Ban/softmod.json b/old/modules/ExpGamingAdmin/Ban/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Ban/softmod.json rename to old/modules/ExpGamingAdmin/Ban/softmod.json diff --git a/modules/ExpGamingAdmin/ClearInventory/control.lua b/old/modules/ExpGamingAdmin/ClearInventory/control.lua similarity index 100% rename from modules/ExpGamingAdmin/ClearInventory/control.lua rename to old/modules/ExpGamingAdmin/ClearInventory/control.lua diff --git a/modules/ExpGamingAdmin/ClearInventory/softmod.json b/old/modules/ExpGamingAdmin/ClearInventory/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/ClearInventory/softmod.json rename to old/modules/ExpGamingAdmin/ClearInventory/softmod.json diff --git a/modules/ExpGamingAdmin/Commands/control.lua b/old/modules/ExpGamingAdmin/Commands/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/control.lua rename to old/modules/ExpGamingAdmin/Commands/control.lua diff --git a/modules/ExpGamingAdmin/Commands/softmod.json b/old/modules/ExpGamingAdmin/Commands/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Commands/softmod.json rename to old/modules/ExpGamingAdmin/Commands/softmod.json diff --git a/modules/ExpGamingAdmin/Commands/src/clear.lua b/old/modules/ExpGamingAdmin/Commands/src/clear.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/src/clear.lua rename to old/modules/ExpGamingAdmin/Commands/src/clear.lua diff --git a/modules/ExpGamingAdmin/Commands/src/jail.lua b/old/modules/ExpGamingAdmin/Commands/src/jail.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/src/jail.lua rename to old/modules/ExpGamingAdmin/Commands/src/jail.lua diff --git a/modules/ExpGamingAdmin/Commands/src/reports.lua b/old/modules/ExpGamingAdmin/Commands/src/reports.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/src/reports.lua rename to old/modules/ExpGamingAdmin/Commands/src/reports.lua diff --git a/modules/ExpGamingAdmin/Commands/src/tempban.lua b/old/modules/ExpGamingAdmin/Commands/src/tempban.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/src/tempban.lua rename to old/modules/ExpGamingAdmin/Commands/src/tempban.lua diff --git a/modules/ExpGamingAdmin/Commands/src/warnings.lua b/old/modules/ExpGamingAdmin/Commands/src/warnings.lua similarity index 100% rename from modules/ExpGamingAdmin/Commands/src/warnings.lua rename to old/modules/ExpGamingAdmin/Commands/src/warnings.lua diff --git a/modules/ExpGamingAdmin/Gui/control.lua b/old/modules/ExpGamingAdmin/Gui/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Gui/control.lua rename to old/modules/ExpGamingAdmin/Gui/control.lua diff --git a/modules/ExpGamingAdmin/Gui/softmod.json b/old/modules/ExpGamingAdmin/Gui/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Gui/softmod.json rename to old/modules/ExpGamingAdmin/Gui/softmod.json diff --git a/modules/ExpGamingAdmin/Jail/control.lua b/old/modules/ExpGamingAdmin/Jail/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Jail/control.lua rename to old/modules/ExpGamingAdmin/Jail/control.lua diff --git a/modules/ExpGamingAdmin/Jail/softmod.json b/old/modules/ExpGamingAdmin/Jail/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Jail/softmod.json rename to old/modules/ExpGamingAdmin/Jail/softmod.json diff --git a/modules/ExpGamingAdmin/Kick/control.lua b/old/modules/ExpGamingAdmin/Kick/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Kick/control.lua rename to old/modules/ExpGamingAdmin/Kick/control.lua diff --git a/modules/ExpGamingAdmin/Kick/softmod.json b/old/modules/ExpGamingAdmin/Kick/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Kick/softmod.json rename to old/modules/ExpGamingAdmin/Kick/softmod.json diff --git a/modules/ExpGamingAdmin/Reports/control.lua b/old/modules/ExpGamingAdmin/Reports/control.lua similarity index 98% rename from modules/ExpGamingAdmin/Reports/control.lua rename to old/modules/ExpGamingAdmin/Reports/control.lua index 56fad0ba84..521397ae61 100644 --- a/modules/ExpGamingAdmin/Reports/control.lua +++ b/old/modules/ExpGamingAdmin/Reports/control.lua @@ -22,10 +22,11 @@ local ThisModule = { } -- Global Define -local global = global{ +local global = { reports={}, verified={} } +Global.register(global,function(tbl) global = tbl end) -- Local Variables local report_to_warnings = 1 -- used in count_reports diff --git a/modules/ExpGamingAdmin/Reports/softmod.json b/old/modules/ExpGamingAdmin/Reports/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Reports/softmod.json rename to old/modules/ExpGamingAdmin/Reports/softmod.json diff --git a/modules/ExpGamingAdmin/Teleport/control.lua b/old/modules/ExpGamingAdmin/Teleport/control.lua similarity index 100% rename from modules/ExpGamingAdmin/Teleport/control.lua rename to old/modules/ExpGamingAdmin/Teleport/control.lua diff --git a/modules/ExpGamingAdmin/Teleport/softmod.json b/old/modules/ExpGamingAdmin/Teleport/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Teleport/softmod.json rename to old/modules/ExpGamingAdmin/Teleport/softmod.json diff --git a/modules/ExpGamingAdmin/TempBan/control.lua b/old/modules/ExpGamingAdmin/TempBan/control.lua similarity index 100% rename from modules/ExpGamingAdmin/TempBan/control.lua rename to old/modules/ExpGamingAdmin/TempBan/control.lua diff --git a/modules/ExpGamingAdmin/TempBan/softmod.json b/old/modules/ExpGamingAdmin/TempBan/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/TempBan/softmod.json rename to old/modules/ExpGamingAdmin/TempBan/softmod.json diff --git a/modules/ExpGamingAdmin/Warnings/control.lua b/old/modules/ExpGamingAdmin/Warnings/control.lua similarity index 97% rename from modules/ExpGamingAdmin/Warnings/control.lua rename to old/modules/ExpGamingAdmin/Warnings/control.lua index 07cd699427..f10bc95a72 100644 --- a/modules/ExpGamingAdmin/Warnings/control.lua +++ b/old/modules/ExpGamingAdmin/Warnings/control.lua @@ -57,7 +57,8 @@ local ThisModule = { } -- Global Define -local global = global{} +local global = {} +Global.register(global,function(tbl) global = tbl end) -- Function Define local function give_punishment(player,by_player,reason) @@ -120,7 +121,7 @@ function Admin.clear_warnings(player,by_player,no_emit) end -- Event Handlers Define -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if (game.tick % min_time_to_remove_warning) == 0 then for name,warnings in pairs(global) do if warnings > 0 then diff --git a/modules/ExpGamingAdmin/Warnings/locale/de.cfg b/old/modules/ExpGamingAdmin/Warnings/locale/de.cfg similarity index 100% rename from modules/ExpGamingAdmin/Warnings/locale/de.cfg rename to old/modules/ExpGamingAdmin/Warnings/locale/de.cfg diff --git a/modules/ExpGamingAdmin/Warnings/locale/en.cfg b/old/modules/ExpGamingAdmin/Warnings/locale/en.cfg similarity index 100% rename from modules/ExpGamingAdmin/Warnings/locale/en.cfg rename to old/modules/ExpGamingAdmin/Warnings/locale/en.cfg diff --git a/modules/ExpGamingAdmin/Warnings/locale/fr.cfg b/old/modules/ExpGamingAdmin/Warnings/locale/fr.cfg similarity index 100% rename from modules/ExpGamingAdmin/Warnings/locale/fr.cfg rename to old/modules/ExpGamingAdmin/Warnings/locale/fr.cfg diff --git a/modules/ExpGamingAdmin/Warnings/locale/nl.cfg b/old/modules/ExpGamingAdmin/Warnings/locale/nl.cfg similarity index 100% rename from modules/ExpGamingAdmin/Warnings/locale/nl.cfg rename to old/modules/ExpGamingAdmin/Warnings/locale/nl.cfg diff --git a/modules/ExpGamingAdmin/Warnings/locale/sv-SE.cfg b/old/modules/ExpGamingAdmin/Warnings/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingAdmin/Warnings/locale/sv-SE.cfg rename to old/modules/ExpGamingAdmin/Warnings/locale/sv-SE.cfg diff --git a/modules/ExpGamingAdmin/Warnings/softmod.json b/old/modules/ExpGamingAdmin/Warnings/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/Warnings/softmod.json rename to old/modules/ExpGamingAdmin/Warnings/softmod.json diff --git a/modules/ExpGamingAdmin/control.lua b/old/modules/ExpGamingAdmin/control.lua similarity index 98% rename from modules/ExpGamingAdmin/control.lua rename to old/modules/ExpGamingAdmin/control.lua index af9d31c2e6..9642ee9bb7 100644 --- a/modules/ExpGamingAdmin/control.lua +++ b/old/modules/ExpGamingAdmin/control.lua @@ -28,9 +28,10 @@ local Admin = { } -- Global Define -local global = global{ +local global = { banned = {} } +Global.register(global,function(tbl) global = tbl end) -- Function Define function Admin.valid_players(player,by_player) diff --git a/modules/ExpGamingAdmin/locale/de.cfg b/old/modules/ExpGamingAdmin/locale/de.cfg similarity index 100% rename from modules/ExpGamingAdmin/locale/de.cfg rename to old/modules/ExpGamingAdmin/locale/de.cfg diff --git a/modules/ExpGamingAdmin/locale/en.cfg b/old/modules/ExpGamingAdmin/locale/en.cfg similarity index 100% rename from modules/ExpGamingAdmin/locale/en.cfg rename to old/modules/ExpGamingAdmin/locale/en.cfg diff --git a/modules/ExpGamingAdmin/locale/fr.cfg b/old/modules/ExpGamingAdmin/locale/fr.cfg similarity index 100% rename from modules/ExpGamingAdmin/locale/fr.cfg rename to old/modules/ExpGamingAdmin/locale/fr.cfg diff --git a/modules/ExpGamingAdmin/locale/nl.cfg b/old/modules/ExpGamingAdmin/locale/nl.cfg similarity index 100% rename from modules/ExpGamingAdmin/locale/nl.cfg rename to old/modules/ExpGamingAdmin/locale/nl.cfg diff --git a/modules/ExpGamingAdmin/locale/sv-SE.cfg b/old/modules/ExpGamingAdmin/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingAdmin/locale/sv-SE.cfg rename to old/modules/ExpGamingAdmin/locale/sv-SE.cfg diff --git a/modules/ExpGamingAdmin/softmod.json b/old/modules/ExpGamingAdmin/softmod.json similarity index 100% rename from modules/ExpGamingAdmin/softmod.json rename to old/modules/ExpGamingAdmin/softmod.json diff --git a/modules/ExpGamingBot/autoChat/control.lua b/old/modules/ExpGamingBot/autoChat/control.lua similarity index 99% rename from modules/ExpGamingBot/autoChat/control.lua rename to old/modules/ExpGamingBot/autoChat/control.lua index b56bc7607b..ed4aa492ad 100644 --- a/modules/ExpGamingBot/autoChat/control.lua +++ b/old/modules/ExpGamingBot/autoChat/control.lua @@ -136,7 +136,7 @@ local ThisModule = { } -- Event Handlers Define -script.on_event(defines.events.on_console_chat,function(event) +Event.add(defines.events.on_console_chat,function(event) local player = Game.get_player(event) if not player then return end local player_message = event.message:lower():gsub("%s+", "") diff --git a/modules/ExpGamingBot/autoChat/locale/de.cfg b/old/modules/ExpGamingBot/autoChat/locale/de.cfg similarity index 100% rename from modules/ExpGamingBot/autoChat/locale/de.cfg rename to old/modules/ExpGamingBot/autoChat/locale/de.cfg diff --git a/modules/ExpGamingBot/autoChat/locale/en.cfg b/old/modules/ExpGamingBot/autoChat/locale/en.cfg similarity index 100% rename from modules/ExpGamingBot/autoChat/locale/en.cfg rename to old/modules/ExpGamingBot/autoChat/locale/en.cfg diff --git a/modules/ExpGamingBot/autoChat/locale/fr.cfg b/old/modules/ExpGamingBot/autoChat/locale/fr.cfg similarity index 100% rename from modules/ExpGamingBot/autoChat/locale/fr.cfg rename to old/modules/ExpGamingBot/autoChat/locale/fr.cfg diff --git a/modules/ExpGamingBot/autoChat/locale/nl.cfg b/old/modules/ExpGamingBot/autoChat/locale/nl.cfg similarity index 100% rename from modules/ExpGamingBot/autoChat/locale/nl.cfg rename to old/modules/ExpGamingBot/autoChat/locale/nl.cfg diff --git a/modules/ExpGamingBot/autoChat/locale/sv-SE.cfg b/old/modules/ExpGamingBot/autoChat/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingBot/autoChat/locale/sv-SE.cfg rename to old/modules/ExpGamingBot/autoChat/locale/sv-SE.cfg diff --git a/modules/ExpGamingBot/autoChat/softmod.json b/old/modules/ExpGamingBot/autoChat/softmod.json similarity index 100% rename from modules/ExpGamingBot/autoChat/softmod.json rename to old/modules/ExpGamingBot/autoChat/softmod.json diff --git a/modules/ExpGamingBot/autoMessage/control.lua b/old/modules/ExpGamingBot/autoMessage/control.lua similarity index 100% rename from modules/ExpGamingBot/autoMessage/control.lua rename to old/modules/ExpGamingBot/autoMessage/control.lua diff --git a/modules/ExpGamingBot/autoMessage/locale/de.cfg b/old/modules/ExpGamingBot/autoMessage/locale/de.cfg similarity index 100% rename from modules/ExpGamingBot/autoMessage/locale/de.cfg rename to old/modules/ExpGamingBot/autoMessage/locale/de.cfg diff --git a/modules/ExpGamingBot/autoMessage/locale/en.cfg b/old/modules/ExpGamingBot/autoMessage/locale/en.cfg similarity index 100% rename from modules/ExpGamingBot/autoMessage/locale/en.cfg rename to old/modules/ExpGamingBot/autoMessage/locale/en.cfg diff --git a/modules/ExpGamingBot/autoMessage/locale/fr.cfg b/old/modules/ExpGamingBot/autoMessage/locale/fr.cfg similarity index 100% rename from modules/ExpGamingBot/autoMessage/locale/fr.cfg rename to old/modules/ExpGamingBot/autoMessage/locale/fr.cfg diff --git a/modules/ExpGamingBot/autoMessage/locale/nl.cfg b/old/modules/ExpGamingBot/autoMessage/locale/nl.cfg similarity index 100% rename from modules/ExpGamingBot/autoMessage/locale/nl.cfg rename to old/modules/ExpGamingBot/autoMessage/locale/nl.cfg diff --git a/modules/ExpGamingBot/autoMessage/locale/sv-SE.cfg b/old/modules/ExpGamingBot/autoMessage/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingBot/autoMessage/locale/sv-SE.cfg rename to old/modules/ExpGamingBot/autoMessage/locale/sv-SE.cfg diff --git a/modules/ExpGamingBot/autoMessage/softmod.json b/old/modules/ExpGamingBot/autoMessage/softmod.json similarity index 100% rename from modules/ExpGamingBot/autoMessage/softmod.json rename to old/modules/ExpGamingBot/autoMessage/softmod.json diff --git a/modules/ExpGamingBot/discordAlerts/control.lua b/old/modules/ExpGamingBot/discordAlerts/control.lua similarity index 97% rename from modules/ExpGamingBot/discordAlerts/control.lua rename to old/modules/ExpGamingBot/discordAlerts/control.lua index a7069d21c1..f3ba31f9e2 100644 --- a/modules/ExpGamingBot/discordAlerts/control.lua +++ b/old/modules/ExpGamingBot/discordAlerts/control.lua @@ -14,7 +14,7 @@ local module_verbose = false local ThisModule = {} -- Event Handlers Define -script.on_event(defines.events.on_console_command,function(event) +Event.add(defines.events.on_console_command,function(event) local command = event.command local args = {} if event.parameters then for word in event.parameters:gmatch('%S+') do table.insert(args,word) end end diff --git a/modules/ExpGamingBot/discordAlerts/softmod.json b/old/modules/ExpGamingBot/discordAlerts/softmod.json similarity index 100% rename from modules/ExpGamingBot/discordAlerts/softmod.json rename to old/modules/ExpGamingBot/discordAlerts/softmod.json diff --git a/modules/ExpGamingBot/softmod.json b/old/modules/ExpGamingBot/softmod.json similarity index 100% rename from modules/ExpGamingBot/softmod.json rename to old/modules/ExpGamingBot/softmod.json diff --git a/modules/ExpGamingCommands/bonus/control.lua b/old/modules/ExpGamingCommands/bonus/control.lua similarity index 90% rename from modules/ExpGamingCommands/bonus/control.lua rename to old/modules/ExpGamingCommands/bonus/control.lua index e772de80e2..97fc3f720f 100644 --- a/modules/ExpGamingCommands/bonus/control.lua +++ b/old/modules/ExpGamingCommands/bonus/control.lua @@ -3,7 +3,8 @@ -- @author Cooldude2606 -- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE -local global = global{} +local global = {} +Global.register(global,function(tbl) global = tbl end) local Game = require('FactorioStdLib.Game') -- these are the settings which are changed with scale being as +100% @@ -29,7 +30,7 @@ commands.add_command('bonus', 'Set your player bonus (default is 20, guest has 0 player_return('Bonus set to: '..math.floor(bonus)..'%') end).default_admin_only = true -script.on_event(defines.events.on_player_respawned,function(event) +Event.add(defines.events.on_player_respawned,function(event) local player = Game.get_player(event) local bonus = global[player.index] if bonus then @@ -38,7 +39,7 @@ script.on_event(defines.events.on_player_respawned,function(event) end) -- overridden by ExpGamingCore.Role if present -script.on_event(defines.events.on_pre_player_died,function(event) +Event.add(defines.events.on_pre_player_died,function(event) local player = Game.get_player(event) if player.admin then player.ticks_to_respawn = 120 @@ -57,7 +58,7 @@ return { if loaded_modules['ExpGamingCore.Role'] then local Role = require('ExpGamingCore.Role') -- instant respawn - script.on_event(defines.events.on_pre_player_died,function(event) + Event.add(defines.events.on_pre_player_died,function(event) local player = Game.get_player(event) if Role.allowed(player,'bonus-respawn') then player.ticks_to_respawn = 120 @@ -71,7 +72,7 @@ return { end end) -- either clears or adds default when rank changed - script.on_event(defines.events.role_change,function(event) + Event.add(defines.events.role_change,function(event) local player = Game.get_player(event) if Role.allowed(player,'bonus') then for key,setting in pairs(settings) do player[key] = setting*0.2 end diff --git a/modules/ExpGamingCommands/bonus/softmod.json b/old/modules/ExpGamingCommands/bonus/softmod.json similarity index 100% rename from modules/ExpGamingCommands/bonus/softmod.json rename to old/modules/ExpGamingCommands/bonus/softmod.json diff --git a/modules/ExpGamingCommands/cheatMode/control.lua b/old/modules/ExpGamingCommands/cheatMode/control.lua similarity index 100% rename from modules/ExpGamingCommands/cheatMode/control.lua rename to old/modules/ExpGamingCommands/cheatMode/control.lua diff --git a/modules/ExpGamingCommands/cheatMode/softmod.json b/old/modules/ExpGamingCommands/cheatMode/softmod.json similarity index 100% rename from modules/ExpGamingCommands/cheatMode/softmod.json rename to old/modules/ExpGamingCommands/cheatMode/softmod.json diff --git a/modules/ExpGamingCommands/home/control.lua b/old/modules/ExpGamingCommands/home/control.lua similarity index 97% rename from modules/ExpGamingCommands/home/control.lua rename to old/modules/ExpGamingCommands/home/control.lua index 5edc3fbbc2..a30f9087fa 100644 --- a/modules/ExpGamingCommands/home/control.lua +++ b/old/modules/ExpGamingCommands/home/control.lua @@ -4,7 +4,8 @@ -- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE local Game = require('FactorioStdLib.Game') -local global = global{} +local global = {} +Global.register(global,function(tbl) global = tbl end) --- Sets the home for a player -- @command set-home diff --git a/modules/ExpGamingCommands/home/locale/en.cfg b/old/modules/ExpGamingCommands/home/locale/en.cfg similarity index 100% rename from modules/ExpGamingCommands/home/locale/en.cfg rename to old/modules/ExpGamingCommands/home/locale/en.cfg diff --git a/modules/ExpGamingCommands/home/softmod.json b/old/modules/ExpGamingCommands/home/softmod.json similarity index 100% rename from modules/ExpGamingCommands/home/softmod.json rename to old/modules/ExpGamingCommands/home/softmod.json diff --git a/modules/ExpGamingCommands/kill/control.lua b/old/modules/ExpGamingCommands/kill/control.lua similarity index 100% rename from modules/ExpGamingCommands/kill/control.lua rename to old/modules/ExpGamingCommands/kill/control.lua diff --git a/modules/ExpGamingCommands/kill/softmod.json b/old/modules/ExpGamingCommands/kill/softmod.json similarity index 100% rename from modules/ExpGamingCommands/kill/softmod.json rename to old/modules/ExpGamingCommands/kill/softmod.json diff --git a/modules/ExpGamingCommands/repair/control.lua b/old/modules/ExpGamingCommands/repair/control.lua similarity index 100% rename from modules/ExpGamingCommands/repair/control.lua rename to old/modules/ExpGamingCommands/repair/control.lua diff --git a/modules/ExpGamingCommands/repair/softmod.json b/old/modules/ExpGamingCommands/repair/softmod.json similarity index 100% rename from modules/ExpGamingCommands/repair/softmod.json rename to old/modules/ExpGamingCommands/repair/softmod.json diff --git a/modules/ExpGamingCommands/repair/src/tempban.lua b/old/modules/ExpGamingCommands/repair/src/tempban.lua similarity index 100% rename from modules/ExpGamingCommands/repair/src/tempban.lua rename to old/modules/ExpGamingCommands/repair/src/tempban.lua diff --git a/modules/ExpGamingCommands/softmod.json b/old/modules/ExpGamingCommands/softmod.json similarity index 100% rename from modules/ExpGamingCommands/softmod.json rename to old/modules/ExpGamingCommands/softmod.json diff --git a/modules/ExpGamingCommands/tags/control.lua b/old/modules/ExpGamingCommands/tags/control.lua similarity index 100% rename from modules/ExpGamingCommands/tags/control.lua rename to old/modules/ExpGamingCommands/tags/control.lua diff --git a/modules/ExpGamingCommands/tags/softmod.json b/old/modules/ExpGamingCommands/tags/softmod.json similarity index 100% rename from modules/ExpGamingCommands/tags/softmod.json rename to old/modules/ExpGamingCommands/tags/softmod.json diff --git a/modules/ExpGamingCommands/teleport/control.lua b/old/modules/ExpGamingCommands/teleport/control.lua similarity index 100% rename from modules/ExpGamingCommands/teleport/control.lua rename to old/modules/ExpGamingCommands/teleport/control.lua diff --git a/modules/ExpGamingCommands/teleport/softmod.json b/old/modules/ExpGamingCommands/teleport/softmod.json similarity index 100% rename from modules/ExpGamingCommands/teleport/softmod.json rename to old/modules/ExpGamingCommands/teleport/softmod.json diff --git a/modules/ExpGamingCore/Command/control.lua b/old/modules/ExpGamingCore/Command/control.lua similarity index 89% rename from modules/ExpGamingCore/Command/control.lua rename to old/modules/ExpGamingCore/Command/control.lua index 84b00e4957..72cdde363b 100644 --- a/modules/ExpGamingCore/Command/control.lua +++ b/old/modules/ExpGamingCore/Command/control.lua @@ -59,40 +59,40 @@ commands.validate = { ['string-inf']=function(value) return tostring(value) end, ['string-list']=function(value,event,list) local rtn = tostring(value) and table.includes(list,tostring(value)) and tostring(value) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-string-list',table.concat(list,', ')} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-string-list',table.concat(list,', ')} end return rtn end, ['string-len']=function(value,event,max) local rtn = tostring(value) and tostring(value):len() <= max and tostring(value) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-string-len',max} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-string-len',max} end return rtn end, ['number']=function(value) local rtn = tonumber(value) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-number'} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-number'} end return rtn end, ['number-int']=function(value) local rtn = tonumber(value) and math.floor(tonumber(value)) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-number'} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-number'} end return rtn end, ['number-range']=function(value,event,min,max) local rtn = tonumber(value) and tonumber(value) > min and tonumber(value) <= max and tonumber(value) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-number-range',min,max} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-number-range',min,max} end return rtn end, ['number-range-int']=function(value,event,min,max) local rtn = tonumber(value) and math.floor(tonumber(value)) > min and math.floor(tonumber(value)) <= max and math.floor(tonumber(value)) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-number-range',min,max} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-number-range',min,max} end return rtn end, ['player']=function(value) local rtn = Game.get_player(value) or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-player',value} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-player',value} end return rtn end, ['player-online']=function(value) local player,err = commands.validate['player'](value) if err then return commands.error(err) end local rtn = player.connected and player or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-player-online'} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-player-online'} end return rtn end, ['player-alive']=function(value) local player,err = commands.validate['player-online'](value) if err then return commands.error(err) end local rtn = player.character and player.character.health > 0 and player or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-player-alive'} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-player-alive'} end return rtn end, ['player-rank']=function(value,event) local player,err = commands.validate['player'](value) if err then return commands.error(err) end local rtn = player.admin and Game.get_player(event).admin and player or nil - if not rtn then return commands.error{'ExpGamingCore_Command.error-player-rank'} end return rtn end, + if not rtn then return commands.error{'expcore-commands.error-player-rank'} end return rtn end, ['player-rank-online']=function(value) local player,err = commands.validate['player-online'](value) if err then return commands.error(err) end @@ -212,13 +212,13 @@ local function run_custom_command(command) local success, err = pcall(callback,player,command.name,command) if not success then error(err) elseif not err then - player_return({'ExpGamingCore_Command.command-fail',{'ExpGamingCore_Command.unauthorized'}},defines.textcolor.crit) + player_return({'expcore-commands.command-fail',{'expcore-commands.unauthorized'}},defines.textcolor.crit) logMessage(player.name,command,'Failed to use command (Unauthorized)',commands.validate_args(command)) game.player.play_sound{path='utility/cannot_build'} return end end elseif data.default_admin_only == true and player and not player.admin then - player_return({'ExpGamingCore_Command.command-fail',{'ExpGamingCore_Command.unauthorized'}},defines.textcolor.crit) + player_return({'expcore-commands.command-fail',{'expcore-commands.unauthorized'}},defines.textcolor.crit) logMessage(player.name,command,'Failed to use command (Unauthorized)',commands.validate_args(command)) game.player.play_sound{path='utility/cannot_build'} return @@ -227,7 +227,7 @@ local function run_custom_command(command) local args, err = commands.validate_args(command) if args == commands.error then if is_type(err,'table') then table.insert(err,command.name) table.insert(err,commands.format_inputs(data)) - player_return({'ExpGamingCore_Command.command-fail',err},defines.textcolor.high) else player_return({'ExpGamingCore_Command.command-fail',{'ExpGamingCore_Command.invalid-inputs',command.name,commands.format_inputs(data)}},defines.textcolor.high) end + player_return({'expcore-commands.command-fail',err},defines.textcolor.high) else player_return({'expcore-commands.command-fail',{'expcore-commands.invalid-inputs',command.name,commands.format_inputs(data)}},defines.textcolor.high) end logMessage(player.name,command,'Failed to use command (Invalid Args)',args) player.play_sound{path='utility/deconstruct_big'} return @@ -235,7 +235,7 @@ local function run_custom_command(command) -- runs the command local success, err = pcall(data.callback,command,args) if not success then error(err) end - if err ~= commands.error then player_return({'ExpGamingCore_Command.command-ran'},defines.textcolor.info) end + if err ~= commands.error then player_return({'expcore-commands.command-ran'},defines.textcolor.info) end logMessage(player.name,command,'Used command',args) end diff --git a/modules/ExpGamingCore/Command/softmod.json b/old/modules/ExpGamingCore/Command/softmod.json similarity index 100% rename from modules/ExpGamingCore/Command/softmod.json rename to old/modules/ExpGamingCore/Command/softmod.json diff --git a/modules/ExpGamingCore/Group/config.lua b/old/modules/ExpGamingCore/Group/config.lua similarity index 100% rename from modules/ExpGamingCore/Group/config.lua rename to old/modules/ExpGamingCore/Group/config.lua diff --git a/modules/ExpGamingCore/Group/control.lua b/old/modules/ExpGamingCore/Group/control.lua similarity index 99% rename from modules/ExpGamingCore/Group/control.lua rename to old/modules/ExpGamingCore/Group/control.lua index 3506fdf72e..97843d3502 100644 --- a/modules/ExpGamingCore/Group/control.lua +++ b/old/modules/ExpGamingCore/Group/control.lua @@ -171,7 +171,7 @@ end -- Event Handlers Define -- creates all permission groups and links them -script.on_event('on_init',function() +Event.add('on_init',function() for name,group in pairs(Group.groups) do local _group = game.permissions.create_group(name) verbose('Created Permission Group: '..name) diff --git a/modules/ExpGamingCore/Group/softmod.json b/old/modules/ExpGamingCore/Group/softmod.json similarity index 100% rename from modules/ExpGamingCore/Group/softmod.json rename to old/modules/ExpGamingCore/Group/softmod.json diff --git a/modules/ExpGamingCore/Gui/center/control.lua b/old/modules/ExpGamingCore/Gui/center/control.lua similarity index 97% rename from modules/ExpGamingCore/Gui/center/control.lua rename to old/modules/ExpGamingCore/Gui/center/control.lua index eb3b8da0ff..50b46d0101 100644 --- a/modules/ExpGamingCore/Gui/center/control.lua +++ b/old/modules/ExpGamingCore/Gui/center/control.lua @@ -208,14 +208,14 @@ function center._prototype:add_tab(name,caption,tooltip,callback) end -- used so that when gui close key is pressed this will close the gui -script.on_event(defines.events.on_gui_closed,function(event) +Event.add(defines.events.on_gui_closed,function(event) if event.element and event.element.valid then event.element.destroy() end end) -script.on_event(defines.events.on_player_respawned,center.clear) +Event.add(defines.events.on_player_respawned,center.clear) function center.on_init() - if loaded_modules['ExpGamingCore.Role'] then script.on_event(defines.events.on_role_change,center.clear) end + if loaded_modules['ExpGamingCore.Role'] then Event.add(defines.events.on_role_change,center.clear) end end -- calling will attempt to add a new gui return setmetatable(center,{__call=function(self,...) return self.add(...) end}) \ No newline at end of file diff --git a/modules/ExpGamingCore/Gui/center/softmod.json b/old/modules/ExpGamingCore/Gui/center/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/center/softmod.json rename to old/modules/ExpGamingCore/Gui/center/softmod.json diff --git a/modules/ExpGamingCore/Gui/control.lua b/old/modules/ExpGamingCore/Gui/control.lua similarity index 98% rename from modules/ExpGamingCore/Gui/control.lua rename to old/modules/ExpGamingCore/Gui/control.lua index 0877c3228e..1ffe615fc6 100644 --- a/modules/ExpGamingCore/Gui/control.lua +++ b/old/modules/ExpGamingCore/Gui/control.lua @@ -9,7 +9,8 @@ local Color = require('FactorioStdLib.Color') local Server -- ExpGamingCore.Server@?^4.0.0 local Gui = {} -local global = global() +local global = {} +Global.register(global,function(tbl) global = tbl end) --- Used to set and get data about different guis -- @usage Gui.data[location] -- returns the gui data for that gui location ex center -- @usage Gui.data(location,gui_name,gui_data) -- adds gui data for a gui at a location @@ -140,7 +141,7 @@ function Gui.cam_link(data) return data.cam end -script.on_event('on_tick', function(event) +Event.add('on_tick', function(event) if loaded_modules['ExpGamingCore.Server'] then return end if global.cams and is_type(global.cams,'table') and #global.cams > 0 then local update = 4 @@ -158,7 +159,7 @@ script.on_event('on_tick', function(event) end end) -script.on_event('on_player_respawned',function(event) +Event.add('on_player_respawned',function(event) if loaded_modules['ExpGamingCore.Server'] then return end if global.players and is_type(global.players,'table') and #global.players > 0 and global.players[event.player_index] then local remove = {} diff --git a/modules/ExpGamingCore/Gui/inputs/control.lua b/old/modules/ExpGamingCore/Gui/inputs/control.lua similarity index 99% rename from modules/ExpGamingCore/Gui/inputs/control.lua rename to old/modules/ExpGamingCore/Gui/inputs/control.lua index 54abfe48a8..9d6aab036a 100644 --- a/modules/ExpGamingCore/Gui/inputs/control.lua +++ b/old/modules/ExpGamingCore/Gui/inputs/control.lua @@ -136,7 +136,7 @@ function inputs._event_handler(event) end end -script.on_event(inputs.events,inputs._event_handler) +Event.add(inputs.events,inputs._event_handler) inputs.events.error = {} -- the following functions are just to make inputs easier but if what you want is not include use inputs.add(obj) diff --git a/modules/ExpGamingCore/Gui/inputs/softmod.json b/old/modules/ExpGamingCore/Gui/inputs/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/inputs/softmod.json rename to old/modules/ExpGamingCore/Gui/inputs/softmod.json diff --git a/modules/ExpGamingCore/Gui/left/control.lua b/old/modules/ExpGamingCore/Gui/left/control.lua similarity index 98% rename from modules/ExpGamingCore/Gui/left/control.lua rename to old/modules/ExpGamingCore/Gui/left/control.lua index 7de7a90499..ac281d58d9 100644 --- a/modules/ExpGamingCore/Gui/left/control.lua +++ b/old/modules/ExpGamingCore/Gui/left/control.lua @@ -27,7 +27,8 @@ left.hide = Gui.inputs{ end end) -local global = global() +local global = {} +Global.register(global,function(tbl) global = tbl end) -- used for debugging function left.override_open(state) @@ -212,7 +213,7 @@ function left._prototype:toggle(player) return left_frame.style.visible end -script.on_event(defines.events.on_player_joined_game,function(event) +Event.add(defines.events.on_player_joined_game,function(event) -- draws the left guis when a player first joins, fake_event is just because i am lazy local player = Game.get_player(event) local frames = Gui.data.left or {} @@ -231,7 +232,7 @@ script.on_event(defines.events.on_player_joined_game,function(event) end end) -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if ((event.tick+10)/(3600*game.speed)) % 15 == 0 then left.update() end diff --git a/modules/ExpGamingCore/Gui/left/order_config.lua b/old/modules/ExpGamingCore/Gui/left/order_config.lua similarity index 100% rename from modules/ExpGamingCore/Gui/left/order_config.lua rename to old/modules/ExpGamingCore/Gui/left/order_config.lua diff --git a/modules/ExpGamingCore/Gui/left/softmod.json b/old/modules/ExpGamingCore/Gui/left/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/left/softmod.json rename to old/modules/ExpGamingCore/Gui/left/softmod.json diff --git a/modules/ExpGamingCore/Gui/locale/de.cfg b/old/modules/ExpGamingCore/Gui/locale/de.cfg similarity index 100% rename from modules/ExpGamingCore/Gui/locale/de.cfg rename to old/modules/ExpGamingCore/Gui/locale/de.cfg diff --git a/modules/ExpGamingCore/Gui/locale/en.cfg b/old/modules/ExpGamingCore/Gui/locale/en.cfg similarity index 100% rename from modules/ExpGamingCore/Gui/locale/en.cfg rename to old/modules/ExpGamingCore/Gui/locale/en.cfg diff --git a/modules/ExpGamingCore/Gui/locale/fr.cfg b/old/modules/ExpGamingCore/Gui/locale/fr.cfg similarity index 100% rename from modules/ExpGamingCore/Gui/locale/fr.cfg rename to old/modules/ExpGamingCore/Gui/locale/fr.cfg diff --git a/modules/ExpGamingCore/Gui/locale/nl.cfg b/old/modules/ExpGamingCore/Gui/locale/nl.cfg similarity index 100% rename from modules/ExpGamingCore/Gui/locale/nl.cfg rename to old/modules/ExpGamingCore/Gui/locale/nl.cfg diff --git a/modules/ExpGamingCore/Gui/locale/sv-SE.cfg b/old/modules/ExpGamingCore/Gui/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingCore/Gui/locale/sv-SE.cfg rename to old/modules/ExpGamingCore/Gui/locale/sv-SE.cfg diff --git a/modules/ExpGamingCore/Gui/popup/control.lua b/old/modules/ExpGamingCore/Gui/popup/control.lua similarity index 98% rename from modules/ExpGamingCore/Gui/popup/control.lua rename to old/modules/ExpGamingCore/Gui/popup/control.lua index 7a49bae3f6..a773c90185 100644 --- a/modules/ExpGamingCore/Gui/popup/control.lua +++ b/old/modules/ExpGamingCore/Gui/popup/control.lua @@ -124,7 +124,7 @@ function popup.on_post() end) end -script.on_event(defines.events.on_player_joined_game,popup.flow) +Event.add(defines.events.on_player_joined_game,popup.flow) -- calling will attempt to add a new popup style return setmetatable(popup,{__call=function(self,...) return self.add(...) end}) \ No newline at end of file diff --git a/modules/ExpGamingCore/Gui/popup/softmod.json b/old/modules/ExpGamingCore/Gui/popup/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/popup/softmod.json rename to old/modules/ExpGamingCore/Gui/popup/softmod.json diff --git a/modules/ExpGamingCore/Gui/softmod.json b/old/modules/ExpGamingCore/Gui/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/softmod.json rename to old/modules/ExpGamingCore/Gui/softmod.json diff --git a/modules/ExpGamingCore/Gui/src/server.lua b/old/modules/ExpGamingCore/Gui/src/server.lua similarity index 100% rename from modules/ExpGamingCore/Gui/src/server.lua rename to old/modules/ExpGamingCore/Gui/src/server.lua diff --git a/modules/ExpGamingCore/Gui/src/test.lua b/old/modules/ExpGamingCore/Gui/src/test.lua similarity index 100% rename from modules/ExpGamingCore/Gui/src/test.lua rename to old/modules/ExpGamingCore/Gui/src/test.lua diff --git a/modules/ExpGamingCore/Gui/toolbar/control.lua b/old/modules/ExpGamingCore/Gui/toolbar/control.lua similarity index 97% rename from modules/ExpGamingCore/Gui/toolbar/control.lua rename to old/modules/ExpGamingCore/Gui/toolbar/control.lua index cae2f46734..a31f2d98c0 100644 --- a/modules/ExpGamingCore/Gui/toolbar/control.lua +++ b/old/modules/ExpGamingCore/Gui/toolbar/control.lua @@ -85,6 +85,6 @@ function toolbar.on_init() if loaded_modules['ExpGamingCore.Role'] then Role = require('ExpGamingCore.Role') end end -script.on_event({defines.events.on_role_change,defines.events.on_player_joined_game},toolbar.draw) +Event.add({defines.events.on_role_change,defines.events.on_player_joined_game},toolbar.draw) -- calling with only a player will draw the toolbar for that player, more params will attempt to add a button return setmetatable(toolbar,{__call=function(self,player,extra,...) if extra then return self.add(player,extra,...) else self.draw(player) end end}) \ No newline at end of file diff --git a/modules/ExpGamingCore/Gui/toolbar/order_config.lua b/old/modules/ExpGamingCore/Gui/toolbar/order_config.lua similarity index 100% rename from modules/ExpGamingCore/Gui/toolbar/order_config.lua rename to old/modules/ExpGamingCore/Gui/toolbar/order_config.lua diff --git a/modules/ExpGamingCore/Gui/toolbar/softmod.json b/old/modules/ExpGamingCore/Gui/toolbar/softmod.json similarity index 100% rename from modules/ExpGamingCore/Gui/toolbar/softmod.json rename to old/modules/ExpGamingCore/Gui/toolbar/softmod.json diff --git a/modules/ExpGamingCore/Role/config.lua b/old/modules/ExpGamingCore/Role/config.lua similarity index 100% rename from modules/ExpGamingCore/Role/config.lua rename to old/modules/ExpGamingCore/Role/config.lua diff --git a/modules/ExpGamingCore/Role/control.lua b/old/modules/ExpGamingCore/Role/control.lua similarity index 99% rename from modules/ExpGamingCore/Role/control.lua rename to old/modules/ExpGamingCore/Role/control.lua index 77e9d204ff..fa0494461a 100644 --- a/modules/ExpGamingCore/Role/control.lua +++ b/old/modules/ExpGamingCore/Role/control.lua @@ -61,7 +61,7 @@ local Role = { _RoleSelfReference=Role -- Global Define -local global = global{ +local global = { change_cache_length=15, changes={}, latest_change={}, @@ -69,7 +69,8 @@ local global = global{ players={}, roles={} } -RoleGlobal = global +Global.register(global,function(tbl) RoleGlobal = tbl end) + -- Function Define --- Used to set default roles for players who join @@ -459,7 +460,7 @@ function Role._prototype:remove_player(player,by_player,batch) end -- Event Handlers Define -script.on_event(role_change_event_id,function(event) +Event.add(role_change_event_id,function(event) -- variable init local player = Game.get_player(event) local by_player = Game.get_player(event.by_player_index) or SERVER @@ -505,7 +506,7 @@ script.on_event(role_change_event_id,function(event) end end) -script.on_event(defines.events.on_player_created,function(event) +Event.add(defines.events.on_player_created,function(event) local player = Game.get_player(event) local highest = Role.get_highest(player) or Role.meta.default Group.assign(player,highest.group) @@ -514,7 +515,7 @@ script.on_event(defines.events.on_player_created,function(event) if Role.preassign[player.name:lower()] then Role.assign(player,Role.preassign[player.name:lower()]) end end) -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if game.tick%(3600*5) ~= 0 then return end -- every 5 minutes for _,player in pairs(game.connected_players) do if not Role.has_flag(player,'block_auto_promote') then diff --git a/modules/ExpGamingCore/Role/locale/en.cfg b/old/modules/ExpGamingCore/Role/locale/en.cfg similarity index 100% rename from modules/ExpGamingCore/Role/locale/en.cfg rename to old/modules/ExpGamingCore/Role/locale/en.cfg diff --git a/modules/ExpGamingCore/Role/softmod.json b/old/modules/ExpGamingCore/Role/softmod.json similarity index 100% rename from modules/ExpGamingCore/Role/softmod.json rename to old/modules/ExpGamingCore/Role/softmod.json diff --git a/modules/ExpGamingCore/Role/src/commands.lua b/old/modules/ExpGamingCore/Role/src/commands.lua similarity index 100% rename from modules/ExpGamingCore/Role/src/commands.lua rename to old/modules/ExpGamingCore/Role/src/commands.lua diff --git a/modules/ExpGamingCore/Role/src/sync.lua b/old/modules/ExpGamingCore/Role/src/sync.lua similarity index 98% rename from modules/ExpGamingCore/Role/src/sync.lua rename to old/modules/ExpGamingCore/Role/src/sync.lua index 36f0fdbe7e..6f5361ad01 100644 --- a/modules/ExpGamingCore/Role/src/sync.lua +++ b/old/modules/ExpGamingCore/Role/src/sync.lua @@ -65,7 +65,7 @@ if Sync.add_to_gui then end -- adds a discord emit for rank changing -script.on_event('on_role_change',function(event) +Event.add('on_role_change',function(event) local role = Role.get(event.role_name) local player = Game.get_player(event) local by_player = Game.get_player(event.by_player_index) or SERVER diff --git a/modules/ExpGamingCore/Server/control.lua b/old/modules/ExpGamingCore/Server/control.lua similarity index 98% rename from modules/ExpGamingCore/Server/control.lua rename to old/modules/ExpGamingCore/Server/control.lua index bcc6d57c52..33523468ff 100644 --- a/modules/ExpGamingCore/Server/control.lua +++ b/old/modules/ExpGamingCore/Server/control.lua @@ -22,7 +22,7 @@ local module_verbose = false --true|false -- @field print_to contains players that event details will be printed to -- @field uuid contains the random number generator for the uuid system local pre_load_uuid = 0 -local global = global{ +local global = { all={_n=0}, queue={}, tick={}, @@ -33,6 +33,7 @@ local global = global{ print_to={}, uuid=0 } +Global.register(global,function(tbl) global = tbl end) --- Used to generate a new uuid for the thread system -- @usage local uuid = tostring(Server.uuid) -- calling tostring locks the value @@ -155,9 +156,9 @@ function Server._thread_debuger(player,event,state) else print_to[player.index][event] = true end end ---- Calls all threads on a certain game event (used with script.on_event) +--- Calls all threads on a certain game event (used with Event.add) -- @local Server._thread_handler --- @usage script.on_event(defines.events,Server._thread_handler) -- adds this handler +-- @usage Event.add(defines.events,Server._thread_handler) -- adds this handler -- @tparam table event the event that is called function Server._thread_handler(event) -- returns to players who have set _thread_debuger to true @@ -195,7 +196,7 @@ function Server.add_thread_handler(event) local threads = global if not threads.events[event] then threads.events[event] = {} - script.on_event(event,Server._thread_handler) + Event.add(event,Server._thread_handler) return true end return false @@ -485,7 +486,7 @@ function Server._thread:on_event(event,callback) return self end -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) -- uses its own on_tick event so that other actions can be tested for if event.tick < 10 then return end if #global.tick > 0 then Server.run_tick_threads() end -- on tick events @@ -505,7 +506,7 @@ script.on_load(function(event) end) function Server:on_init() - for name,id in pairs(defines.events) do if not script.get_event_handler(id) then script.on_event(id,Server._thread_handler) end end + for name,id in pairs(defines.events) do if not script.get_event_handler(id) then Event.add(id,Server._thread_handler) end end if loaded_modules['ExpGamingCore.Command'] then verbose('ExpGamingCore.Command is installed; Loading commands src') require(module_path..'/src/commands',{Server=Server}) end end diff --git a/modules/ExpGamingCore/Server/softmod.json b/old/modules/ExpGamingCore/Server/softmod.json similarity index 100% rename from modules/ExpGamingCore/Server/softmod.json rename to old/modules/ExpGamingCore/Server/softmod.json diff --git a/modules/ExpGamingCore/Server/src/commands.lua b/old/modules/ExpGamingCore/Server/src/commands.lua similarity index 100% rename from modules/ExpGamingCore/Server/src/commands.lua rename to old/modules/ExpGamingCore/Server/src/commands.lua diff --git a/modules/ExpGamingCore/Sync/control.lua b/old/modules/ExpGamingCore/Sync/control.lua similarity index 98% rename from modules/ExpGamingCore/Sync/control.lua rename to old/modules/ExpGamingCore/Sync/control.lua index bfd91b4342..4a780a95a5 100644 --- a/modules/ExpGamingCore/Sync/control.lua +++ b/old/modules/ExpGamingCore/Sync/control.lua @@ -24,7 +24,7 @@ local module_verbose = false --true|false -- @field ranks a list of player ranks -- @field rockets the number of rockets launched -- @field mods the mods which are loaded -local global = global{ +local global = { server_name='Factorio Server', server_description='A factorio server for everyone', reset_time='On Demand', @@ -47,6 +47,7 @@ local global = global{ rockets=0, mods={'Offline'} } +Global.register(global,function(tbl) global = tbl end) --- Player sub-table -- @table global.players @@ -316,14 +317,14 @@ Sync.time=add_metatable({},function(full,date) end,function() local info = Sync.info return info.time..' (+'..(game.tick-info.time_set[1])..' Ticks)' end) -- will auto replace the file every 5 min by default -script.on_event('on_tick',function(event) +Event.add('on_tick',function(event) local time = Sync.info.time_period[1] if (event.tick%time)==0 then Sync.emit_update() end end) -script.on_event('on_player_joined_game',Sync.emit_update) -script.on_event('on_pre_player_left_game',Sync.emit_update) -script.on_event('on_rocket_launched',Sync.emit_update) +Event.add('on_player_joined_game',Sync.emit_update) +Event.add('on_pre_player_left_game',Sync.emit_update) +Event.add('on_rocket_launched',Sync.emit_update) function Sync:on_init() if loaded_modules['ExpGamingCore.Gui'] then verbose('ExpGamingCore.Gui is installed; Loading gui src') require(module_path..'/src/gui',{Sync=Sync,module_path=module_path}) end diff --git a/modules/ExpGamingCore/Sync/softmod.json b/old/modules/ExpGamingCore/Sync/softmod.json similarity index 100% rename from modules/ExpGamingCore/Sync/softmod.json rename to old/modules/ExpGamingCore/Sync/softmod.json diff --git a/modules/ExpGamingCore/Sync/src/gui.lua b/old/modules/ExpGamingCore/Sync/src/gui.lua similarity index 96% rename from modules/ExpGamingCore/Sync/src/gui.lua rename to old/modules/ExpGamingCore/Sync/src/gui.lua index f01ebf2a97..72c256dd05 100644 --- a/modules/ExpGamingCore/Sync/src/gui.lua +++ b/old/modules/ExpGamingCore/Sync/src/gui.lua @@ -96,11 +96,11 @@ Sync.info_gui = Gui.center{ }.style.font='default-small' end} -script.on_event(defines.events.on_gui_click,function(event) +Event.add(defines.events.on_gui_click,function(event) local element = event.element if element and element.valid and element.caption and element.caption == 'Press Ecs or E to close; this is only visible once!' then Gui.center.clear(event) end end) -script.on_event(defines.events.on_player_joined_game,function(event) Sync.info_gui(event) end) \ No newline at end of file +Event.add(defines.events.on_player_joined_game,function(event) Sync.info_gui(event) end) \ No newline at end of file diff --git a/modules/ExpGamingCore/Sync/src/logo.png b/old/modules/ExpGamingCore/Sync/src/logo.png similarity index 100% rename from modules/ExpGamingCore/Sync/src/logo.png rename to old/modules/ExpGamingCore/Sync/src/logo.png diff --git a/modules/ExpGamingCore/softmod.json b/old/modules/ExpGamingCore/softmod.json similarity index 100% rename from modules/ExpGamingCore/softmod.json rename to old/modules/ExpGamingCore/softmod.json diff --git a/modules/ExpGamingInfo/Readme/control.lua b/old/modules/ExpGamingInfo/Readme/control.lua similarity index 100% rename from modules/ExpGamingInfo/Readme/control.lua rename to old/modules/ExpGamingInfo/Readme/control.lua diff --git a/modules/ExpGamingInfo/Readme/locale/de.cfg b/old/modules/ExpGamingInfo/Readme/locale/de.cfg similarity index 100% rename from modules/ExpGamingInfo/Readme/locale/de.cfg rename to old/modules/ExpGamingInfo/Readme/locale/de.cfg diff --git a/modules/ExpGamingInfo/Readme/locale/en.cfg b/old/modules/ExpGamingInfo/Readme/locale/en.cfg similarity index 100% rename from modules/ExpGamingInfo/Readme/locale/en.cfg rename to old/modules/ExpGamingInfo/Readme/locale/en.cfg diff --git a/modules/ExpGamingInfo/Readme/locale/fr.cfg b/old/modules/ExpGamingInfo/Readme/locale/fr.cfg similarity index 100% rename from modules/ExpGamingInfo/Readme/locale/fr.cfg rename to old/modules/ExpGamingInfo/Readme/locale/fr.cfg diff --git a/modules/ExpGamingInfo/Readme/locale/nl.cfg b/old/modules/ExpGamingInfo/Readme/locale/nl.cfg similarity index 100% rename from modules/ExpGamingInfo/Readme/locale/nl.cfg rename to old/modules/ExpGamingInfo/Readme/locale/nl.cfg diff --git a/modules/ExpGamingInfo/Readme/locale/sv-SE.cfg b/old/modules/ExpGamingInfo/Readme/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingInfo/Readme/locale/sv-SE.cfg rename to old/modules/ExpGamingInfo/Readme/locale/sv-SE.cfg diff --git a/modules/ExpGamingInfo/Readme/softmod.json b/old/modules/ExpGamingInfo/Readme/softmod.json similarity index 100% rename from modules/ExpGamingInfo/Readme/softmod.json rename to old/modules/ExpGamingInfo/Readme/softmod.json diff --git a/modules/ExpGamingInfo/Readme/src/sync.lua b/old/modules/ExpGamingInfo/Readme/src/sync.lua similarity index 100% rename from modules/ExpGamingInfo/Readme/src/sync.lua rename to old/modules/ExpGamingInfo/Readme/src/sync.lua diff --git a/modules/ExpGamingInfo/Rockets/control.lua b/old/modules/ExpGamingInfo/Rockets/control.lua similarity index 95% rename from modules/ExpGamingInfo/Rockets/control.lua rename to old/modules/ExpGamingInfo/Rockets/control.lua index 6edd2130d1..d11f558d7d 100644 --- a/modules/ExpGamingInfo/Rockets/control.lua +++ b/old/modules/ExpGamingInfo/Rockets/control.lua @@ -17,7 +17,7 @@ local ThisModule = { } -- Global Define -local global = global{ +local global = { update=0, first=0, _last=0, @@ -25,6 +25,7 @@ local global = global{ fastest=0, milestones={m1=0,m2=0,m5=0,m10=0,m20=0,m50=0,m100=0,m200=0,m500=0,m1000=0,m2000=0,m5000=0} } +Global.register(global,function(tbl) global = tbl end) -- Function Define ThisModule.Gui = Gui.left{ @@ -97,7 +98,7 @@ ThisModule.Gui = Gui.left{ } -- Event Define -script.on_event(defines.events.on_rocket_launched,function(event) Gui.left.update('rockets') end) +Event.add(defines.events.on_rocket_launched,function(event) Gui.left.update('rockets') end) -- Module Return -- when called will toggle the gui for that player, updates gui if no player given diff --git a/modules/ExpGamingInfo/Rockets/locale/de.cfg b/old/modules/ExpGamingInfo/Rockets/locale/de.cfg similarity index 100% rename from modules/ExpGamingInfo/Rockets/locale/de.cfg rename to old/modules/ExpGamingInfo/Rockets/locale/de.cfg diff --git a/modules/ExpGamingInfo/Rockets/locale/en.cfg b/old/modules/ExpGamingInfo/Rockets/locale/en.cfg similarity index 100% rename from modules/ExpGamingInfo/Rockets/locale/en.cfg rename to old/modules/ExpGamingInfo/Rockets/locale/en.cfg diff --git a/modules/ExpGamingInfo/Rockets/locale/fr.cfg b/old/modules/ExpGamingInfo/Rockets/locale/fr.cfg similarity index 100% rename from modules/ExpGamingInfo/Rockets/locale/fr.cfg rename to old/modules/ExpGamingInfo/Rockets/locale/fr.cfg diff --git a/modules/ExpGamingInfo/Rockets/locale/nl.cfg b/old/modules/ExpGamingInfo/Rockets/locale/nl.cfg similarity index 100% rename from modules/ExpGamingInfo/Rockets/locale/nl.cfg rename to old/modules/ExpGamingInfo/Rockets/locale/nl.cfg diff --git a/modules/ExpGamingInfo/Rockets/locale/sv-SE.cfg b/old/modules/ExpGamingInfo/Rockets/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingInfo/Rockets/locale/sv-SE.cfg rename to old/modules/ExpGamingInfo/Rockets/locale/sv-SE.cfg diff --git a/modules/ExpGamingInfo/Rockets/softmod.json b/old/modules/ExpGamingInfo/Rockets/softmod.json similarity index 100% rename from modules/ExpGamingInfo/Rockets/softmod.json rename to old/modules/ExpGamingInfo/Rockets/softmod.json diff --git a/modules/ExpGamingInfo/Rockets/src/sync.lua b/old/modules/ExpGamingInfo/Rockets/src/sync.lua similarity index 100% rename from modules/ExpGamingInfo/Rockets/src/sync.lua rename to old/modules/ExpGamingInfo/Rockets/src/sync.lua diff --git a/modules/ExpGamingInfo/Science/control.lua b/old/modules/ExpGamingInfo/Science/control.lua similarity index 95% rename from modules/ExpGamingInfo/Science/control.lua rename to old/modules/ExpGamingInfo/Science/control.lua index 741189606d..9edfa55f05 100644 --- a/modules/ExpGamingInfo/Science/control.lua +++ b/old/modules/ExpGamingInfo/Science/control.lua @@ -28,7 +28,7 @@ local ThisModule = { } -- Global Define -local global = global{ +local global = { _base={ update=0, _update=0, @@ -36,6 +36,7 @@ local global = global{ _made={0,0,0,0,0,0,0} } } +Global.register(global,function(tbl) global = tbl end) -- Function Define ThisModule.Gui = Gui.left{ @@ -98,7 +99,7 @@ ThisModule.Gui = Gui.left{ } -- Event Define -script.on_event(defines.events.on_research_finished,function(event) Gui.left.update('science') end) +Event.add(defines.events.on_research_finished,function(event) Gui.left.update('science') end) -- Module Return -- when called will toggle the gui for that player, if no player it will update the gui diff --git a/modules/ExpGamingInfo/Science/locale/de.cfg b/old/modules/ExpGamingInfo/Science/locale/de.cfg similarity index 100% rename from modules/ExpGamingInfo/Science/locale/de.cfg rename to old/modules/ExpGamingInfo/Science/locale/de.cfg diff --git a/modules/ExpGamingInfo/Science/locale/en.cfg b/old/modules/ExpGamingInfo/Science/locale/en.cfg similarity index 100% rename from modules/ExpGamingInfo/Science/locale/en.cfg rename to old/modules/ExpGamingInfo/Science/locale/en.cfg diff --git a/modules/ExpGamingInfo/Science/locale/fr.cfg b/old/modules/ExpGamingInfo/Science/locale/fr.cfg similarity index 100% rename from modules/ExpGamingInfo/Science/locale/fr.cfg rename to old/modules/ExpGamingInfo/Science/locale/fr.cfg diff --git a/modules/ExpGamingInfo/Science/locale/nl.cfg b/old/modules/ExpGamingInfo/Science/locale/nl.cfg similarity index 100% rename from modules/ExpGamingInfo/Science/locale/nl.cfg rename to old/modules/ExpGamingInfo/Science/locale/nl.cfg diff --git a/modules/ExpGamingInfo/Science/locale/sv-Se.cfg b/old/modules/ExpGamingInfo/Science/locale/sv-Se.cfg similarity index 100% rename from modules/ExpGamingInfo/Science/locale/sv-Se.cfg rename to old/modules/ExpGamingInfo/Science/locale/sv-Se.cfg diff --git a/modules/ExpGamingInfo/Science/softmod.json b/old/modules/ExpGamingInfo/Science/softmod.json similarity index 100% rename from modules/ExpGamingInfo/Science/softmod.json rename to old/modules/ExpGamingInfo/Science/softmod.json diff --git a/modules/ExpGamingInfo/Science/src/sync.lua b/old/modules/ExpGamingInfo/Science/src/sync.lua similarity index 100% rename from modules/ExpGamingInfo/Science/src/sync.lua rename to old/modules/ExpGamingInfo/Science/src/sync.lua diff --git a/modules/ExpGamingInfo/Tasklist/control.lua b/old/modules/ExpGamingInfo/Tasklist/control.lua similarity index 98% rename from modules/ExpGamingInfo/Tasklist/control.lua rename to old/modules/ExpGamingInfo/Tasklist/control.lua index 5754742d07..d8dbe8b589 100644 --- a/modules/ExpGamingInfo/Tasklist/control.lua +++ b/old/modules/ExpGamingInfo/Tasklist/control.lua @@ -14,7 +14,7 @@ local module_verbose = false local ThisModule = {} -- Global Define -local global = global{ +local global = { tasks={}, _edit={}, _base={ @@ -23,6 +23,7 @@ local global = global{ _editing={} } } +Global.register(global,function(tbl) global = tbl end) -- Function Define local edit = Gui.inputs{ diff --git a/modules/ExpGamingInfo/Tasklist/locale/de.cfg b/old/modules/ExpGamingInfo/Tasklist/locale/de.cfg similarity index 100% rename from modules/ExpGamingInfo/Tasklist/locale/de.cfg rename to old/modules/ExpGamingInfo/Tasklist/locale/de.cfg diff --git a/modules/ExpGamingInfo/Tasklist/locale/en.cfg b/old/modules/ExpGamingInfo/Tasklist/locale/en.cfg similarity index 100% rename from modules/ExpGamingInfo/Tasklist/locale/en.cfg rename to old/modules/ExpGamingInfo/Tasklist/locale/en.cfg diff --git a/modules/ExpGamingInfo/Tasklist/locale/fr.cfg b/old/modules/ExpGamingInfo/Tasklist/locale/fr.cfg similarity index 100% rename from modules/ExpGamingInfo/Tasklist/locale/fr.cfg rename to old/modules/ExpGamingInfo/Tasklist/locale/fr.cfg diff --git a/modules/ExpGamingInfo/Tasklist/locale/nl.cfg b/old/modules/ExpGamingInfo/Tasklist/locale/nl.cfg similarity index 100% rename from modules/ExpGamingInfo/Tasklist/locale/nl.cfg rename to old/modules/ExpGamingInfo/Tasklist/locale/nl.cfg diff --git a/modules/ExpGamingInfo/Tasklist/locale/sv-SE.cfg b/old/modules/ExpGamingInfo/Tasklist/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingInfo/Tasklist/locale/sv-SE.cfg rename to old/modules/ExpGamingInfo/Tasklist/locale/sv-SE.cfg diff --git a/modules/ExpGamingInfo/Tasklist/softmod.json b/old/modules/ExpGamingInfo/Tasklist/softmod.json similarity index 100% rename from modules/ExpGamingInfo/Tasklist/softmod.json rename to old/modules/ExpGamingInfo/Tasklist/softmod.json diff --git a/modules/ExpGamingInfo/softmod.json b/old/modules/ExpGamingInfo/softmod.json similarity index 100% rename from modules/ExpGamingInfo/softmod.json rename to old/modules/ExpGamingInfo/softmod.json diff --git a/modules/ExpGamingLib/control.lua b/old/modules/ExpGamingLib/control.lua similarity index 100% rename from modules/ExpGamingLib/control.lua rename to old/modules/ExpGamingLib/control.lua diff --git a/modules/ExpGamingLib/softmod.json b/old/modules/ExpGamingLib/softmod.json similarity index 100% rename from modules/ExpGamingLib/softmod.json rename to old/modules/ExpGamingLib/softmod.json diff --git a/modules/ExpGamingPlayer/afkKick/control.lua b/old/modules/ExpGamingPlayer/afkKick/control.lua similarity index 96% rename from modules/ExpGamingPlayer/afkKick/control.lua rename to old/modules/ExpGamingPlayer/afkKick/control.lua index aa8f1c1128..1add91c999 100644 --- a/modules/ExpGamingPlayer/afkKick/control.lua +++ b/old/modules/ExpGamingPlayer/afkKick/control.lua @@ -17,7 +17,7 @@ local function get_allowed_afk_time(player) return (role_count/role_index)*player_count end -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if (game.tick%3600) ~= 0 then return end for _,player in pairs(game.connected_players) do local afk = #game.connected_players < 3 and 10 or get_allowed_afk_time(player) diff --git a/modules/ExpGamingPlayer/afkKick/softmod.json b/old/modules/ExpGamingPlayer/afkKick/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/afkKick/softmod.json rename to old/modules/ExpGamingPlayer/afkKick/softmod.json diff --git a/modules/ExpGamingPlayer/afkKick/src/server.lua b/old/modules/ExpGamingPlayer/afkKick/src/server.lua similarity index 100% rename from modules/ExpGamingPlayer/afkKick/src/server.lua rename to old/modules/ExpGamingPlayer/afkKick/src/server.lua diff --git a/modules/ExpGamingPlayer/inventorySearch/control.lua b/old/modules/ExpGamingPlayer/inventorySearch/control.lua similarity index 98% rename from modules/ExpGamingPlayer/inventorySearch/control.lua rename to old/modules/ExpGamingPlayer/inventorySearch/control.lua index 12318f15e3..b2313f1430 100644 --- a/modules/ExpGamingPlayer/inventorySearch/control.lua +++ b/old/modules/ExpGamingPlayer/inventorySearch/control.lua @@ -76,7 +76,7 @@ function ThisModule.search_player(player) end -- Event Handlers Define -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if (game.tick%900) == 0 then local players = game.connected_players if #players == 0 then return end diff --git a/modules/ExpGamingPlayer/inventorySearch/locale/de.cfg b/old/modules/ExpGamingPlayer/inventorySearch/locale/de.cfg similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/locale/de.cfg rename to old/modules/ExpGamingPlayer/inventorySearch/locale/de.cfg diff --git a/modules/ExpGamingPlayer/inventorySearch/locale/en.cfg b/old/modules/ExpGamingPlayer/inventorySearch/locale/en.cfg similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/locale/en.cfg rename to old/modules/ExpGamingPlayer/inventorySearch/locale/en.cfg diff --git a/modules/ExpGamingPlayer/inventorySearch/locale/fr.cfg b/old/modules/ExpGamingPlayer/inventorySearch/locale/fr.cfg similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/locale/fr.cfg rename to old/modules/ExpGamingPlayer/inventorySearch/locale/fr.cfg diff --git a/modules/ExpGamingPlayer/inventorySearch/locale/nl.cfg b/old/modules/ExpGamingPlayer/inventorySearch/locale/nl.cfg similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/locale/nl.cfg rename to old/modules/ExpGamingPlayer/inventorySearch/locale/nl.cfg diff --git a/modules/ExpGamingPlayer/inventorySearch/locale/sv-SE.cfg b/old/modules/ExpGamingPlayer/inventorySearch/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/locale/sv-SE.cfg rename to old/modules/ExpGamingPlayer/inventorySearch/locale/sv-SE.cfg diff --git a/modules/ExpGamingPlayer/inventorySearch/softmod.json b/old/modules/ExpGamingPlayer/inventorySearch/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/inventorySearch/softmod.json rename to old/modules/ExpGamingPlayer/inventorySearch/softmod.json diff --git a/modules/ExpGamingPlayer/playerInfo/control.lua b/old/modules/ExpGamingPlayer/playerInfo/control.lua similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/control.lua rename to old/modules/ExpGamingPlayer/playerInfo/control.lua diff --git a/modules/ExpGamingPlayer/playerInfo/locale/de.cfg b/old/modules/ExpGamingPlayer/playerInfo/locale/de.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/locale/de.cfg rename to old/modules/ExpGamingPlayer/playerInfo/locale/de.cfg diff --git a/modules/ExpGamingPlayer/playerInfo/locale/en.cfg b/old/modules/ExpGamingPlayer/playerInfo/locale/en.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/locale/en.cfg rename to old/modules/ExpGamingPlayer/playerInfo/locale/en.cfg diff --git a/modules/ExpGamingPlayer/playerInfo/locale/fr.cfg b/old/modules/ExpGamingPlayer/playerInfo/locale/fr.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/locale/fr.cfg rename to old/modules/ExpGamingPlayer/playerInfo/locale/fr.cfg diff --git a/modules/ExpGamingPlayer/playerInfo/locale/nl.cfg b/old/modules/ExpGamingPlayer/playerInfo/locale/nl.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/locale/nl.cfg rename to old/modules/ExpGamingPlayer/playerInfo/locale/nl.cfg diff --git a/modules/ExpGamingPlayer/playerInfo/locale/sv-SE.cfg b/old/modules/ExpGamingPlayer/playerInfo/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/locale/sv-SE.cfg rename to old/modules/ExpGamingPlayer/playerInfo/locale/sv-SE.cfg diff --git a/modules/ExpGamingPlayer/playerInfo/softmod.json b/old/modules/ExpGamingPlayer/playerInfo/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/playerInfo/softmod.json rename to old/modules/ExpGamingPlayer/playerInfo/softmod.json diff --git a/modules/ExpGamingPlayer/playerList/control.lua b/old/modules/ExpGamingPlayer/playerList/control.lua similarity index 94% rename from modules/ExpGamingPlayer/playerList/control.lua rename to old/modules/ExpGamingPlayer/playerList/control.lua index 886e3139e5..536519f249 100644 --- a/modules/ExpGamingPlayer/playerList/control.lua +++ b/old/modules/ExpGamingPlayer/playerList/control.lua @@ -37,11 +37,12 @@ local ThisModule = { } -- Global Define -local global = global{ +local global = { update=0, delay=10, interval=54000 } +Global.register(global,function(tbl) global = tbl end) function ThisModule.update(tick) local tick = is_type(tick,'table') and tick.tick or is_type(tick,'number') and tick or game.tick @@ -110,14 +111,14 @@ ThisModule.Gui = Gui.left{ open_on_join=true } -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if event.tick > global.update then ThisModule.Gui() global.update = event.tick + global.interval end end) -script.on_event(defines.events.on_gui_click,function(event) +Event.add(defines.events.on_gui_click,function(event) -- lots of checks for it being valid if event.element and event.element.valid and event.element.parent and event.element.parent.parent and event.element.parent.parent.parent @@ -136,8 +137,8 @@ script.on_event(defines.events.on_gui_click,function(event) if Admin and AdminGui and Admin.allowed(event.player_index) then AdminGui(flow).caption = event.element.name end end) -script.on_event(defines.events.on_player_joined_game,function() ThisModule.update() end) -script.on_event(defines.events.on_player_left_game,function() ThisModule.update() end) +Event.add(defines.events.on_player_joined_game,function() ThisModule.update() end) +Event.add(defines.events.on_player_left_game,function() ThisModule.update() end) ThisModule.force_update = function() return ThisModule.Gui() end -- when called it will queue an update to the player list diff --git a/modules/ExpGamingPlayer/playerList/locale/de.cfg b/old/modules/ExpGamingPlayer/playerList/locale/de.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerList/locale/de.cfg rename to old/modules/ExpGamingPlayer/playerList/locale/de.cfg diff --git a/modules/ExpGamingPlayer/playerList/locale/en.cfg b/old/modules/ExpGamingPlayer/playerList/locale/en.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerList/locale/en.cfg rename to old/modules/ExpGamingPlayer/playerList/locale/en.cfg diff --git a/modules/ExpGamingPlayer/playerList/locale/fr.cfg b/old/modules/ExpGamingPlayer/playerList/locale/fr.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerList/locale/fr.cfg rename to old/modules/ExpGamingPlayer/playerList/locale/fr.cfg diff --git a/modules/ExpGamingPlayer/playerList/locale/nl.cfg b/old/modules/ExpGamingPlayer/playerList/locale/nl.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerList/locale/nl.cfg rename to old/modules/ExpGamingPlayer/playerList/locale/nl.cfg diff --git a/modules/ExpGamingPlayer/playerList/locale/sv-SE.cfg b/old/modules/ExpGamingPlayer/playerList/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingPlayer/playerList/locale/sv-SE.cfg rename to old/modules/ExpGamingPlayer/playerList/locale/sv-SE.cfg diff --git a/modules/ExpGamingPlayer/playerList/softmod.json b/old/modules/ExpGamingPlayer/playerList/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/playerList/softmod.json rename to old/modules/ExpGamingPlayer/playerList/softmod.json diff --git a/modules/ExpGamingPlayer/playerList/src/ranking.lua b/old/modules/ExpGamingPlayer/playerList/src/ranking.lua similarity index 88% rename from modules/ExpGamingPlayer/playerList/src/ranking.lua rename to old/modules/ExpGamingPlayer/playerList/src/ranking.lua index 7ef48a583f..266741b97f 100644 --- a/modules/ExpGamingPlayer/playerList/src/ranking.lua +++ b/old/modules/ExpGamingPlayer/playerList/src/ranking.lua @@ -1,6 +1,6 @@ local Role = require('ExpGamingCore.Role') -script.on_event(defines.events.on_role_change,self.update) +Event.add(defines.events.on_role_change,self.update) return function() local rtn = {} diff --git a/modules/ExpGamingPlayer/polls/control.lua b/old/modules/ExpGamingPlayer/polls/control.lua similarity index 99% rename from modules/ExpGamingPlayer/polls/control.lua rename to old/modules/ExpGamingPlayer/polls/control.lua index 1f18743707..fa9ed01e71 100644 --- a/modules/ExpGamingPlayer/polls/control.lua +++ b/old/modules/ExpGamingPlayer/polls/control.lua @@ -20,10 +20,11 @@ local ThisModule = { } -- Global Define -local global = global{ +local global = { active={}, old={} } +Global.register(global,function(tbl) global = tbl end) -- Function Define local function _poll_data(question,answers) diff --git a/modules/ExpGamingPlayer/polls/locale/de.cfg b/old/modules/ExpGamingPlayer/polls/locale/de.cfg similarity index 100% rename from modules/ExpGamingPlayer/polls/locale/de.cfg rename to old/modules/ExpGamingPlayer/polls/locale/de.cfg diff --git a/modules/ExpGamingPlayer/polls/locale/en.cfg b/old/modules/ExpGamingPlayer/polls/locale/en.cfg similarity index 100% rename from modules/ExpGamingPlayer/polls/locale/en.cfg rename to old/modules/ExpGamingPlayer/polls/locale/en.cfg diff --git a/modules/ExpGamingPlayer/polls/locale/fr.cfg b/old/modules/ExpGamingPlayer/polls/locale/fr.cfg similarity index 100% rename from modules/ExpGamingPlayer/polls/locale/fr.cfg rename to old/modules/ExpGamingPlayer/polls/locale/fr.cfg diff --git a/modules/ExpGamingPlayer/polls/locale/nl.cfg b/old/modules/ExpGamingPlayer/polls/locale/nl.cfg similarity index 100% rename from modules/ExpGamingPlayer/polls/locale/nl.cfg rename to old/modules/ExpGamingPlayer/polls/locale/nl.cfg diff --git a/modules/ExpGamingPlayer/polls/locale/sv-SE.cfg b/old/modules/ExpGamingPlayer/polls/locale/sv-SE.cfg similarity index 100% rename from modules/ExpGamingPlayer/polls/locale/sv-SE.cfg rename to old/modules/ExpGamingPlayer/polls/locale/sv-SE.cfg diff --git a/modules/ExpGamingPlayer/polls/softmod.json b/old/modules/ExpGamingPlayer/polls/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/polls/softmod.json rename to old/modules/ExpGamingPlayer/polls/softmod.json diff --git a/modules/ExpGamingPlayer/softmod.json b/old/modules/ExpGamingPlayer/softmod.json similarity index 100% rename from modules/ExpGamingPlayer/softmod.json rename to old/modules/ExpGamingPlayer/softmod.json diff --git a/modules/FactorioStdLib/Color/control.lua b/old/modules/FactorioStdLib/Color/control.lua similarity index 100% rename from modules/FactorioStdLib/Color/control.lua rename to old/modules/FactorioStdLib/Color/control.lua diff --git a/modules/FactorioStdLib/Color/softmod.json b/old/modules/FactorioStdLib/Color/softmod.json similarity index 100% rename from modules/FactorioStdLib/Color/softmod.json rename to old/modules/FactorioStdLib/Color/softmod.json diff --git a/modules/FactorioStdLib/Game/control.lua b/old/modules/FactorioStdLib/Game/control.lua similarity index 100% rename from modules/FactorioStdLib/Game/control.lua rename to old/modules/FactorioStdLib/Game/control.lua diff --git a/modules/FactorioStdLib/Game/softmod.json b/old/modules/FactorioStdLib/Game/softmod.json similarity index 100% rename from modules/FactorioStdLib/Game/softmod.json rename to old/modules/FactorioStdLib/Game/softmod.json diff --git a/modules/FactorioStdLib/String/control.lua b/old/modules/FactorioStdLib/String/control.lua similarity index 100% rename from modules/FactorioStdLib/String/control.lua rename to old/modules/FactorioStdLib/String/control.lua diff --git a/modules/FactorioStdLib/String/softmod.json b/old/modules/FactorioStdLib/String/softmod.json similarity index 100% rename from modules/FactorioStdLib/String/softmod.json rename to old/modules/FactorioStdLib/String/softmod.json diff --git a/modules/FactorioStdLib/Table/control.lua b/old/modules/FactorioStdLib/Table/control.lua similarity index 100% rename from modules/FactorioStdLib/Table/control.lua rename to old/modules/FactorioStdLib/Table/control.lua diff --git a/modules/FactorioStdLib/Table/softmod.json b/old/modules/FactorioStdLib/Table/softmod.json similarity index 100% rename from modules/FactorioStdLib/Table/softmod.json rename to old/modules/FactorioStdLib/Table/softmod.json diff --git a/modules/FactorioStdLib/softmod.json b/old/modules/FactorioStdLib/softmod.json similarity index 100% rename from modules/FactorioStdLib/softmod.json rename to old/modules/FactorioStdLib/softmod.json diff --git a/modules/GameSettingsGui/control.lua b/old/modules/GameSettingsGui/control.lua similarity index 100% rename from modules/GameSettingsGui/control.lua rename to old/modules/GameSettingsGui/control.lua diff --git a/modules/GameSettingsGui/locale/de.cfg b/old/modules/GameSettingsGui/locale/de.cfg similarity index 100% rename from modules/GameSettingsGui/locale/de.cfg rename to old/modules/GameSettingsGui/locale/de.cfg diff --git a/modules/GameSettingsGui/locale/en.cfg b/old/modules/GameSettingsGui/locale/en.cfg similarity index 100% rename from modules/GameSettingsGui/locale/en.cfg rename to old/modules/GameSettingsGui/locale/en.cfg diff --git a/modules/GameSettingsGui/locale/fr.cfg b/old/modules/GameSettingsGui/locale/fr.cfg similarity index 100% rename from modules/GameSettingsGui/locale/fr.cfg rename to old/modules/GameSettingsGui/locale/fr.cfg diff --git a/modules/GameSettingsGui/locale/nl.cfg b/old/modules/GameSettingsGui/locale/nl.cfg similarity index 100% rename from modules/GameSettingsGui/locale/nl.cfg rename to old/modules/GameSettingsGui/locale/nl.cfg diff --git a/modules/GameSettingsGui/locale/sv-SE.cfg b/old/modules/GameSettingsGui/locale/sv-SE.cfg similarity index 100% rename from modules/GameSettingsGui/locale/sv-SE.cfg rename to old/modules/GameSettingsGui/locale/sv-SE.cfg diff --git a/modules/GameSettingsGui/softmod.json b/old/modules/GameSettingsGui/softmod.json similarity index 100% rename from modules/GameSettingsGui/softmod.json rename to old/modules/GameSettingsGui/softmod.json diff --git a/modules/GuiAnnouncements/control.lua b/old/modules/GuiAnnouncements/control.lua similarity index 100% rename from modules/GuiAnnouncements/control.lua rename to old/modules/GuiAnnouncements/control.lua diff --git a/modules/GuiAnnouncements/locale/de.cfg b/old/modules/GuiAnnouncements/locale/de.cfg similarity index 100% rename from modules/GuiAnnouncements/locale/de.cfg rename to old/modules/GuiAnnouncements/locale/de.cfg diff --git a/modules/GuiAnnouncements/locale/en.cfg b/old/modules/GuiAnnouncements/locale/en.cfg similarity index 100% rename from modules/GuiAnnouncements/locale/en.cfg rename to old/modules/GuiAnnouncements/locale/en.cfg diff --git a/modules/GuiAnnouncements/locale/fr.cfg b/old/modules/GuiAnnouncements/locale/fr.cfg similarity index 100% rename from modules/GuiAnnouncements/locale/fr.cfg rename to old/modules/GuiAnnouncements/locale/fr.cfg diff --git a/modules/GuiAnnouncements/locale/nl.cfg b/old/modules/GuiAnnouncements/locale/nl.cfg similarity index 100% rename from modules/GuiAnnouncements/locale/nl.cfg rename to old/modules/GuiAnnouncements/locale/nl.cfg diff --git a/modules/GuiAnnouncements/locale/sv-SE.cfg b/old/modules/GuiAnnouncements/locale/sv-SE.cfg similarity index 100% rename from modules/GuiAnnouncements/locale/sv-SE.cfg rename to old/modules/GuiAnnouncements/locale/sv-SE.cfg diff --git a/modules/GuiAnnouncements/softmod.json b/old/modules/GuiAnnouncements/softmod.json similarity index 100% rename from modules/GuiAnnouncements/softmod.json rename to old/modules/GuiAnnouncements/softmod.json diff --git a/modules/PlayerAutoColor/control.lua b/old/modules/PlayerAutoColor/control.lua similarity index 91% rename from modules/PlayerAutoColor/control.lua rename to old/modules/PlayerAutoColor/control.lua index b4776c9ecd..3dc7a4942b 100644 --- a/modules/PlayerAutoColor/control.lua +++ b/old/modules/PlayerAutoColor/control.lua @@ -12,7 +12,7 @@ local module_verbose = false local ThisModule = {} -- Global Define -local global = global{ +local global = { BADgamerNL={r=255,g=20,b=147}, arty714={r=150,g=68,b=161}, Cooldude2606={r=57,g=192,b=207}, @@ -26,9 +26,10 @@ local global = global{ cydes={r=82,g=249,b=155}, UUBlueFire={r=0,g=204,b=255} } +Global.register(global,function(tbl) global = tbl end) -- Event Handlers Define -script.on_event(defines.events.on_player_created, function(event) +Event.add(defines.events.on_player_created, function(event) local player = game.players[event.player_index] local colours = table.keys(defines.color) player.color = defines.color.black diff --git a/modules/PlayerAutoColor/softmod.json b/old/modules/PlayerAutoColor/softmod.json similarity index 100% rename from modules/PlayerAutoColor/softmod.json rename to old/modules/PlayerAutoColor/softmod.json diff --git a/modules/SpawnArea/control.lua b/old/modules/SpawnArea/control.lua similarity index 96% rename from modules/SpawnArea/control.lua rename to old/modules/SpawnArea/control.lua index d32258fddb..0e9e1d2c78 100644 --- a/modules/SpawnArea/control.lua +++ b/old/modules/SpawnArea/control.lua @@ -26,12 +26,13 @@ local ThisModule = {} -- Global Define -- location of auto refill turrets -local global = global{ +local global = { {1,-3,-3}, {1,-3,3}, {1,3,-3}, {1,3,3} } +Global.register(global,function(tbl) global = tbl end) -- Function Define function ThisModule.afk_belt(surface,offset) @@ -71,14 +72,14 @@ end -- Event Handlers Define if turret_enabled then - script.on_event(defines.events.on_tick,function(event) + Event.add(defines.events.on_tick,function(event) if event.tick % 3600 then ThisModule.auto_turret() end end) end -script.on_event(defines.events.on_player_created, function(event) +Event.add(defines.events.on_player_created, function(event) if event.player_index == 1 then local player = Game.get_player(event) local surface = player.surface diff --git a/modules/SpawnArea/softmod.json b/old/modules/SpawnArea/softmod.json similarity index 100% rename from modules/SpawnArea/softmod.json rename to old/modules/SpawnArea/softmod.json diff --git a/modules/SpawnArea/src/spawn_entities.lua b/old/modules/SpawnArea/src/spawn_entities.lua similarity index 100% rename from modules/SpawnArea/src/spawn_entities.lua rename to old/modules/SpawnArea/src/spawn_entities.lua diff --git a/modules/SpawnArea/src/spawn_tiles.lua b/old/modules/SpawnArea/src/spawn_tiles.lua similarity index 100% rename from modules/SpawnArea/src/spawn_tiles.lua rename to old/modules/SpawnArea/src/spawn_tiles.lua diff --git a/modules/WarpPoints/control.lua b/old/modules/WarpPoints/control.lua similarity index 97% rename from modules/WarpPoints/control.lua rename to old/modules/WarpPoints/control.lua index 16c150f9ff..19b5a9addc 100644 --- a/modules/WarpPoints/control.lua +++ b/old/modules/WarpPoints/control.lua @@ -22,7 +22,6 @@ local global_offset = {x=0,y=0} local warp_min_distance = 25 -- Module Define -local _global = global local global local module_verbose = false local ThisModule = { @@ -33,10 +32,11 @@ local ThisModule = { } -- Global Define -global = _global{ +global = { warps={}, -- 0,0 is always a warp cooldowns={} } +Global.register(global,function(tbl) global = tbl end) -- Function Define @@ -210,7 +210,7 @@ ThisModule.Gui = Gui.left{ } -- Event Handlers Define -script.on_event(defines.events.on_tick,function(event) +Event.add(defines.events.on_tick,function(event) if not (event.tick % 60 == 0) then return end for index,time in pairs(global.cooldowns) do if time > 0 then @@ -220,7 +220,7 @@ script.on_event(defines.events.on_tick,function(event) end end) -script.on_event(defines.events.on_player_changed_position, function(event) +Event.add(defines.events.on_player_changed_position, function(event) local player = Game.get_player(event) local cooldown = global.cooldowns[player.index] or 0 local tile = player.surface.get_tile(player.position).name @@ -233,7 +233,7 @@ script.on_event(defines.events.on_player_changed_position, function(event) end end) -script.on_event(defines.events.on_player_created, function(event) +Event.add(defines.events.on_player_created, function(event) if event.player_index == 1 then local player = Game.get_player(event) player.force.chart(player.surface, {{player.position.x - 20, player.position.y - 20}, {player.position.x + 20, player.position.y + 20}}) diff --git a/modules/WarpPoints/locale/de.cfg b/old/modules/WarpPoints/locale/de.cfg similarity index 100% rename from modules/WarpPoints/locale/de.cfg rename to old/modules/WarpPoints/locale/de.cfg diff --git a/modules/WarpPoints/locale/en.cfg b/old/modules/WarpPoints/locale/en.cfg similarity index 100% rename from modules/WarpPoints/locale/en.cfg rename to old/modules/WarpPoints/locale/en.cfg diff --git a/modules/WarpPoints/locale/fr.cfg b/old/modules/WarpPoints/locale/fr.cfg similarity index 100% rename from modules/WarpPoints/locale/fr.cfg rename to old/modules/WarpPoints/locale/fr.cfg diff --git a/modules/WarpPoints/locale/nl.cfg b/old/modules/WarpPoints/locale/nl.cfg similarity index 100% rename from modules/WarpPoints/locale/nl.cfg rename to old/modules/WarpPoints/locale/nl.cfg diff --git a/modules/WarpPoints/locale/sv-SE.cfg b/old/modules/WarpPoints/locale/sv-SE.cfg similarity index 100% rename from modules/WarpPoints/locale/sv-SE.cfg rename to old/modules/WarpPoints/locale/sv-SE.cfg diff --git a/modules/WarpPoints/softmod.json b/old/modules/WarpPoints/softmod.json similarity index 100% rename from modules/WarpPoints/softmod.json rename to old/modules/WarpPoints/softmod.json diff --git a/modules/WarpPoints/src/commands.lua b/old/modules/WarpPoints/src/commands.lua similarity index 100% rename from modules/WarpPoints/src/commands.lua rename to old/modules/WarpPoints/src/commands.lua diff --git a/modules/WarpPoints/src/warp_entities.lua b/old/modules/WarpPoints/src/warp_entities.lua similarity index 100% rename from modules/WarpPoints/src/warp_entities.lua rename to old/modules/WarpPoints/src/warp_entities.lua diff --git a/modules/WarpPoints/src/warp_tiles.lua b/old/modules/WarpPoints/src/warp_tiles.lua similarity index 100% rename from modules/WarpPoints/src/warp_tiles.lua rename to old/modules/WarpPoints/src/warp_tiles.lua diff --git a/modules/WornPaths/control.lua b/old/modules/WornPaths/control.lua similarity index 92% rename from modules/WornPaths/control.lua rename to old/modules/WornPaths/control.lua index 1ccf183055..0459de26a5 100644 --- a/modules/WornPaths/control.lua +++ b/old/modules/WornPaths/control.lua @@ -21,7 +21,8 @@ local module_verbose = false local ThisModule = {} -- Global Define -local global = global() +local global = {} +Global.register(global,function(tbl) global = tbl end) -- Function Define local function global_key(surface,pos) @@ -42,7 +43,7 @@ function ThisModule.down_grade(surface,pos) end -- Event Handlers Define -script.on_event({defines.events.on_player_built_tile,defines.events.on_robot_built_tile}, function(event) +Event.add({defines.events.on_player_built_tile,defines.events.on_robot_built_tile}, function(event) local surface = event.surface_index and game.surfaces[event.surface_index] or event.robot and event.robot.surface local old_tiles = event.tiles for _,old_tile in pairs(old_tiles) do @@ -52,7 +53,7 @@ script.on_event({defines.events.on_player_built_tile,defines.events.on_robot_bui end end) -script.on_event(defines.events.on_player_changed_position, function(event) +Event.add(defines.events.on_player_changed_position, function(event) local player = Game.get_player(event) if not player or not player.valid or game.tick < 10 then return end if player.afk_time > 300 then return end @@ -73,7 +74,7 @@ script.on_event(defines.events.on_player_changed_position, function(event) end end) -script.on_event({defines.events.on_built_entity,on_robot_built_entity}, function(event) +Event.add({defines.events.on_built_entity,on_robot_built_entity}, function(event) local entity = event.created_entity local surface = entity.surface if entities[entity.name] then diff --git a/modules/WornPaths/softmod.json b/old/modules/WornPaths/softmod.json similarity index 100% rename from modules/WornPaths/softmod.json rename to old/modules/WornPaths/softmod.json diff --git a/modules/WornPaths/src/entites.lua b/old/modules/WornPaths/src/entites.lua similarity index 100% rename from modules/WornPaths/src/entites.lua rename to old/modules/WornPaths/src/entites.lua diff --git a/modules/WornPaths/src/paths.lua b/old/modules/WornPaths/src/paths.lua similarity index 100% rename from modules/WornPaths/src/paths.lua rename to old/modules/WornPaths/src/paths.lua diff --git a/modules/WornPaths/src/placed.lua b/old/modules/WornPaths/src/placed.lua similarity index 100% rename from modules/WornPaths/src/placed.lua rename to old/modules/WornPaths/src/placed.lua diff --git a/modules/index.lua b/old/modules/index.lua similarity index 100% rename from modules/index.lua rename to old/modules/index.lua diff --git a/modules/softmod.json b/old/modules/softmod.json similarity index 100% rename from modules/softmod.json rename to old/modules/softmod.json diff --git a/resources/color_presets.lua b/resources/color_presets.lua new file mode 100644 index 0000000000..0dd965e439 --- /dev/null +++ b/resources/color_presets.lua @@ -0,0 +1,163 @@ +-- source: https://www.rapidtables.com/web/color/RGB_Color.html +return { + maroon = {r = 128, g = 0, b = 0}, + dark_red = {r = 139, g = 0, b = 0}, + brown = {r = 165, g = 42, b = 42}, + firebrick = {r = 178, g = 34, b = 34}, + crimson = {r = 220, g = 20, b = 60}, + red = {r = 255, g = 0, b = 0}, + tomato = {r = 255, g = 99, b = 71}, + coral = {r = 255, g = 127, b = 80}, + indian_red = {r = 205, g = 92, b = 92}, + light_coral = {r = 240, g = 128, b = 128}, + dark_salmon = {r = 233, g = 150, b = 122}, + salmon = {r = 250, g = 128, b = 114}, + light_salmon = {r = 255, g = 160, b = 122}, + orange_red = {r = 255, g = 69, b = 0}, + dark_orange = {r = 255, g = 140, b = 0}, + orange = {r = 255, g = 165, b = 0}, + gold = {r = 255, g = 215, b = 0}, + dark_golden_rod = {r = 184, g = 134, b = 11}, + golden_rod = {r = 218, g = 165, b = 32}, + pale_golden_rod = {r = 238, g = 232, b = 170}, + dark_khaki = {r = 189, g = 183, b = 107}, + khaki = {r = 240, g = 230, b = 140}, + olive = {r = 128, g = 128, b = 0}, + yellow = {r = 255, g = 255, b = 0}, + yellow_green = {r = 154, g = 205, b = 50}, + dark_olive_green = {r = 85, g = 107, b = 47}, + olive_drab = {r = 107, g = 142, b = 35}, + lawn_green = {r = 124, g = 252, b = 0}, + chart_reuse = {r = 127, g = 255, b = 0}, + green_yellow = {r = 173, g = 255, b = 47}, + dark_green = {r = 0, g = 100, b = 0}, + green = {r = 0, g = 128, b = 0}, + forest_green = {r = 34, g = 139, b = 34}, + lime = {r = 0, g = 255, b = 0}, + lime_green = {r = 50, g = 205, b = 50}, + light_green = {r = 144, g = 238, b = 144}, + pale_green = {r = 152, g = 251, b = 152}, + dark_sea_green = {r = 143, g = 188, b = 143}, + medium_spring_green = {r = 0, g = 250, b = 154}, + spring_green = {r = 0, g = 255, b = 127}, + sea_green = {r = 46, g = 139, b = 87}, + medium_aqua_marine = {r = 102, g = 205, b = 170}, + medium_sea_green = {r = 60, g = 179, b = 113}, + light_sea_green = {r = 32, g = 178, b = 170}, + dark_slate_gray = {r = 47, g = 79, b = 79}, + teal = {r = 0, g = 128, b = 128}, + dark_cyan = {r = 0, g = 139, b = 139}, + aqua = {r = 0, g = 255, b = 255}, + cyan = {r = 0, g = 255, b = 255}, + light_cyan = {r = 224, g = 255, b = 255}, + dark_turquoise = {r = 0, g = 206, b = 209}, + turquoise = {r = 64, g = 224, b = 208}, + medium_turquoise = {r = 72, g = 209, b = 204}, + pale_turquoise = {r = 175, g = 238, b = 238}, + aqua_marine = {r = 127, g = 255, b = 212}, + powder_blue = {r = 176, g = 224, b = 230}, + cadet_blue = {r = 95, g = 158, b = 160}, + steel_blue = {r = 70, g = 130, b = 180}, + corn_flower_blue = {r = 100, g = 149, b = 237}, + deep_sky_blue = {r = 0, g = 191, b = 255}, + dodger_blue = {r = 30, g = 144, b = 255}, + light_blue = {r = 173, g = 216, b = 230}, + sky_blue = {r = 135, g = 206, b = 235}, + light_sky_blue = {r = 135, g = 206, b = 250}, + midnight_blue = {r = 25, g = 25, b = 112}, + navy = {r = 0, g = 0, b = 128}, + dark_blue = {r = 0, g = 0, b = 139}, + medium_blue = {r = 0, g = 0, b = 205}, + blue = {r = 0, g = 0, b = 255}, + royal_blue = {r = 65, g = 105, b = 225}, + blue_violet = {r = 138, g = 43, b = 226}, + indigo = {r = 75, g = 0, b = 130}, + dark_slate_blue = {r = 72, g = 61, b = 139}, + slate_blue = {r = 106, g = 90, b = 205}, + medium_slate_blue = {r = 123, g = 104, b = 238}, + medium_purple = {r = 147, g = 112, b = 219}, + dark_magenta = {r = 139, g = 0, b = 139}, + dark_violet = {r = 148, g = 0, b = 211}, + dark_orchid = {r = 153, g = 50, b = 204}, + medium_orchid = {r = 186, g = 85, b = 211}, + purple = {r = 128, g = 0, b = 128}, + thistle = {r = 216, g = 191, b = 216}, + plum = {r = 221, g = 160, b = 221}, + violet = {r = 238, g = 130, b = 238}, + magenta = {r = 255, g = 0, b = 255}, + fuchsia = {r = 255, g = 0, b = 255}, + orchid = {r = 218, g = 112, b = 214}, + medium_violet_red = {r = 199, g = 21, b = 133}, + pale_violet_red = {r = 219, g = 112, b = 147}, + deep_pink = {r = 255, g = 20, b = 147}, + hot_pink = {r = 255, g = 105, b = 180}, + light_pink = {r = 255, g = 182, b = 193}, + pink = {r = 255, g = 192, b = 203}, + antique_white = {r = 250, g = 235, b = 215}, + beige = {r = 245, g = 245, b = 220}, + bisque = {r = 255, g = 228, b = 196}, + blanched_almond = {r = 255, g = 235, b = 205}, + wheat = {r = 245, g = 222, b = 179}, + corn_silk = {r = 255, g = 248, b = 220}, + lemon_chiffon = {r = 255, g = 250, b = 205}, + light_golden_rod_yellow = {r = 250, g = 250, b = 210}, + light_yellow = {r = 255, g = 255, b = 224}, + saddle_brown = {r = 139, g = 69, b = 19}, + sienna = {r = 160, g = 82, b = 45}, + chocolate = {r = 210, g = 105, b = 30}, + peru = {r = 205, g = 133, b = 63}, + sandy_brown = {r = 244, g = 164, b = 96}, + burly_wood = {r = 222, g = 184, b = 135}, + tan = {r = 210, g = 180, b = 140}, + rosy_brown = {r = 188, g = 143, b = 143}, + moccasin = {r = 255, g = 228, b = 181}, + navajo_white = {r = 255, g = 222, b = 173}, + peach_puff = {r = 255, g = 218, b = 185}, + misty_rose = {r = 255, g = 228, b = 225}, + lavender_blush = {r = 255, g = 240, b = 245}, + linen = {r = 250, g = 240, b = 230}, + old_lace = {r = 253, g = 245, b = 230}, + papaya_whip = {r = 255, g = 239, b = 213}, + sea_shell = {r = 255, g = 245, b = 238}, + mint_cream = {r = 245, g = 255, b = 250}, + slate_gray = {r = 112, g = 128, b = 144}, + light_slate_gray = {r = 119, g = 136, b = 153}, + light_steel_blue = {r = 176, g = 196, b = 222}, + lavender = {r = 230, g = 230, b = 250}, + floral_white = {r = 255, g = 250, b = 240}, + alice_blue = {r = 240, g = 248, b = 255}, + ghost_white = {r = 248, g = 248, b = 255}, + honeydew = {r = 240, g = 255, b = 240}, + ivory = {r = 255, g = 255, b = 240}, + azure = {r = 240, g = 255, b = 255}, + snow = {r = 255, g = 250, b = 250}, + black = {r = 0, g = 0, b = 0}, + silver = {r = 192, g = 192, b = 192}, + dim_grey = {r = 105, g = 105, b = 105}, + dim_gray = {r = 105, g = 105, b = 105}, + grey = {r = 128, g = 128, b = 128}, + gray = {r = 128, g = 128, b = 128}, + dark_grey = {r = 169, g = 169, b = 169}, + dark_gray = {r = 169, g = 169, b = 169}, + light_grey = {r = 211, g = 211, b = 211}, + light_gray = {r = 211, g = 211, b = 211}, + gainsboro = {r = 220, g = 220, b = 220}, + white_smoke = {r = 245, g = 245, b = 245}, + white = {r = 255, g = 255, b = 255}, + jailed = {r = 255, g = 255, b = 255}, + probation = {r = 255, g = 255, b = 255}, + guest = {r = 255, g = 255, b = 255}, + auto_trusted = {r = 192, g = 192, b = 192}, + regular = {r = 0.155, g = 0.540, b = 0.898}, + admin = {r = 0.093, g = 0.768, b = 0.172}, + donator = {r = 172.6, g = 70.2, b = 215.8}, + [-10] = {r = 255, g = 255, b = 255}, -- probation + [0] = {r = 255, g = 255, b = 255}, -- guest + [10] = {r = 192, g = 192, b = 192}, -- auto_trusted + [20] = {r = 0.155, g = 0.540, b = 0.898}, -- regular + [30] = {r = 0.093, g = 0.768, b = 0.172}, -- admin + 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} +} diff --git a/resources/data_stages.lua b/resources/data_stages.lua new file mode 100644 index 0000000000..516fb321de --- /dev/null +++ b/resources/data_stages.lua @@ -0,0 +1,12 @@ +-- Info on the data lifecycle and how we use it: https://github.com/Refactorio/RedMew/wiki/The-data-lifecycle +-- Non-applicable stages are commented out. +_STAGE = { + --settings = 1, + --data = 2, + --migration = 3, + control = 4, + init = 5, + load = 6, + --config_change = 7, + runtime = 8 +} diff --git a/resources/day_night_cycles.lua b/resources/day_night_cycles.lua new file mode 100644 index 0000000000..dd4062bdfa --- /dev/null +++ b/resources/day_night_cycles.lua @@ -0,0 +1,59 @@ +return { + -- ~7 minute cycle, 3m28s of full light, 1m23s light to dark, 42s full dark, 1m23s dark to light + vanilla = { + ticks_per_day = 25000, + dusk = 0.25, + evening = 0.45, + morning = 0.55, + dawn = 0.75 + }, + -- 10 minute cycle, 4m of full light, 4m light to dark, 6s full dark, 2m dark to light + bright = { + ticks_per_day = 36000, + dusk = 0.2, + evening = 0.59, + morning = 0.6, + dawn = 0.8 + }, + -- ~14 minute cycle, 6m56s of full light, 2m46s light to dark, 1m24s full dark, 2m46s dark to light + double_length = { + ticks_per_day = 50000, + dusk = 0.25, + evening = 0.45, + morning = 0.55, + dawn = 0.75 + }, + -- 10 minute cycle, 6s of full light, 2m light to dark, 4m full dark, 4m dark to light + gloomy = { + ticks_per_day = 36000, + dusk = 0, + evening = 0.2, + morning = 0.6, + dawn = 0.99 + }, + -- ~3.5 minute cycle, 1m44s of full light, 42s light to dark, 21s full dark, 42s dark to light + half_length = { + ticks_per_day = 12500, + dusk = 0.25, + evening = 0.45, + morning = 0.55, + dawn = 0.75 + }, + -- 20 minute cycle, 9m of full light, 1m light to dark, 9m full dark, 1m dark to light + long_days_long_nights_fast_transitions = { + ticks_per_day = 72000, + dusk = 0.225, + evening = 0.275, + morning = 0.725, + dawn = 0.775 + }, + -- 6 hour cycle based on Feb 3 London, England for the day/night/twilight times: + -- Day: 2h15m Night: 2h45m Day to night and night to day: 30m each Map starts mid-day + feb3 = { + ticks_per_day = 1296000, + dusk = 4.5 / 24, + evening = 15.5 / 24, + morning = 17.5 / 24, + dawn = 19.5 / 24 + } +} diff --git a/resources/difficulty_settings.lua b/resources/difficulty_settings.lua new file mode 100644 index 0000000000..6a1db0bfd4 --- /dev/null +++ b/resources/difficulty_settings.lua @@ -0,0 +1,72 @@ +-- technology_difficulty has no effect in vanilla +return { + -- the default table is included as a reference but also to give the option of overwriting all user settings + default = { + recipe_difficulty = defines.difficulty_settings.recipe_difficulty.normal, + technology_difficulty = defines.difficulty_settings.technology_difficulty.normal, + technology_price_multiplier = 1 + }, + -- turns on expensive recipes + expensive_recipe = { + recipe_difficulty = defines.difficulty_settings.recipe_difficulty.expensive + }, + -- the following are tech cost reducers + ['tech_x0.25'] = { + technology_price_multiplier = 0.25 + }, + ['tech_x0.5'] = { + technology_price_multiplier = 0.5 + }, + ['tech_x0.75'] = { + technology_price_multiplier = 0.75 + }, + -- the following are all tech cost multipliers + tech_x2 = { + technology_price_multiplier = 2 + }, + tech_x3 = { + technology_price_multiplier = 3 + }, + tech_x4 = { + technology_price_multiplier = 4 + }, + tech_x5 = { + technology_price_multiplier = 5 + }, + tech_x6 = { + technology_price_multiplier = 6 + }, + tech_x8 = { + technology_price_multiplier = 8 + }, + tech_x10 = { + technology_price_multiplier = 10 + }, + tech_x12 = { + technology_price_multiplier = 12 + }, + tech_x14 = { + technology_price_multiplier = 14 + }, + tech_x16 = { + technology_price_multiplier = 16 + }, + tech_x20 = { + technology_price_multiplier = 20 + }, + tech_x50 = { + technology_price_multiplier = 50 + }, + tech_x100 = { + technology_price_multiplier = 100 + }, + tech_x250 = { + technology_price_multiplier = 250 + }, + tech_x500 = { + technology_price_multiplier = 500 + }, + tech_x1000 = { + technology_price_multiplier = 1000 + } +} diff --git a/resources/donator_perks.lua b/resources/donator_perks.lua new file mode 100644 index 0000000000..1e68bc6d2b --- /dev/null +++ b/resources/donator_perks.lua @@ -0,0 +1,4 @@ +return { + rank = 0x1, + train = 0x2 +} diff --git a/resources/fish_messages.lua b/resources/fish_messages.lua new file mode 100644 index 0000000000..7f584da45a --- /dev/null +++ b/resources/fish_messages.lua @@ -0,0 +1,56 @@ +return { + 'Why don’t fish like basketball? Cause they’re afraid of the net', + 'What do you get when you cross a banker with a fish? A Loan shark!', + 'How do you make an Octupus laugh? With ten-tickles', + 'What do you call a fish that needs help with his or her vocals? Autotuna', + 'What is the difference between a piano and a fish? You can tune a piano but you cannot tuna fish.', + 'What did the blind man say when he passed the fish market? Good morning ladies.', + 'Did you hear about the goldfish who went bankrupt? Now he’s a bronze fish.', + 'What happens when you put nutella on salmon? You get salmonella', + 'What do you call a fish with no eyes?…Fsh', + 'What kind of money do fishermen make?…Net profits', + 'What do you get if you cross a salmon, a bird’s leg and a hand?…Birdsthigh fish fingers', + 'Why is a fish easy to weigh?…Because it has its own scales', + 'Why are gold fish orange?…The water makes them rusty', + 'What was the Tsar of Russia’s favorite fish?…Tsardines', + 'Why did the dog jump into the sea?…He wanted to chase the catfish', + 'Which fish dresses the best?…The Swordfish – It always looks sharp', + 'What do you get if you cross an abbot with a trout?…Monkfish', + 'What do you call a big fish who makes you an offer you can’t refuse?…The Codfather', + 'Why is a swordfish’s nose 11 inches long?…If it were 12 inches long it would be a foot', + 'What do you get if you cross a trout with an apartment?…A flat fish', + 'Why are fish no good at tennis?…They don’t like to get too close to the net', + 'How do the fish get to school?…By octobus', + 'What fish make the best sandwich?…A peanut butter and jellyfish', + 'Man: Can I have a fly rod and reel for my son?…Fishing Shop Owner: Sorry sir we don’t do trades', + 'Where do fish keep their money?…In the river bank', + 'Why do fish like arcade games?…Because they are finball wizards', + 'What is a mermaid?…A deep-she fish', + 'What do you get if you cross a whale with rotten fish?…Moby Sick', + 'Why didn’t the lobster share his toys?…He was too shellfish', + 'What do fish use to make telephone calls?…a Shell phone', + 'Why don’t fish make very good tennis balls?…They keep getting caught in the net', + 'Electric eels and electric rays have enough electricity to kill a horse.', + 'Most fish have taste buds all over their body.', + 'Most brands of lipstick contain fish scales.', + 'A fish does not add new scales as it grows, but the scales it has increase in size. In this way, growth rings are formed and the rings reveal the age of a fish.', + 'An inflated porcupine fish can reach a diameter of up to 35 inches. It puffs up by swallowing water and then storing it in its stomach.', + 'Most fish cannot swim backwards. Those that can are mainly members of one of the eel families.', + 'The fastest fish is the sailfish. It can swim as fast as a car travels on the highway.', + 'Some desert pupfish can live in hot springs that reach temperatures greater than 113° F.', + 'Anableps, four-eyed fish, can see above and below water at the same time.', + 'Catfish have over 27,000 taste buds. Humans have around 7,000.', + 'One hagfish can make enough slime in one minute to fill a bucket.', + 'A female sunfish can lay 300 million eggs each year.', + 'Fish feel pain and suffer stress just like mammals and birds.', + 'The Dwarf Seahorse is so slow you can’t see it move', + 'Some fish are as small as a grain of rice', + "There's a species of fish called 'Slippery Dick'", + 'Herrings communicate through farts.', + 'One Puffer Fish contains enough poison to kill 30 medium-biters.', + 'When Anglerfish mate, they melt into each other and share their bodies forever.', + "A koi fish named 'Hanako' lived for 225 years.", + "What did the fish say when he posted bail? I'm off the hook!", + 'There was a sale at the fish market today. I went to see what was the catch.', + 'There are over 25,000 identified species of fish on the earth.' +} diff --git a/resources/hodor_messages.lua b/resources/hodor_messages.lua new file mode 100644 index 0000000000..45d021ffe6 --- /dev/null +++ b/resources/hodor_messages.lua @@ -0,0 +1,12 @@ +-- List of hodor's responses and their weights +return { + {'Hodor.', 16}, + {'Hodor?', 16}, + {'Hodor!', 16}, + {'Hodor! Hodor! Hodor! Hodor!', 4}, + {'Hodor :(', 4}, + {'Hodor :)', 4}, + {'HOOOODOOOR!', 4}, + {'( ͡° ͜ʖ ͡°)', 1}, + {'☉ ‿ ⚆', 1} +} diff --git a/resources/join_messages.lua b/resources/join_messages.lua new file mode 100644 index 0000000000..4caceef3e1 --- /dev/null +++ b/resources/join_messages.lua @@ -0,0 +1,9 @@ +-- List of join messages and their weights. Default is 10. +return { + {'And remember.. Keep Calm And Spaghetti!', 50}, + {'Press F to pay respects to the "Press F to pay respect" message', 3}, + {'Not sure what to do? Ask Newcott.', 1}, + {'Stick and move, stick and move', 10}, + {'Fly like a butterfly, sting like a bee', 10}, + {"These are not the bots you're looking for", 10} +} diff --git a/resources/map_gen_settings.lua b/resources/map_gen_settings.lua new file mode 100644 index 0000000000..400ceefd33 --- /dev/null +++ b/resources/map_gen_settings.lua @@ -0,0 +1,330 @@ +--[[ The easiest way to create a preset to add to this file is to use factorio itself. Create a new world + (vanilla, not scenario) and configure the settings you want. When you launch the game, you can run the following: + /c + local str = serpent.block(game.surfaces.nauvis.map_gen_settings) + game.write_file('map_gen_settings.lua', str) + + This will output a file with a table that you can add to this resources file or into your specific map. + In either case, make sure to set seed to nil unless you want your map to be *exactly* the same each time. + The expectation is that all changes that deviate from default generation are noted. + Water size and frequency is not denoted as such. Instead water size = water and water frequency = terrain_segmentation +]] +return { + -- the default table is included as a reference but also to give the option of overwriting all user settings + default = { + autoplace_controls = { + coal = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + ['copper-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + ['crude-oil'] = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + desert = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + dirt = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + ['enemy-base'] = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + grass = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + ['iron-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + sand = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + stone = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + trees = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + }, + ['uranium-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'normal' + } + }, + cliff_settings = { + cliff_elevation_0 = 10, + cliff_elevation_interval = 10, + name = 'cliff' + }, + height = 2000000, + peaceful_mode = false, + starting_area = 'normal', + terrain_segmentation = 'normal', + water = 'normal', + width = 2000000 + }, + -- no enemies + enemy_none = { + autoplace_controls = { + ['enemy-base'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + } + }, + -- high frequency and big size enemies + enemy_high = { + autoplace_controls = { + ['enemy-base'] = { + frequency = 'high', + richness = 'normal', + size = 'high' + } + } + }, + -- very high frequency and very big size enemies + enemy_very_high = { + autoplace_controls = { + ['enemy-base'] = { + frequency = 'very-high', + richness = 'normal', + size = 'very-high' + } + } + }, + -- no ores + ore_none = { + autoplace_controls = { + coal = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['copper-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['iron-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + stone = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['uranium-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + } + }, + -- no oil + oil_none = { + autoplace_controls = { + ['crude-oil'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + } + }, + -- no ores, no oil + ore_oil_none = { + autoplace_controls = { + coal = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['copper-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['crude-oil'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['iron-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + stone = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + ['uranium-ore'] = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + } + }, + -- no water + water_none = { + terrain_segmentation = 'very-low', + water = 'none' + }, + -- very low water + water_very_low = { + terrain_segmentation = 'very-low', + water = 'very-low' + }, + -- no cliffs + cliff_none = { + cliff_settings = { + cliff_elevation_0 = 1024, + cliff_elevation_interval = 10, + name = 'cliff' + } + }, + -- normal cliffs + cliff_normal = { + name = 'cliff', + cliff_elevation_0 = 10, + cliff_elevation_interval = 10 + }, + -- cliffs to very high frequency, very big size + cliff_very_high = { + cliff_settings = { + cliff_elevation_0 = 2.5000572204589844, + cliff_elevation_interval = 2.5000572204589844, + name = 'cliff' + } + }, + -- cliffs to very high frequency, very big size + tree_none = { + autoplace_controls = { + trees = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + } + }, + -- cliffs to very high frequency, very big size + tree_very_high = { + autoplace_controls = { + trees = { + frequency = 'very-high', + richness = 'very-high', + size = 'very-high' + } + } + }, + -- starting area to very low + starting_area_very_low = { + starting_area = 'very-low' + }, + -- peaceful mode on + peaceful_mode_on = { + peaceful_mode = true + }, + -- random seed, in case you need/want the seed to be unique from nauvis + unique_seed = { + seed = nil + }, + -- grass only + grass_only = { + autoplace_controls = { + grass = {frequency = 'normal', size = 'normal', richness = 'normal'}, + desert = {frequency = 'normal', size = 'none', richness = 'normal'}, + dirt = {frequency = 'normal', size = 'none', richness = 'normal'}, + sand = {frequency = 'normal', size = 'none', richness = 'normal'} + } + }, + -- desert only + desert_only = { + autoplace_controls = { + grass = {frequency = 'normal', size = 'none', richness = 'normal'}, + desert = {frequency = 'normal', size = 'normal', richness = 'normal'}, + dirt = {frequency = 'normal', size = 'none', richness = 'normal'}, + sand = {frequency = 'normal', size = 'none', richness = 'normal'} + } + }, + -- dirt only + dirt_only = { + autoplace_controls = { + grass = {frequency = 'normal', size = 'none', richness = 'normal'}, + desert = {frequency = 'normal', size = 'none', richness = 'normal'}, + dirt = {frequency = 'normal', size = 'normal', richness = 'normal'}, + sand = {frequency = 'normal', size = 'none', richness = 'normal'} + } + }, + -- sand only + sand_only = { + autoplace_controls = { + grass = {frequency = 'normal', size = 'none', richness = 'normal'}, + desert = {frequency = 'normal', size = 'none', richness = 'normal'}, + dirt = {frequency = 'normal', size = 'none', richness = 'normal'}, + sand = {frequency = 'normal', size = 'normal', richness = 'normal'} + } + }, + -- will generate a world with only water (useful for maps that want full terrain control and no entities on the surface) + waterworld = { + autoplace_controls = { + desert = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + dirt = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + grass = { + frequency = 'normal', + richness = 'normal', + size = 'none' + }, + sand = { + frequency = 'normal', + richness = 'normal', + size = 'none' + } + }, + starting_points = { + { + x = 0, + y = 0 + } + } + }, + -- creates a 1x1 world border, this will prevent chunks from being generated + void = { + height = 1, + width = 1 + } +} diff --git a/resources/map_settings.lua b/resources/map_settings.lua new file mode 100644 index 0000000000..c18de210aa --- /dev/null +++ b/resources/map_settings.lua @@ -0,0 +1,186 @@ +return { + -- the default table is included as a reference but also to give the option of overwriting all user settings + default = { + pollution = { + enabled = true, + diffusion_ratio = 0.02, + min_to_diffuse = 15, + ageing = 1, + expected_max_per_chunk = 7000, + min_to_show_per_chunk = 700, + min_pollution_to_damage_trees = 3500, + pollution_with_max_forest_damage = 10000, + pollution_per_tree_damage = 2000, + pollution_restored_per_tree_damage = 500, + max_pollution_to_restore_trees = 1000 + }, + enemy_evolution = { + enabled = true, + time_factor = 0.000004, + destroy_factor = 0.002, + pollution_factor = 0.000015 + }, + enemy_expansion = { + enabled = true, + max_expansion_distance = 7, + friendly_base_influence_radius = 2, + enemy_building_influence_radius = 2, + building_coefficient = 0.1, + other_base_coefficient = 2.0, + neighbouring_chunk_coefficient = 0.5, + neighbouring_base_chunk_coefficient = 0.4, + max_colliding_tiles_coefficient = 0.9, + settler_group_min_size = 5, + settler_group_max_size = 20, + min_expansion_cooldown = 4 * 3600, + max_expansion_cooldown = 60 * 3600 + }, + unit_group = { + min_group_gathering_time = 3600, + max_group_gathering_time = 10 * 3600, + max_wait_time_for_late_members = 2 * 3600, + max_group_radius = 30.0, + min_group_radius = 5.0, + max_member_speedup_when_behind = 1.4, + max_member_slowdown_when_ahead = 0.6, + max_group_slowdown_factor = 0.3, + max_group_member_fallback_factor = 3, + member_disown_distance = 10, + tick_tolerance_when_member_arrives = 60, + max_gathering_unit_groups = 30, + max_unit_group_size = 200 + }, + steering = { + default = { + radius = 1.2, + separation_force = 0.005, + separation_factor = 1.2, + force_unit_fuzzy_goto_behavior = false + }, + moving = { + radius = 3, + separation_force = 0.01, + separation_factor = 3, + force_unit_fuzzy_goto_behavior = false + } + }, + path_finder = { + fwd2bwd_ratio = 5, + goal_pressure_ratio = 2, + max_steps_worked_per_tick = 100, + use_path_cache = true, + short_cache_size = 5, + long_cache_size = 25, + short_cache_min_cacheable_distance = 10, + short_cache_min_algo_steps_to_cache = 50, + long_cache_min_cacheable_distance = 30, + cache_max_connect_to_cache_steps_multiplier = 100, + cache_accept_path_start_distance_ratio = 0.2, + cache_accept_path_end_distance_ratio = 0.15, + negative_cache_accept_path_start_distance_ratio = 0.3, + negative_cache_accept_path_end_distance_ratio = 0.3, + cache_path_start_distance_rating_multiplier = 10, + cache_path_end_distance_rating_multiplier = 20, + stale_enemy_with_same_destination_collision_penalty = 30, + ignore_moving_enemy_collision_distance = 5, + enemy_with_different_destination_collision_penalty = 30, + general_entity_collision_penalty = 10, + general_entity_subsequent_collision_penalty = 3, + max_clients_to_accept_any_new_request = 10, + max_clients_to_accept_short_new_request = 100, + direct_distance_to_consider_short_request = 100, + short_request_max_steps = 1000, + short_request_ratio = 0.5, + min_steps_to_check_path_find_termination = 2000, + start_to_goal_cost_multiplier_to_terminate_path_find = 500.0 + }, + max_failed_behavior_count = 3 + }, + -- no pollution + pollution_off = { + pollution = { + enabled = false + } + }, + -- decreases the spread of pollution and increases the absorption per chunk of land + pollution_decreased_per_chunk = { + pollution = { + diffusion_ratio = 0.01, + min_to_diffuse = 30, + ageing = 2 + } + }, + -- tough to spread pollution, pollution rapidly decayse: for venus + pollution_hard_to_spread = { + enabled = true, + diffusion_ratio = 0.01, + min_to_diffuse = 200, + ageing = 5 + }, + -- increases the ability of trees to suck up pollution + pollution_decreased_per_tree = { + pollution = { + pollution_with_max_forest_damage = 20000, + pollution_per_tree_damage = 4000, + max_pollution_to_restore_trees = 2000 + } + }, + -- no enemy evolution + enemy_evolution_off = { + enemy_evolution = { + enabled = false + } + }, + -- evolution from all factors x2 + enemy_evolution_x2 = { + enemy_evolution = { + enabled = true, + time_factor = 0.000008, + destroy_factor = 0.004, + pollution_factor = 0.000030 + } + }, + -- 3x cost for pollution, all else 1x + enemy_evolution_punishes_pollution = { + enemy_evolution = { + enabled = true, + time_factor = 0.000004, + destroy_factor = 0.002, + pollution_factor = 0.000045 + } + }, + -- 3x cost for destroying spawners, all else 1x + enemy_evolution_punishes_destruction = { + enemy_evolution = { + enabled = true, + time_factor = 0.000004, + destroy_factor = 0.006, + pollution_factor = 0.000015 + } + }, + -- no enemy expansion + enemy_expansion_off = { + enemy_expansion = { + enabled = false + } + }, + -- should increase the fequency with which enemies expand + enemy_expansion_frequency_x4 = { + enemy_expansion = { + enabled = true, + min_expansion_cooldown = 1 * 3600, + max_expansion_cooldown = 15 * 3600 + } + }, + -- biters will expand to more chunks and will be more densely packed + enemy_expansion_aggressive = { + enemy_expansion = { + enabled = true, + max_expansion_distance = 21, + friendly_base_influence_radius = 1, + enemy_building_influence_radius = 1, + settler_group_min_size = 1, + settler_group_max_size = 10 + } + } +} diff --git a/resources/market_items.lua b/resources/market_items.lua new file mode 100644 index 0000000000..e63da3b4cb --- /dev/null +++ b/resources/market_items.lua @@ -0,0 +1,81 @@ +return { + { + name = 'temporary-running-speed-bonus', + name_label = 'Temporary running speed bonus', + type = 'temporary-buff', + description = 'Increases running speed by one level for a short period', + sprite = 'technology/exoskeleton-equipment', + stack_limit = 1, + price = 10, + }, + { + name = 'temporary-mining-speed-bonus', + name_label = 'Temporary mining speed bonus', + type = 'temporary-buff', + description = 'Increases manual mining speed by one level for a short period', + sprite = 'technology/mining-productivity-1', + stack_limit = 1, + price = 10, + }, + {price = 2, name = 'raw-fish'}, + {price = 0.95, name = 'rail'}, + {price = 2, name = 'rail-signal'}, + {price = 2, name = 'rail-chain-signal'}, + {price = 15, name = 'train-stop'}, + {price = 75, name = 'locomotive'}, + {price = 30, name = 'cargo-wagon'}, + {price = 0.95, name = 'red-wire'}, + {price = 0.95, name = 'green-wire'}, + {price = 3, name = 'decider-combinator'}, + {price = 3, name = 'arithmetic-combinator'}, + {price = 3, name = 'constant-combinator'}, + {price = 7, name = 'programmable-speaker'}, + {price = 15, name = 'steel-axe'}, + {price = 15, name = 'submachine-gun'}, + {price = 15, name = 'shotgun'}, + {price = 250, name = 'combat-shotgun'}, + {price = 25, name = 'railgun'}, + {price = 250, name = 'flamethrower'}, + {price = 175, name = 'rocket-launcher'}, + {price = 250, name = 'tank-cannon'}, + {price = 750, name = 'tank-machine-gun'}, + {price = 75, name = 'tank-flamethrower'}, + {price = 2500, name = 'artillery-wagon-cannon'}, + {price = 1, name = 'firearm-magazine'}, + {price = 5, name = 'piercing-rounds-magazine'}, + {price = 20, name = 'uranium-rounds-magazine'}, + {price = 2, name = 'shotgun-shell'}, + {price = 10, name = 'piercing-shotgun-shell'}, + {price = 5, name = 'railgun-dart'}, + {price = 25, name = 'flamethrower-ammo'}, + {price = 15, name = 'rocket'}, + {price = 25, name = 'explosive-rocket'}, + {price = 2500, name = 'atomic-bomb'}, + {price = 20, name = 'cannon-shell'}, + {price = 30, name = 'explosive-cannon-shell'}, + {price = 75, name = 'explosive-uranium-cannon-shell'}, + {price = 100, name = 'artillery-shell'}, + {price = 3, name = 'land-mine'}, + {price = 5, name = 'grenade'}, + {price = 35, name = 'cluster-grenade'}, + {price = 5, name = 'defender-capsule'}, + {price = 75, name = 'destroyer-capsule'}, + {price = 35, name = 'poison-capsule'}, + {price = 35, name = 'slowdown-capsule'}, + {price = 50, name = 'artillery-targeting-remote'}, + {price = 1000, name = 'artillery-turret'}, + {price = 350, name = 'modular-armor'}, + {price = 875, name = 'power-armor'}, + {price = 40, name = 'solar-panel-equipment'}, + {price = 875, name = 'fusion-reactor-equipment'}, + {price = 100, name = 'battery-equipment'}, + {price = 625, name = 'battery-mk2-equipment'}, + {price = 250, name = 'belt-immunity-equipment'}, + {price = 100, name = 'night-vision-equipment'}, + {price = 150, name = 'exoskeleton-equipment'}, + {price = 250, name = 'personal-roboport-equipment'}, + {price = 25, name = 'construction-robot'}, + {price = 350, name = 'energy-shield-equipment'}, + {price = 750, name = 'personal-laser-defense-equipment'}, + {price = 1, name = 'refined-hazard-concrete'}, +} diff --git a/resources/naming_words.lua b/resources/naming_words.lua new file mode 100644 index 0000000000..e36c45d648 --- /dev/null +++ b/resources/naming_words.lua @@ -0,0 +1,253 @@ +-- Currently geared towards the winter holidays but we can always revise if needed. +-- (Ex. a table of standard/common words and tables for season-specific words, then combined for specific purposes/use-cases) + +local Module = {} + +Module.adverbs = { + 'Abnormally', + 'Accidentally', + 'Adventurously', + 'Anxiously', + 'Arrogantly', + 'Awkwardly', + 'Bashfully', + 'Beautifully', + 'Blindly', + 'Blissfully', + 'Boastfully', + 'Boldly', + 'Bravely', + 'Calmly', + 'Carefully', + 'Carelessly', + 'Cautiously', + 'Certainly', + 'Cheerfully', + 'Clearly', + 'Closely', + 'Continually', + 'Courageously', + 'Cruelly', + 'Curiously', + 'Dearly', + 'Deeply', + 'Defiantly', + 'Deliberately', + 'Delightfully', + 'Dimly', + 'Doubtfully', + 'Dreamily', + 'Easily', + 'Elegantly', + 'Energetically', + 'Enormously', + 'Enthusiastically', + 'Especially', + 'Eventually', + 'Excitedly', + 'Extremely', + 'Fairly', + 'Faithfully', + 'Famously', + 'Fatally', + 'Ferociously', + 'Fervently', + 'Fiercely', + 'Fondly', + 'Foolishly', + 'Frantically', + 'Frightfully', + 'Furiously', + 'Generally', + 'Generously', + 'Gently', + 'Gladly', + 'Gleefully', + 'Gracefully', + 'Greatly', + 'Happily', + 'Heavily', + 'Helpfully', + 'Helplessly', + 'Honestly', + 'Hopelessly', + 'Hungrily', + 'Innocently', + 'Inquisitively', + 'Intensely', + 'Interestingly', + 'Irritably', + 'Jovially', + 'Joyfully', + 'Kindheartedly', + 'Kindly', + 'Knowingly', + 'Lazily', + 'Lively', + 'Longingly', + 'Loosely', + 'Loudly', + 'Lovingly', + 'Loyally', + 'Madly', + 'Majestically', + 'Merrily', + 'Miserably', + 'Mockingly', + 'Mostly', + 'Mysteriously', + 'Naturally', + 'Nearly', + 'Nicely', + 'Noisily', + 'Obnoxiously', + 'Offensively', + 'Optimistically', + 'Painfully', + 'Patiently', + 'Perfectly', + 'Playfully', + 'Politely', + 'Positively', + 'Powerfully', + 'Questionably', + 'Quickly', + 'Quietly', + 'Randomly', + 'Rapidly', + 'Readily', + 'Reluctantly', + 'Righteously', + 'Safely', + 'Seemingly', + 'Selfishly', + 'Silently', + 'Sleepily', + 'Stealthily', + 'Successfully', + 'Suddenly', + 'Surprisingly', + 'Suspiciously', + 'Sweetly', + 'Tenderly', + 'Thankfully', + 'Unbearably', + 'Unexpectedly', + 'Unfortunately', + 'Unimpressively', + 'Unnecessarily', + 'Urgently', + 'Uselessly', + 'Vaguely', + 'Warmly', + 'Wildly', + 'Wisely', + 'Wrongly', + 'Youthfully', +} + +Module.adjectives = { + 'Amazing', + 'Attractive', + 'Awesome', + 'Beautiful', + 'Big', + 'Blissful', + 'Brave', + 'Breathtaking', + 'Careful', + 'Caroling', + 'Chubby', + 'Clever', + 'Clumsy', + 'Dazzling', + 'Delightful', + 'Eager', + 'Excitable', + 'Fabulous', + 'Faithful', + 'Fancy', + 'Fantastic', + 'Fantastical', + 'Fierce', + 'Gentle', + 'Glamorous', + 'Gorgeous', + 'Great', + 'Grumpy', + 'Happy', + 'Helpful', + 'Interesting', + 'Jolly', + 'Kind', + 'Lazy', + 'Magical', + 'Magnificent', + 'Merry', + 'Muscular', + 'Mystical', + 'Naughty', + 'Nice', + 'Obedient', + 'Peaceful', + 'Plump', + 'Polite', + 'Quaint', + 'Remarkable', + 'Roasting', + 'Scary', + 'Silly', + 'Small', + 'Tender', + 'Thoughtful', + 'White', + 'Witty', + 'Wonderful', +} + +Module.nouns = { + 'Advent', + 'Angel', + 'Bear', + 'Bell', + 'Candy_Cane', + 'Caroler', + 'Chestnut', + 'Christmas_Stocking', + 'Decoration', + 'Elf', + 'Feast', + 'Fruit_Cake', + 'Garland', + 'Gift', + 'Grinch', + 'Ham', + 'Helper', + 'Holiday_Dinner', + 'Holiday_Sweater', + 'Holly', + 'Ice_Skate', + 'Ivy', + 'Menora', + 'Miracle', + 'Mistletoe', + 'Ornament', + 'Package', + 'Party', + 'Present', + 'Reindeer', + 'Ribbon', + 'Scarf', + 'Scrooge', + 'Sleigh', + 'Snowball', + 'Snowflake', + 'Snowman', + 'Sugarplum', + 'Toy', + 'Tree', + 'Turkey', + 'Wreath', +} + +return Module diff --git a/resources/naughty_words.lua b/resources/naughty_words.lua new file mode 100644 index 0000000000..b5890bd3a6 --- /dev/null +++ b/resources/naughty_words.lua @@ -0,0 +1,41 @@ +return { + ['ass'] = true, + ['bugger'] = true, + ['butt'] = true, + ['bum'] = true, + ['bummer'] = true, + ['christ'] = true, + ['crikey'] = true, + ['darn'] = true, + ['dam'] = true, + ['damn'] = true, + ['dang'] = true, + ['dagnabit'] = true, + ['dagnabbit'] = true, + ['drat'] = true, + ['fart'] = true, + ['feck'] = true, + ['frack'] = true, + ['freaking'] = true, + ['frick'] = true, + ['gay'] = true, + ['gee'] = true, + ['geez'] = true, + ['git'] = true, + ['god'] = true, + ['golly'] = true, + ['gosh'] = true, + ['heavens'] = true, + ['heck'] = true, + ['hell'] = true, + ['holy'] = true, + ['jerk'] = true, + ['jesus'] = true, + ['petes'] = true, + ["pete's"] = true, + ['poo'] = true, + ['satan'] = true, + ['willy'] = true, + ['wee'] = true, + ['yikes'] = true +} diff --git a/resources/player_colors.lua b/resources/player_colors.lua new file mode 100644 index 0000000000..9b56f480c3 --- /dev/null +++ b/resources/player_colors.lua @@ -0,0 +1,50 @@ +return { + ['grilledham'] = { + color = {r = 0.9290000202716064, g = 0.3860000739097595, b = 0.51399999856948853, a = 0.5}, + chat_color = {r = 1, g = 0.51999998092651367, b = 0.63300001621246338, a = 0.5} + }, + ['plague006'] = { + color = {r = 64, g = 224, b = 208, a = 0.5}, + chat_color = {r = 175, g = 238, b = 238, a = 0.5} + }, + ['Linaori'] = { + color = {r = 255, g = 255, b = 0, a = 0.5}, + chat_color = {r = 255, g = 255, b = 0, a = 0.5} + }, + ['Jayefuu'] = { + color = {r = 0.559, g = 0.761, b = 0.157, a = 0.5}, + chat_color = {r = 0.708, g = 0.996, b = 0.134, a = 0.5} + }, + ['robertkruijt'] = { + color = {r = 0.275, g = 0.755, b = 0.712, a = 0.5}, + chat_color = {r = 0.335, g = 0.918, b = 0.866, a = 0.5} + }, + ['der-dave.com'] = { + color = {r = 255, g = 162, b = 0, a = 0.5}, + chat_color = {r = 255, g = 162, b = 0, a = 0.5} + }, + ['chromaddict'] = { + color = {r = 0, g = 1, b = 1, a = 0.5}, + chat_color = {r = 0, g = 1, b = 1, a = 0.5} + }, + ['shoghicp'] = { + color = {a = 0, b = 0.50980395078659058, g = 0, r = 0.29411765933036804}, + chat_color = {a = 0, b = 0.50980395078659058, g = 0, r = 0.29411765933036804} + }, + ['aldldl'] = { + color = {r = 0, g = 0, b = 0, a = 0.5}, + chat_color = {r = 0, g = 127, b = 0, a = 0.5} + }, + ['Raiguard'] = { + color = {a = 1, b = 0.50980395078659058, g = 0.54901963472366333, r = 0.13725490868091583}, + chat_color = {a = 1, b = 0.75490200519561768, g = 0.77450978755950928, r = 0.56862747669219971} + }, + ['ferefang'] = { + color = {a = 1, b = 0, g = 0.024000000208616, r = 0.81499999761581}, + chat_color = {a = 1, b = 0.1410000026226, g = 016599999368191, r = 1} + }, + ['Gerkis'] = { + color = {a = 0.5, b = 0.15700000524520874, g = 0.76099997758865356, r = 0.55900001525878906}, + chat_color = {a = 0.5, b = 0.13400000333786011, g = 0.99599999189376831, r = 0.70800000429153442} + }, +} diff --git a/resources/player_sprites.lua b/resources/player_sprites.lua new file mode 100644 index 0000000000..4977d9fbfe --- /dev/null +++ b/resources/player_sprites.lua @@ -0,0 +1,54 @@ +return { + 'item/iron-axe', + 'item/burner-mining-drill', + 'item/burner-inserter', + 'item/stone-furnace', + 'item/light-armor', + 'item/steam-engine', + 'item/inserter', + 'item/transport-belt', + 'item/underground-belt', + 'item/splitter', + 'item/assembling-machine-1', + 'item/long-handed-inserter', + 'item/electronic-circuit', + 'item/electric-mining-drill', + 'item/heavy-armor', + 'item/steel-furnace', + 'item/steel-axe', + 'item/gun-turret', + 'item/fast-transport-belt', + 'item/fast-underground-belt', + 'item/fast-splitter', + 'item/assembling-machine-2', + 'item/fast-inserter', + 'item/radar', + 'item/filter-inserter', + 'item/defender-capsule', + 'item/pumpjack', + 'item/chemical-plant', + 'item/solar-panel', + 'item/advanced-circuit', + 'item/modular-armor', + 'item/accumulator', + 'item/construction-robot', + 'item/distractor-capsule', + 'item/stack-inserter', + 'item/electric-furnace', + 'item/express-transport-belt', + 'item/express-underground-belt', + 'item/express-splitter', + 'item/assembling-machine-3', + 'item/processing-unit', + 'item/power-armor', + 'item/logistic-robot', + 'item/laser-turret', + 'item/stack-filter-inserter', + 'item/destroyer-capsule', + 'item/power-armor-mk2', + 'item/flamethrower-turret', + 'item/beacon', + 'item/steam-turbine', + 'item/centrifuge', + 'item/nuclear-reactor' +} diff --git a/resources/poke_messages.lua b/resources/poke_messages.lua new file mode 100644 index 0000000000..4b7b835c2f --- /dev/null +++ b/resources/poke_messages.lua @@ -0,0 +1,402 @@ +return { + "a stick", + "a leaf", + "a moldy carrot", + "a crispy slice of bacon", + "a french fry", + "a realistic toygun", + "a broomstick", + "a thirteen inch iron stick", + "a mechanical keyboard", + "a fly fishing cane", + "a selfie stick", + "an oversized fidget spinner", + "a thumb extender", + "a dirty straw", + "a green bean", + "a banana", + "an umbrella", + "grandpa's walking stick", + "live firework", + "a toilet brush", + "a fake hand", + "an undercooked hotdog", + "a slice of yesterday's microwaved pizza", + "bubblegum", + "a biter leg", + "grandma's toothbrush", + "charred octopus", + "a dollhouse bathtub", + "a length of copper wire", + "a decommissioned nuke", + "a smelly trout", + "an unopened can of deodorant", + "a stone brick", + "a half full barrel of lube", + "a half empty barrel of lube", + "an unexploded cannon shell", + "a blasting programmable speaker", + "a not so straight rail", + "a mismatched pipe to ground", + "a surplus box of landmines", + "decommissioned yellow rounds", + "an oily pumpjack shaft", + "a melted plastic bar in the shape of the virgin mary", + "a bottle of watermelon vitamin water", + "a slice of watermelon", + "a stegosaurus tibia", + "a basking musician's clarinet", + "a twig", + "an undisclosed pokey item", + "a childhood trophy everyone else got", + "a dead starfish", + "a titanium toothpick", + "a nail file", + "a stamp collection", + "a bucket of lego", + "a rolled up carpet", + "a rolled up WELCOME doormat", + "Bobby's favorite bone", + "an empty bottle of cheap vodka", + "a tattooing needle", + "a peeled cucumber", + "a stack of cotton candy", + "a signed baseball bat", + "that 5 dollar bill grandma sent for christmas", + "a stack of overdue phone bills", + "the 'relax' section of the white pages", + "a bag of gym clothes which never made it to the washing machine", + "a handful of peanut butter", + "a pheasant's feather", + "a rusty pickaxe", + "a diamond sword", + "the bill of rights of a banana republic", + "one of those giant airport Toblerone's", + "a long handed inserter", + "a wiimote", + "an easter chocolate rabbit", + "a ball of yarn the cat threw up", + "a slightly expired but perfectly edible cheese sandwich", + "conclusive proof of lizard people existence", + "a pen drive full of high res wallpapers", + "a pet hamster", + "an oversized goldfish", + "a one foot extension cord", + "a CD from Walmart's 1 dollar bucket", + "a magic wand", + "a list of disappointed people who believed in you", + "murder exhibit no. 3", + "a paperback copy of 'Great Expectations'", + "a baby biter", + "a little biter fang", + "the latest diet fad", + "a belt that no longer fits you", + "an abandoned pet rock", + "a lava lamp", + "some spirit herbs", + "a box of fish sticks found at the back of the freezer", + "a bowl of tofu rice", + "a bowl of ramen noodles", + "a live lobster!", + "a miniature golf cart", + "dunce cap", + "a fully furnished x-mas tree", + "an orphaned power pole", + "an horphaned power pole", + "an box of overpriced girl scout cookies", + "the cheapest item from the yard sale", + "a Sharpie", + "a glowstick", + "a thick unibrow hair", + "a very detailed map of Kazakhstan", + "the official Factorio installation DVD", + "a Liberal Arts degree", + "a pitcher of Kool-Aid", + "a 1/4 pound vegan burrito", + "a bottle of expensive wine", + "a hamster sized gravestone", + "a counterfeit Cuban cigar", + "an old Nokia phone", + "a huge inferiority complex", + "a dead real state agent", + "a deck of tarot cards", + "unreleased Wikileaks documents", + "a mean-looking garden dwarf", + "the actual mythological OBESE cat", + "a telescope used to spy on the MILF next door", + "a fancy candelabra", + "the comic version of the Kama Sutra", + "an inflatable 'Netflix & chill' doll", + "whatever it is redlabel gets high on", + "Obama's birth certificate", + "a deck of Cards Against Humanity", + "a copy of META MEME HUMOR for Dummies", + "an abandoned not-so-young-anymore puppy", + "one of those useless items advertised on TV", + "a genetic blueprint of a Japanese teen idol", + "yesterday’s jam", + "non-stick honey", + "gluten-free gluten", + "a canister of organic petrol", + "the world's tallest midget", + "an inflammable fire extinguisher", + "a chocolate teapot", + "a dvd rewinder", + "an inflatable dart board", + "a copy of ‘How to read for dummies’", + "an English to Spanish dictionary written entirely in Chinese", + "a camouflage high vis jacket", + "soap that has been dropped in the communal showers", + "a portal to the other side", + "", + "a limited offer, one time only poke", + "the poke-o-matic 4000", + "their finger where the sun doesn’t shine", + "a flogged dead horse", + "a chicken that came before the egg", + "a calculator that can divide by zero", + "a dial up internet connection", + "some stuff they found on the underside of the map", + "a proof that the world is flat", + "a radioactive cockroach", + "the second season of Firefly", + "a non-random random number generator", + "last weeks crash report", + "a pair of two left shoes", + "the meaning of life", + "a map of the London underground", + "an oversized foam hand", + "weight loss pills", + "a deconstruction planner that new players can use", + "a fish that is the same size as a grain of rice", + "a videotape of what they did last Summer", + "a love note from the cute girl sitting behind them", + "a cup of dihydrogen monoxide", + "an external combustion engine", + "a profound sense of optimism", + "a yoghurt past its use by date", + "steel beams that can’t be melted with jet fuel", + "a picture of who really shot JFK", + "footage of the faked Apollo landing", + "some of their holiday photos", + "the password for the server mainframe", + "ʇxǝʇ uʍop ǝpısdn ǝɯos", + "their lost jumper", + "a melted ice cube", + "a box where they keep all their secrets", + "a piece of paper that says ‘You are reading this’", + "a book with the answer to every lateral thinking puzzle that hasn’t been made yet", + "a list of cheat codes for Factorio", + "a lemon that looks and taste like a lime", + "a bible for atheists", + "99 red balloons", + "a biter egg", + "what the cat dragged in", + "a straight banana", + "a clock where all the hours say ‘Party time’", + "some overcooked bacon", + "a copy of a copy of a copy of a cloning machine", + "trademark infringement", + "their undying, unquestionable love", + "an old Nintendo cartridge that only works if you blow on it", + "all their hopes and ambitions condensed into a single action", + "their existential crisis", + "a call for their attention", + "an antimatter version of themselves", + "a left handed tin opener", + "a fireplace poker", + "a parallel universe in which the poking happens the other way round", + "a message in a bottle", + "spaghetti bolognese", + "an active proximity mine", + "their fear of rejection", + "all the effort it takes to press a button in a video game", + "a genuine fake Rolex watch", + "the last digit of Pi", + "the 0.17 patch notes", + "a chest full of landfill", + "a Comcast call centre", + "a 3-10-3 train", + "a train deadlock", + "an incorrectly placed rail signal", + "a desync log", + "'error executing command'", + "a stack overflow", + "Trump’s tax return", + "an ego deflating machine", + "the keys to Redlabel’s gentleman's club", + "a used voodoo doll", + "a cheese grater that has seen better days", + "a bowl of swinger’s car keys", + "a student’s cookbook where all the pages are damp", + "a copy of ‘How to start a cult’ covered in Redlabel’s fingerprints", + "a censored copy of 1984", + "the local orphanage’s ice cream delivery", + "a map to the treasure", + "the clothes they use for cross dressing at the weekend", + "their student loans", + "a cattle prod", + "forbidden love", + "an innocent looking poke, but deep down their heart longs for so much more", + "a rough draft of their new rom-com script", + "a finger covered in whipped cream and an expression that says there is plenty more where that came from", + "an empty toilet roll tube and a look of urgent desperation", + "a kitchen sink that does everything except work as a sink", + "teenage angst", + "sexually repressive parents", + "an overdue pregnant women", + "biter pheromones", + "a mail order bride", + "an unoriginal message", + "a subscription to the magazine ‘Identifying wood’", + "their shopping list", + "the monster that lives under their bed", + "a creaky floorboard", + "an ask for forgiveness", + "suspicious intentions", + "all of their childhood nightmares", + "an expired winning lottery ticket", + "all the trash that’s piling up round back", + "The location where they bury the bodies", + "a fear of trains", + "a piece of blu tack that is covered in hairs", + "a life filled with regret", + "a lifejacket for a child", + "a neglected tamagotchi", + "an obese cat", + "a randomly selected predetermined message", + "a copy of the Kamasutra with some of the pages missing", + "the american dream", + "a fluffy pillow", + "the Spanish Inquisition", + "an addiction to Cracktorio", + "a broken mirror", + "a dismembered hooker", + "a popped balloon", + "a hipster breakfast", + "a nintendo cartridge", + "a generic greething card", + "an empty bottle of barbiturics", + "a cleanup on aisle 4", + "the Eiffel Tower", + "an idea for a poke message", + "Hodor's brain", + "a barn full of mice", + "thousands of wooden chests", + "a deconstruction planner for environment only", + "a blueprint that makes a lag machine", + "a poorly setup Miditorio blueprint", + "their chores", + "a random adjective followed by a random noun", + "the Communist Manifesto for capitalists", + "an uncomputable number", + "a decimal in factorio", + "an old redmew fun fact", + "a poke", + "a cheeto that looks like Abraham Lincoln", + "the lack of hope these messages give", + "recursives with no end condition", + "a player poking a player with a player poking a player with...", + "Ebenezer Scrooge's wallet", + "a hundred dollars paid in pennies", + "a game of paintball in a room filled with mirrors", + "a hunted house running away from a rifle shot", + "a breakfast of bleach and nails", + "the time of day", + "the square root of two", + "two plus two minus one", + "a textbook on elementary calculus in group theory", + "a younger version of themself", + "a grabbing claw", + "a missing comma in code", + "a calculator dividing by zero", + "ultrared ultraviolet light", + "the originality in half of these", + "a collection of Sim's patch notes", + "a game of Dwarf Fortress", + "immense eye strain", + "Ctrl + Alt + F4", + "a match box in a boxing glove", + "a goat with a pen inside", + "the amount of iterations before bogosort sorts 100 objects", + "reddit.com/r/redmew", + "a recording of Seeburg background music", + "an ever-expanding trumpet", + "the current number of poke messages: 556", + "the twelve pokes of pokemas", + "a pokey pokemon", + "a spot in the Boston Marathon", + "an eleven-seven", + "an engineer in a car in a rocket", + "the fact that you can landfill over a pump", + "a fish that swims in land", + "an everything bagel without the bagel", + "the three hundred thirty third poke message", + "a fake holiday", + "poke messages that are useful", + "a recorder sonata", + "a real cannon", + "lorem ipsum dolor sit amet consectetuer adipiscing elit sed diam nonummy nibh euismod tincidunt", + "a handle taped on a handlebar mustache", + "a Rick and Morty copypasta", + "a skip button that skips to the next ad", + "a loading screen that doesn't tell you progress", + "the acceleration of earth's gravity", + "a poke repeated twice", + "a poke repeated twice", + "a sentence intentionnaly mispeeled", + "an overly proud committee", + "a narcissitic history book", + "a fruit more intelligent than cows", + "a pig the size of your pinky", + "a schizophrenic sorting algorithm", + "a dye of rhea", + "a stick the dog brought in", + "the yellow paint on a pencil", + "a flag of surrender", + "their private airstrip", + "a well with a hundred frogs", + "syntax errors", + "a ten foot chin", + "a goldfish that plays jazz", + "a free lettuce", + "a hilarious sock", + "jean skirts", + "a fire hydrant that shoots fire", + "a teethbrush", + "a toothsbrush", + "a belief that caboose plural is cabeese", + "an unidentified flying object", + "a bigfoot sighting", + "their determination", + "the steadily declining quality of these poke messages as I run out of ideas", + "a random generator for these messages", + "a hat made for whales", + "an ice cube on fire", + "a ring that wears you", + "an everyday noun", + "a fun fact", + "the fun fact: there are three other fun fact messages", + "the fun fact: most calico cats are female", + "the fun fact: sloths move about 2.564 times faster than snails", + "the fun fact: there are only two actual fun facts", + "a broken clock in prison", + "a wishing well with more money than you", + "a snake in a hole", + "a colossal toad", + "a pair of shoes for a colossal toad", + "an alarm that sounds like the fire alarm", + "a sponge made out of ice", + "a rude key", + "Hodor", + "a moonwalking horse", + "a horn made out of jello", + "a fine wine negative one year old", + "a six running away from seven", + "an island of cannibals that's sinking", + "a respectful insult", + "a highfalutin retort", + "a rabbit in the briar patch", + "a petition to respell poker as poke her", + "the four hundredth poke message", +} diff --git a/resources/ranks.lua b/resources/ranks.lua new file mode 100644 index 0000000000..977bc9e578 --- /dev/null +++ b/resources/ranks.lua @@ -0,0 +1,8 @@ +-- When adding/removing/changing ranks, rank_system has a migrate_data() function you can use to adjust the existing data. +return { + probation = -10, + guest = 0, + auto_trusted = 10, + regular = 20, + admin = 30, +} diff --git a/resources/tag_groups.lua b/resources/tag_groups.lua new file mode 100644 index 0000000000..527a9bf010 --- /dev/null +++ b/resources/tag_groups.lua @@ -0,0 +1,53 @@ +-- A part of band.lua +-- Feel free to edit. + +return { + ['Trooper'] = { + path = 'item/tank', + verb = 'strengthened' + }, + ['Mining'] = { + path = 'item/electric-mining-drill', + verb = 'enriched' + }, + ['Smelting'] = { + path = 'item/stone-furnace', + verb = 'fused' + }, + ['Production'] = { + path = 'item/assembling-machine-2', + verb = 'enhanced' + }, + ['Science'] = { + path = 'item/science-pack-3', + verb = 'advanced' + }, + ['Wizard'] = { + path = 'item/green-wire', + verb = 'combinated' + }, + ['Trains'] = { + path = 'item/locomotive', + verb = 'derailed' + }, + ['Oil'] = { + path = 'fluid/crude-oil', + verb = 'lubricated' + }, + ['Powah!'] = { + path = 'item/steam-engine', + verb = 'electrified' + }, + ['Spaceman'] = { + path = 'item/rocket-silo', + verb = 'warped' + }, + ['Cat'] = { + path = 'item/raw-fish', + verb = 'mewed' + }, + ['Dog'] = { + path = 'entity/medium-biter', + verb = 'woofed' + } +} diff --git a/resources/turkey_messages.lua b/resources/turkey_messages.lua new file mode 100644 index 0000000000..86876ec09f --- /dev/null +++ b/resources/turkey_messages.lua @@ -0,0 +1,57 @@ +return { + 'Benjamin Franklin wanted the turkey to be the national bird, not the eagle.', + 'There was no turkey on the menu at the first Thanksgiving.', + 'Thanksgiving is the reason for TV dinners!', + 'Wild turkeys can run 20 miles per hour when they are scared.', + 'Female turkeys (called hens) do not gobble.', + 'The real first Thanksgiving was held in Texas in 1541.', + 'Baby turkeys are called poults.', + 'The best way to tell if a cranberry is ripe it to see if it bounces.', + 'Benjamin Franklin wanted the turkey to be the national bird, not the eagle.', + 'There was no turkey on the menu at the first Thanksgiving.', + 'Thanksgiving is the reason for TV dinners!', + 'Wild turkeys can run 20 miles per hour when they are scared.', + 'Female turkeys (called hens) do not gobble.', + 'The real first Thanksgiving was held in Texas in 1541.', + 'Baby turkeys are called poults.', + 'The best way to tell if a cranberry is ripe it to see if it bounces.', + 'There were no forks at the first Thanksgiving. ', + 'Thomas Jefferson refused to declare Thanksgiving as a holiday.', + 'About 46 million turkeys are cooked for Thanksgiving each year.', + 'The Butterball Turkey Talk Line answers almost 100,000 calls each season.', + 'There are four places in the US named Turkey.', + 'Black Friday is the busiest day of the year for plumbers.', + 'Jingle Bells was originally a Thanksgiving song.', + 'Turkey-like creatures roamed the Americas 75 million years ago.', + 'Canadian Thanksgiving predates American Thanksgiving by 43 years.', + 'On average, it takes about 7 hours to cook a Thanksgiving dinner. People spend about 16 minutes eating it.', + 'The first Thanksgiving was held in the autumn of 1621', + 'Why did the turkey cross the road? It was Thanksgiving and he wanted to convince people he was a chicken.', + 'What did the turkey say to the computer? "Google, google, google."', + 'Why did the farmer separate the turkey and the chicken? He sensed fowl play.', + 'What music did the Pilgrims listen to? Plymouth rock.', + 'If Pilgrims were alive today what would they be known for? Their age!', + 'What does Miley Cyrus eat for Thanksgiving? Twerky.', + 'If your great-grandmother saw you making boxed mashed potatoes shed turn over in her gravy.', + 'What does a turkey drink from? A gobble-t.', + 'What smells best at Thanksgiving dinner? Your nose.', + 'Thanksgiving is the only holiday where you eat the mascot.', + 'How do you keep a turkey in suspense? Ill tell you later.', + 'My family told me to stop telling bad Thanksgiving jokes, but I couldnt just quit cold turkey.', + 'What kind of music did the Pilgrims like? Plymouth Rock ', + 'If April showers bring May flowers, what do May flowers bring? Pilgrims ', + 'Why cant you take a turkey to church? They use FOWL language. ', + 'Why was the Thanksgiving soup so expensive? It had 24 carrots. ', + 'What happened when the turkey got into a fight? He got the stuffing knocked out of him! ', + 'What do you get when you cross a turkey with a banjo? A turkey that can pluck itself! ', + 'When do you serve tofu turkey? Pranksgiving. ', + 'What did the turkey say to the man who tried to shoot it? Liberty, Equality and Bad aim for all. ', + 'Who doesnt eat on Thanksgiving? A turkey because it is always stuffed. ', + 'Why did the Pilgrims want to sail to America in the spring? Because April showers bring Mayflowers! ', + 'What did baby corn say to mama corn? Wheres popcorn? ', + 'If the Pilgrims were alive today, what would they be most famous for? Their AGE! ', + 'Why do the pants of pilgrims keep falling down? Because their belt buckles are on their hats! ', + 'Why did they let the turkey join the band? Because he had the drumsticks ', + 'What does Miley Cyrus eat for Thanksgiving? Twerk-ey! ', + 'What did the mother turkey say to her disobedient children? "If your father could see you now, hed turn over in his gravy!" ' +} diff --git a/resources/version.lua b/resources/version.lua new file mode 100644 index 0000000000..98d7ac58c7 --- /dev/null +++ b/resources/version.lua @@ -0,0 +1,2 @@ +global.redmew_version = nil +global.expgaming_version = '5.0.0' \ No newline at end of file diff --git a/utils/alien_evolution_progress.lua b/utils/alien_evolution_progress.lua new file mode 100644 index 0000000000..343aff821c --- /dev/null +++ b/utils/alien_evolution_progress.lua @@ -0,0 +1,179 @@ +--[[-- info + Original (javascript) version: https://hastebin.com/udakacavap.js + Can be tested against: https://wiki.factorio.com/Enemies#Spawn_chances_by_evolution_factor +]] + +-- dependencies +local Global = require 'utils.global' +local Debug = require 'utils.debug' +local table = require 'utils.table' + +-- localized functions +local get_random_weighted = table.get_random_weighted +local round = math.round +local ceil = math.ceil +local floor = math.floor +local random = math.random +local pairs = pairs +local format = string.format + +-- this +local AlienEvolutionProgress = {} + +local memory = { + spawner_specifications = {}, + spawner_specifications_count = 0, + evolution_cache = { + ['biter-spawner'] = { + evolution = -1, + weight_table = {}, + }, + ['spitters-spawner'] = { + evolution = -1, + weight_table = {}, + }, + }, +} + +Global.register_init({ + memory = memory, +}, function(tbl) + for name, prototype in pairs(game.entity_prototypes) do + if prototype.type == 'unit-spawner' and prototype.subgroup.name == 'enemies' then + tbl.memory.spawner_specifications[name] = prototype.result_units + memory.spawner_specifications_count = memory.spawner_specifications_count + 1 + end + end +end, function(tbl) + memory = tbl.memory +end) + +local function lerp(low, high, pos) + local s = high.evolution_factor - low.evolution_factor; + local l = (pos - low.evolution_factor) / s; + return (low.weight * (1 - l)) + (high.weight * l) +end + +local function get_values(map, evolution_factor) + local result = {} + local sum = 0 + + for _, spawner_data in pairs(map) do + local list = spawner_data.spawn_points; + local low = list[1]; + local high = list[#list]; + + for _, val in pairs(list) do + local val_evolution = val.evolution_factor + if val_evolution <= evolution_factor and val_evolution > low.evolution_factor then + low = val; + end + if val_evolution >= evolution_factor and val_evolution < high.evolution_factor then + high = val + end + end + + local val + if evolution_factor <= low.evolution_factor then + val = low.weight + elseif evolution_factor >= high.evolution_factor then + val = high.weight; + else + val = lerp(low, high, evolution_factor) + end + sum = sum + val; + + result[spawner_data.unit] = val; + end + + local weighted_table = {} + local count = 0 + for index, _ in pairs(result) do + count = count + 1 + weighted_table[count] = {index, result[index] / sum} + end + + return weighted_table; +end + +local function get_spawner_values(spawner, evolution) + local spawner_specification = memory.spawner_specifications[spawner] + if not spawner_specification then + Debug.print(format('Spawner "%s" does not exist in the prototype data', spawner)) + return + end + + local cache = memory.evolution_cache[spawner] + + if not cache then + cache = { + evolution = -1, + weight_table = {}, + } + memory.evolution_cache[spawner] = cache + end + + local evolution_value = round(evolution * 100) + if (cache.evolution < evolution_value) then + cache.evolution = evolution_value + cache.weight_table = get_values(spawner_specification, evolution) + end + + return cache.weight_table +end + +local function calculate_total(count, spawner, evolution) + if count == 0 then + return {} + end + + local spawner_values = get_spawner_values(spawner, evolution) + if not spawner_values then + return {} + end + + local aliens = {} + for _ = 1, count do + local name = get_random_weighted(spawner_values) + aliens[name] = (aliens[name] or 0) + 1 + end + + return aliens +end + +---Creates the spawner_request structure required for AlienEvolutionProgress.get_aliens for all +---available spawners. If dividing the total spawners by the total aliens causes a fraction, the +---fraction will decide a chance to spawn. 1 alien for 2 spawners will have 50% on both. +---@param total_aliens table +function AlienEvolutionProgress.create_spawner_request(total_aliens) + local per_spawner = total_aliens / memory.spawner_specifications_count + local fraction = per_spawner % 1 + + local spawner_request = {} + for spawner, _ in pairs(memory.spawner_specifications) do + local count = per_spawner + if fraction > 0 then + if random() > fraction then + count = ceil(count) + else + count = floor(count) + end + end + spawner_request[spawner] = count + end + + return spawner_request +end + +function AlienEvolutionProgress.get_aliens(spawner_requests, evolution) + local aliens = {} + for spawner, count in pairs(spawner_requests) do + for name, amount in pairs(calculate_total(count, spawner, evolution)) do + aliens[name] = (aliens[name] or 0) + amount + end + end + + return aliens +end + +return AlienEvolutionProgress diff --git a/utils/command.lua b/utils/command.lua new file mode 100644 index 0000000000..5f57110a68 --- /dev/null +++ b/utils/command.lua @@ -0,0 +1,326 @@ +local Event = require 'utils.event' +local Game = require 'utils.game' +local Utils = require 'utils.core' +local Timestamp = require 'utils.timestamp' +local Rank = require 'features.rank_system' +local Donator = require 'features.donator' +local Server = require 'features.server' +local Ranks = require 'resources.ranks' + +local insert = table.insert +local format = string.format +local next = next +local serialize = serpent.line +local match = string.match +local gmatch = string.gmatch +local get_rank_name = Rank.get_rank_name + +local Command = {} + +local deprecated_command_alternatives = { + ['silent-command'] = 'sc', + ['tpplayer'] = 'tp ', + ['tppos'] = 'tp', + ['tpmode'] = 'tp mode', + ['color-redmew'] = 'redmew-color' +} + +local notify_on_commands = { + ['version'] = 'RedMew has a version as well, accessible via /redmew-version', + ['color'] = 'RedMew allows color saving and a color randomizer: check out /redmew-color', + ['ban'] = 'In case your forgot: please remember to include a message on how to appeal a ban' +} + +local option_names = { + ['description'] = 'A description of the command', + ['arguments'] = 'A table of arguments, example: {"foo", "bar"} would map the first 2 arguments to foo and bar', + ['default_values'] = 'A default value for a given argument when omitted, example: {bar = false}', + ['required_rank'] = 'Set this to determins what rank is required to execute a command', + ['donator_only'] = 'Set this to true if only donators may execute this command', + ['debug_only'] = 'Set this to true if it should be registered when _DEBUG is true', + ['cheat_only'] = 'Set this to true if it should be registered when _CHEATS is true', + ['allowed_by_server'] = 'Set to true if the server (host) may execute this command', + ['allowed_by_player'] = 'Set to false to disable players from executing this command', + ['log_command'] = 'Set to true to log commands. Always true when admin is required', + ['capture_excess_arguments'] = 'Allows the last argument to be the remaining text in the command', + ['custom_help_text'] = 'Sets a custom help text to override the auto-generated help', +} + +---Validates if there aren't any wrong fields in the options. +---@param command_name string +---@param options table +local function assert_existing_options(command_name, options) + local invalid = {} + for name, _ in pairs(options) do + if not option_names[name] then + insert(invalid, name) + end + end + + if next(invalid) then + error(format("The following options were given to the command '%s' but are invalid: %s", command_name, serialize(invalid))) + end +end + +---Adds a command to be executed. +--- +---Options table accepts the following structure: { +--- description = 'A description of the command', +--- arguments = {'foo', 'bar'}, -- maps arguments to these names in the given sequence +--- default_values = {bar = false}, -- gives a default value to 'bar' when omitted +--- required_rank = Ranks.regular, -- defaults to Ranks.guest +--- donator_only = true, -- defaults to false +--- debug_only = true, -- registers the command if _DEBUG is set to true, defaults to false +--- cheat_only = true, -- registers the command if _CHEATS is set to true, defaults to false +--- allowed_by_server = true, -- lets the server execute this, defaults to false +--- allowed_by_player = false, -- lets players execute this, defaults to true +--- log_command = true, -- defaults to false unless admin only, then always true +--- capture_excess_arguments = true, -- defaults to false, captures excess arguments in the last argument, useful for sentences +---} +--- +---The callback receives the following arguments: +--- - arguments (indexed by name, value is extracted from the parameters) +--- - the LuaPlayer or nil if it doesn't exist (such as the server player) +--- - the game tick in which the command was executed +--- +---@param command_name string +---@param options table +---@param callback function +function Command.add(command_name, options, callback) + local description = options.description or '[Undocumented command]' + local arguments = options.arguments or {} + local default_values = options.default_values or {} + local required_rank = options.required_rank or Ranks.guest + local donator_only = options.donator_only or false + local debug_only = options.debug_only or false + local cheat_only = options.cheat_only or false + local capture_excess_arguments = options.capture_excess_arguments or false + local custom_help_text = options.custom_help_text or false + local allowed_by_server = options.allowed_by_server or false + local allowed_by_player = options.allowed_by_player + local log_command = options.log_command or (required_rank >= Ranks.admin) or false + local argument_list_size = table_size(arguments) + local argument_list = '' + + assert_existing_options(command_name, options) + + if nil == options.allowed_by_player then + allowed_by_player = true + end + + if (not _DEBUG and debug_only) and (not _CHEATS and cheat_only) then + return + end + + if not allowed_by_player and not allowed_by_server then + error(format("The command '%s' is not allowed by the server nor player, please enable at least one of them.", command_name)) + end + + for index, argument_name in pairs(arguments) do + local argument_display = argument_name + for default_value_name, _ in pairs(default_values) do + if default_value_name == argument_name then + argument_display = argument_display .. ':optional' + break + end + end + + if argument_list_size == index and capture_excess_arguments then + argument_display = argument_display .. ':sentence' + end + + argument_list = format('%s<%s> ', argument_list, argument_display) + end + + local extra = '' + + if allowed_by_server and not allowed_by_player then + extra = ' (Server only)' + elseif allowed_by_player and (required_rank > Ranks.guest) then + extra = {'command.required_rank', get_rank_name(required_rank)} + elseif allowed_by_player and donator_only then + extra = ' (Donator only)' + end + + local help_text = {'command.help_text_format',(custom_help_text or argument_list), description, extra} + + commands.add_command(command_name, help_text, function (command) + local print -- custom print reference in case no player is present + local player = game.player + local player_name = player and player.valid and player.name or '' + if not player or not player.valid then + print = log + + if not allowed_by_server then + print(format("The command '%s' is not allowed to be executed by the server.", command_name)) + return + end + else + print = player.print + + if not allowed_by_player then + print(format("The command '%s' is not allowed to be executed by players.", command_name)) + return + end + + if Rank.less_than(player_name, required_rank) then + print({'command.higher_rank_needed', command_name, get_rank_name(required_rank)}) + return + end + + if donator_only and not Donator.is_donator(player_name) then + print(format("The command '%s' is only allowed for donators.", command_name)) + return + end + end + + local named_arguments = {} + local from_command = {} + local raw_parameter_index = 1 + for param in gmatch(command.parameter or '', '%S+') do + if capture_excess_arguments and raw_parameter_index == argument_list_size then + if not from_command[raw_parameter_index] then + from_command[raw_parameter_index] = param + else + from_command[raw_parameter_index] = from_command[raw_parameter_index] .. ' ' .. param + end + else + from_command[raw_parameter_index] = param + raw_parameter_index = raw_parameter_index + 1 + end + end + + local errors = {} + + for index, argument in pairs(arguments) do + local parameter = from_command[index] + + if not parameter then + for default_value_name, default_value in pairs(default_values) do + if default_value_name == argument then + parameter = default_value + break + end + end + end + + if parameter == nil then + insert(errors, format('Argument "%s" from command %s is missing.', argument, command_name)) + else + named_arguments[argument] = parameter + end + end + + local return_early = false + + for _, error in pairs(errors) do + return_early = true + print(error) + end + + if return_early then + return + end + + if log_command then + local tick = 'pre-game' + if game then + tick = Utils.format_time(game.tick) + end + local server_time = Server.get_current_time() + if server_time then + server_time = format('(Server time: %s)', Timestamp.to_string(server_time)) + else + server_time = '' + end + + log(format('%s(Map time: %s) [%s Command] %s, used: %s %s', server_time, tick, (options.required_rank >= Ranks.admin) and 'Admin' or 'Player', player_name, command_name, serialize(named_arguments))) + end + + local success, error = pcall(function () + callback(named_arguments, player, command.tick) + end) + + if not success then + local serialized_arguments = serialize(named_arguments) + if _DEBUG then + print(format("%s triggered an error running a command and has been logged: '%s' with arguments %s", player_name, command_name, serialized_arguments)) + print(error) + return + end + + print(format('There was an error running %s, it has been logged.', command_name)) + log(format("Error while running '%s' with arguments %s: %s", command_name, serialized_arguments, error)) + end + end) +end + +function Command.search(keyword) + local matches = {} + local count = 0 + keyword = keyword:lower() + for name, description in pairs(commands.commands) do + local command = format('%s %s', name, description) + if match(command:lower(), keyword) then + count = count + 1 + matches[count] = command + end + end + + -- built-in commands use LocalisedString, which cannot be translated until player.print is called + for name in pairs(commands.game_commands) do + name = name + if match(name:lower(), keyword) then + count = count + 1 + matches[count] = name + end + end + + return matches +end + +--- Trigger messages on deprecated or defined commands, ignores the server +local function on_command(event) + if not event.player_index then + return + end + + local alternative = deprecated_command_alternatives[event.command] + if alternative then + local player = Game.get_player_by_index(event.player_index) + if player then + player.print(format('Warning! Usage of the command "/%s" is deprecated. Please use "/%s" instead.', event.command, alternative)) + end + end + + local notification = notify_on_commands[event.command] + if notification and event.player_index then + local player = Game.get_player_by_index(event.player_index) + if player then + player.print(notification) + end + end +end + +--- Traps command errors if not in DEBUG. +if not _DEBUG then + local old_add_command = commands.add_command + commands.add_command = + function(name, desc, func) + old_add_command( + name, + desc, + function(cmd) + local success, error = pcall(func, cmd) + if not success then + log(error) + Game.player_print('Sorry there was an error running ' .. cmd.name) + end + end + ) + end +end + +Event.add(defines.events.on_console_command, on_command) + +return Command diff --git a/utils/core.lua b/utils/core.lua new file mode 100644 index 0000000000..d8bdc6b3d5 --- /dev/null +++ b/utils/core.lua @@ -0,0 +1,246 @@ +-- This file contains core utilities used by the redmew scenario. + +-- Dependencies +local Game = require 'utils.game' +local Color = require 'resources.color_presets' +local Server = require 'features.server' + +-- localized functions +local random = math.random +local sqrt = math.sqrt +local floor = math.floor +local format = string.format +local match = string.match +local insert = table.insert +local concat = table.concat + +-- local constants +local prefix = '## - ' +local minutes_to_ticks = 60 * 60 +local hours_to_ticks = 60 * 60 * 60 +local ticks_to_minutes = 1 / minutes_to_ticks +local ticks_to_hours = 1 / hours_to_ticks + +-- local vars +local Module = {} + +--- Measures distance between pos1 and pos2 +function Module.distance(pos1, pos2) + local dx = pos2.x - pos1.x + local dy = pos2.y - pos1.y + return sqrt(dx * dx + dy * dy) +end + +--- Takes msg and prints it to all players except provided player +-- @param msg table if locale is used +-- @param player the player not to send the message to +-- @param color the color to use for the message, defaults to white +function Module.print_except(msg, player, color) + if not color then + color = Color.white + end + + for _, p in pairs(game.connected_players) do + if p ~= player then + p.print(msg, color) + end + end +end + +--- Prints a message to all online admins +-- @param msg table if locale is used +-- @param source string must be the name of a player, nil for server. +function Module.print_admins(msg, source) + local source_name + local chat_color + if source then + if type(source) == 'string' then + source_name = source + chat_color = game.players[source].chat_color + else + source_name = source.name + chat_color = source.chat_color + end + else + source_name = 'Server' + chat_color = Color.yellow + end + local formatted_msg = {'utils_core.print_admins',prefix, source_name, msg} + log(formatted_msg) + for _, p in pairs(game.connected_players) do + if p.admin then + p.print(formatted_msg, chat_color) + end + end +end + +--- Returns a valid string with the name of the actor of a command. +function Module.get_actor() + if game.player then + return game.player.name + end + return '' +end + +function Module.cast_bool(var) + if var then + return true + else + return false + end +end + +function Module.find_entities_by_last_user(player, surface, filters) + if type(player) == 'string' or not player then + error("bad argument #1 to '" .. debug.getinfo(1, 'n').name .. "' (number or LuaPlayer expected, got " .. type(player) .. ')', 1) + return + end + if type(surface) ~= 'table' and type(surface) ~= 'number' then + error("bad argument #2 to '" .. debug.getinfo(1, 'n').name .. "' (number or LuaSurface expected, got " .. type(surface) .. ')', 1) + return + end + local entities = {} + local filter = filters or {} + if type(surface) == 'number' then + surface = game.surfaces[surface] + end + if type(player) == 'number' then + player = Game.get_player_by_index(player) + end + filter.force = player.force.name + for _, e in pairs(surface.find_entities_filtered(filter)) do + if e.last_user == player then + insert(entities, e) + end + end + return entities +end + +function Module.ternary(c, t, f) + if c then + return t + else + return f + end +end + +--- Takes a time in ticks and returns a string with the time in format "x hour(s) x minute(s)" +function Module.format_time(ticks) + local result = {} + + local hours = floor(ticks * ticks_to_hours) + if hours > 0 then + ticks = ticks - hours * hours_to_ticks + insert(result, hours) + if hours == 1 then + insert(result, 'hour') + else + insert(result, 'hours') + end + end + + local minutes = floor(ticks * ticks_to_minutes) + insert(result, minutes) + if minutes == 1 then + insert(result, 'minute') + else + insert(result, 'minutes') + end + + return concat(result, ' ') +end + +--- Prints a message letting the player know they cannot run a command +-- @param name string name of the command +function Module.cant_run(name) + Game.player_print("Can't run command (" .. name .. ') - insufficient permission.') +end + +--- Logs the use of a command and its user +-- @param actor string with the actor's name (usually acquired by calling get_actor) +-- @param command the command's name as table element +-- @param parameters the command's parameters as a table (optional) +function Module.log_command(actor, command, parameters) + local action = concat {'[Admin-Command] ', actor, ' used: ', command} + if parameters then + action = concat {action, ' ', parameters} + end + log(action) +end + +function Module.comma_value(n) -- credit http://richard.warburton.it + local left, num, right = match(n, '^([^%d]*%d)(%d*)(.-)$') + return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right +end + +--- Asserts the argument is one of type arg_types +-- @param arg the variable to check +-- @param arg_types the type as a table of sings +-- @return boolean +function Module.verify_mult_types(arg, arg_types) + for _, arg_type in pairs(arg_types) do + if type(arg) == arg_type then + return true + end + end + return false +end + +--- Returns a random RGB color as a table +function Module.random_RGB() + return {r = random(0, 255), g = random(0, 255), b = random(0, 255)} +end + +--- Sets a table element to value while also returning value. +-- @param tbl table to change the element of +-- @param key string +-- @param value nil|boolean|number|string|table to set the element to +-- @return value +function Module.set_and_return(tbl, key, value) + tbl[key] = value + return value +end + +--- Takes msg and prints it to all players. Also prints to the log and discord +-- @param msg The message to print +-- @param warning_prefix The name of the module/warning +function Module.action_warning(warning_prefix, msg) + game.print(prefix .. msg, Color.yellow) + msg = format('%s %s', warning_prefix, msg) + log(msg) + Server.to_discord_bold(msg) +end + +--- Takes msg and prints it to all players except provided player. Also prints to the log and discord +-- @param msg The message to print +-- @param warning_prefix The name of the module/warning +-- @param player the player not to send the message to +function Module.silent_action_warning(warning_prefix, msg, player) + Module.print_except(prefix .. msg, player, Color.yellow) + msg = format('%s %s', warning_prefix, msg) + log(msg) + Server.to_discord_bold(msg) +end + +-- add utility functions that exist in base factorio/util +require 'util' + +--- Moves a position according to the parameters given +-- Notice: only accepts cardinal directions as direction +-- @param position
table containing a map position +-- @param direction north, east, south, west +-- @param distance +-- @return
modified position +Module.move_position = util.moveposition + +--- Takes a direction and gives you the opposite +-- @param direction north, east, south, west, northeast, northwest, southeast, southwest +-- @return representing the direction +Module.opposite_direction = util.oppositedirection + +--- Takes the string of a module and returns whether is it available or not +-- @param name the name of the module (ex. 'utils.core') +-- @return +Module.is_module_available = util.ismoduleavailable + +return Module diff --git a/utils/debug.lua b/utils/debug.lua new file mode 100644 index 0000000000..1c1a363309 --- /dev/null +++ b/utils/debug.lua @@ -0,0 +1,164 @@ +-- localised functions +local format = string.format +local match = string.match +local gsub = string.gsub +local serialize = serpent.line +local debug_getupvalue = debug.getupvalue + +-- this +local Debug = {} + +global.debug_message_count = 0 + +---@return number next index +local function increment() + local next = global.debug_message_count + 1 + global.debug_message_count = next + + return next +end + +--- Takes the table output from debug.getinfo and pretties it +local function cleanup_debug(debug_table) + local short_src = match(debug_table.source, '/[^/]*/[^/]*$') + -- require will not return a valid string so short_src may be nil here + if short_src then + short_src = gsub(short_src, '%.lua', '') + end + + return format('[function: %s file: %s line number: %s]', debug_table.name, short_src, debug_table.currentline) +end + +---Shows the given message if debug is enabled. Uses serpent to print non scalars. +-- @param message +-- @param stack_traceback levels of stack trace to give, defaults to 1 level if nil +function Debug.print(message, trace_levels) + if not _DEBUG then + return + end + + if not trace_levels then + trace_levels = 2 + else + trace_levels = trace_levels + 1 + end + + local traceback_string = '' + if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then + message = serialize(message) + end + + message = format('[%d] %s', increment(), tostring(message)) + + if trace_levels >= 2 then + for i = 2, trace_levels do + local debug_table = debug.getinfo(i) + if debug_table then + traceback_string = format('%s -> %s', traceback_string, cleanup_debug(debug_table)) + else + break + end + end + message = format('%s - Traceback%s', message, traceback_string) + end + + if _LIFECYCLE == _STAGE.runtime then + game.print(message) + end + log(message) +end + +local function get(obj, prop) + return obj[prop] +end + +local function get_lua_object_type_safe(obj) + local s, r = pcall(get, obj, 'help') + + if not s then + return + end + + return r():match('Lua%a+') +end + +--- Returns the value of the key inside the object +-- or 'InvalidLuaObject' if the LuaObject is invalid. +-- or 'InvalidLuaObjectKey' if the LuaObject does not have an entry at that key +-- @param object
LuaObject or metatable +-- @param key +-- @return +function Debug.get_meta_value(object, key) + if Debug.object_type(object) == 'InvalidLuaObject' then + return 'InvalidLuaObject' + end + + local suc, value = pcall(get, object, key) + if not suc then + return 'InvalidLuaObjectKey' + end + + return value +end + +--- Returns the Lua data type or the factorio LuaObject type +-- or 'NoHelpLuaObject' if the LuaObject does not have a help function +-- or 'InvalidLuaObject' if the LuaObject is invalid. +-- @param object +-- @return string +function Debug.object_type(object) + local obj_type = type(object) + + if obj_type ~= 'table' or type(object.__self) ~= 'userdata' then + return obj_type + end + + local suc, valid = pcall(get, object, 'valid') + if not suc then + -- no 'valid' property + return get_lua_object_type_safe(object) or 'NoHelpLuaObject' + end + + if not valid then + return 'InvalidLuaObject' + else + return get_lua_object_type_safe(object) or 'NoHelpLuaObject' + end +end + +---Shows the given message if debug is on. +---@param position Position +---@param message string +function Debug.print_position(position, message) + Debug.print(format('%s %s', serialize(position), message)) +end + +---Executes the given callback if cheating is enabled. +---@param callback function +function Debug.cheat(callback) + if _CHEATS then + callback() + end +end + +--- Returns true if the function is a closure, false otherwise. +-- A closure is a function that contains 'upvalues' or in other words +-- has a reference to a local variable defined outside the function's scope. +-- @param func +-- @return boolean +function Debug.is_closure(func) + local i = 1 + while true do + local n = debug_getupvalue(func, i) + + if n == nil then + return false + elseif n ~= '_ENV' then + return true + end + + i = i + 1 + end +end + +return Debug diff --git a/utils/dump_env.lua b/utils/dump_env.lua new file mode 100644 index 0000000000..b5cbccac18 --- /dev/null +++ b/utils/dump_env.lua @@ -0,0 +1,32 @@ +-- A small debugging tool that writes the contents of _ENV to a file when the game loads. +-- Useful for ensuring you get the same information when loading +-- the reference and desync levels in desync reports. +-- dependencies +local table = require 'utils.table' +local Event = require 'utils.event' + +-- localized functions +local inspect = table.inspect + +-- local constants +local filename = 'env_dump.lua' + +-- Removes metatables and the package table +local filter = function(item, path) + if path[#path] ~= inspect.METATABLE and item ~= 'package' then + return item + end +end + +local function player_joined(event) + local dump_string = inspect(_ENV, {process = filter}) + if dump_string then + local s = string.format('tick on join: %s\n%s', event.tick, dump_string) + game.write_file(filename, s) + game.print('_ENV dumped into ' .. filename) + else + game.print('_ENV not dumped, dump_string was nil') + end +end + +Event.add(defines.events.on_player_joined_game, player_joined) diff --git a/utils/event.lua b/utils/event.lua new file mode 100644 index 0000000000..e183bb2c8b --- /dev/null +++ b/utils/event.lua @@ -0,0 +1,457 @@ +--- This Module allows for registering multiple handlers to the same event, overcoming the limitation of script.register. +-- +-- ** Event.add(event_name, handler) ** +-- +-- Handlers added with Event.add must be added at the control stage or in Event.on_init or Event.on_load. +-- Remember that for each player, on_init or on_load is run, never both. So if you can't add the handler in the +-- control stage add the handler in both on_init and on_load. +-- Handlers added with Event.add cannot be removed. +-- For handlers that need to be removed or added at runtime use Event.add_removable. +-- @usage +-- local Event = require 'utils.event' +-- Event.add( +-- defines.events.on_built_entity, +-- function(event) +-- game.print(serpent.block(event)) -- prints the content of the event table to console. +-- end +-- ) +-- +-- ** Event.add_removable(event_name, token) ** +-- +-- For conditional event handlers. Event.add_removable can be safely called at runtime without desync risk. +-- Only use this if you need to add the handler at runtime or need to remove the handler, otherwise use Event.add +-- +-- Event.add_removable can be safely used at the control stage or in Event.on_init. If used in on_init you don't +-- need to also add in on_load (unlike Event.add). +-- Event.add_removable cannot be called in on_load, doing so will crash the game on loading. +-- Token is used because it's a desync risk to store closures inside the global table. +-- +-- @usage +-- local Token = require 'utils.token' +-- local Event = require 'utils.event' +-- +-- Token.register must not be called inside an event handler. +-- local handler = +-- Token.register( +-- function(event) +-- game.print(serpent.block(event)) -- prints the content of the event table to console. +-- end +-- ) +-- +-- The below code would typically be inside another event or a custom command. +-- Event.add_removable(defines.events.on_built_entity, handler) +-- +-- When you no longer need the handler. +-- Event.remove_removable(defines.events.on_built_entity, handler) +-- +-- It's not an error to register the same token multiple times to the same event, however when +-- removing only the first occurrence is removed. +-- +-- ** Event.add_removable_function(event_name, func) ** +-- +-- Only use this function if you can't use Event.add_removable. i.e you are registering the handler at the console. +-- The same restrictions that apply to Event.add_removable also apply to Event.add_removable_function. +-- func cannot be a closure in this case, as there is no safe way to store closures in the global table. +-- A closure is a function that uses a local variable not defined in the function. +-- +-- @usage +-- local Event = require 'utils.event' +-- +-- If you want to remove the handler you will need to keep a reference to it. +-- global.handler = function(event) +-- game.print(serpent.block(event)) -- prints the content of the event table to console. +-- end +-- +-- The below code would typically be used at the command console. +-- Event.add_removable_function(defines.events.on_built_entity, global.handler) +-- +-- When you no longer need the handler. +-- Event.remove_removable_function(defines.events.on_built_entity, global.handler) +-- +-- ** Other Events ** +-- +-- Use Event.on_init(handler) for script.on_init(handler) +-- Use Event.on_load(handler) for script.on_load(handler) +-- +-- Use Event.on_nth_tick(tick, handler) for script.on_nth_tick(tick, handler) +-- Favour this event over Event.add(defines.events.on_tick, handler) +-- There are also Event.add_removable_nth_tick(tick, token) and Event.add_removable_nth_tick_function(tick, func) +-- That work the same as above. +-- +-- ** Custom Scenario Events ** +-- +-- local Event = require 'utils.event' +-- +-- local event_id = script.generate_event_name() +-- +-- Event.add( +-- event_id, +-- function(event) +-- game.print(serpent.block(event)) -- prints the content of the event table to console. +-- end +-- ) +-- +-- The table contains extra information that you want to pass to the handler. +-- script.raise_event(event_id, {extra = 'data'}) + +local EventCore = require 'utils.event_core' +local Global = require 'utils.global' +local Token = require 'utils.token' +local Debug = require 'utils.debug' + +local table_remove = table.remove +local core_add = EventCore.add +local core_on_init = EventCore.on_init +local core_on_load = EventCore.on_load +local core_on_nth_tick = EventCore.on_nth_tick +local stage_load = _STAGE.load +local script_on_event = script.on_event +local script_on_nth_tick = script.on_nth_tick + +local Event = {} + +local handlers_added = false -- set to true after the removeable event handlers have been added. + +local event_handlers = EventCore.get_event_handlers() +local on_nth_tick_event_handlers = EventCore.get_on_nth_tick_event_handlers() + +local token_handlers = {} +local token_nth_tick_handlers = {} +local function_handlers = {} +local function_nth_tick_handlers = {} + +Global.register( + { + token_handlers = token_handlers, + token_nth_tick_handlers = token_nth_tick_handlers, + function_handlers = function_handlers, + function_nth_tick_handlers = function_nth_tick_handlers + }, + function(tbl) + token_handlers = tbl.token_handlers + token_nth_tick_handlers = tbl.token_nth_tick_handlers + function_handlers = tbl.function_handlers + function_nth_tick_handlers = tbl.function_nth_tick_handlers + end +) + +local function remove(tbl, handler) + if tbl == nil then + return + end + + -- the handler we are looking for is more likly to be at the back of the array. + for i = #tbl, 1, -1 do + if tbl[i] == handler then + table_remove(tbl, i) + break + end + end +end + +--- Register a handler for the event_name event. +-- This function must be called in the control stage or in Event.on_init or Event.on_load. +-- See documentation at top of file for details on using events. +-- @param event_name +-- @param handler +function Event.add(event_name, handler) + if _LIFECYCLE == 8 then + error('Calling Event.add after on_init() or on_load() has run is a desync risk.', 2) + end + + core_add(event_name, handler) +end + +--- Register a handler for the script.on_init event. +-- This function must be called in the control stage or in Event.on_init or Event.on_load +-- See documentation at top of file for details on using events. +-- @param handler +function Event.on_init(handler) + if _LIFECYCLE == 8 then + error('Calling Event.on_init after on_init() or on_load() has run is a desync risk.', 2) + end + + core_on_init(handler) +end + +--- Register a handler for the script.on_load event. +-- This function must be called in the control stage or in Event.on_init or Event.on_load +-- See documentation at top of file for details on using events. +-- @param handler +function Event.on_load(handler) + if _LIFECYCLE == 8 then + error('Calling Event.on_load after on_init() or on_load() has run is a desync risk.', 2) + end + + core_on_load(handler) +end + +--- Register a handler for the nth_tick event. +-- This function must be called in the control stage or in Event.on_init or Event.on_load. +-- See documentation at top of file for details on using events. +-- @param tick The handler will be called every nth tick +-- @param handler +function Event.on_nth_tick(tick, handler) + if _LIFECYCLE == 8 then + error('Calling Event.on_nth_tick after on_init() or on_load() has run is a desync risk.', 2) + end + + core_on_nth_tick(tick, handler) +end + +--- Register a token handler that can be safely added and removed at runtime. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param event_name +-- @param token +function Event.add_removable(event_name, token) + if type(token) ~= 'number' then + error('token must be a number', 2) + end + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + + local tokens = token_handlers[event_name] + if not tokens then + token_handlers[event_name] = {token} + else + tokens[#tokens + 1] = token + end + + if handlers_added then + local handler = Token.get(token) + core_add(event_name, handler) + end +end + +--- Removes a token handler for the given event_name. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param event_name +-- @param token +function Event.remove_removable(event_name, token) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + local tokens = token_handlers[event_name] + + if not tokens then + return + end + + local handler = Token.get(token) + local handlers = event_handlers[event_name] + + remove(tokens, token) + remove(handlers, handler) + + if #handlers == 0 then + script_on_event(event_name, nil) + end +end + +--- Register a handler that can be safely added and removed at runtime. +-- The handler must not be a closure, as that is a desync risk. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param event_name +-- @param func +function Event.add_removable_function(event_name, func) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + if type(func) ~= 'function' then + error('func must be a function', 2) + end + + if Debug.is_closure(func) then + error( + 'func cannot be a closure as that is a desync risk. Consider using Event.add_removable(event_name, token) instead.', + 2 + ) + end + + local funcs = function_handlers[event_name] + if not funcs then + function_handlers[event_name] = {func} + else + funcs[#funcs + 1] = func + end + + if handlers_added then + core_add(event_name, func) + end +end + +--- Removes a handler for the given event_name. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param event_name +-- @param func +function Event.remove_removable_function(event_name, func) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + local funcs = function_handlers[event_name] + + if not funcs then + return + end + + local handlers = event_handlers[event_name] + + remove(funcs, func) + remove(handlers, func) + + if #handlers == 0 then + script_on_event(event_name, nil) + end +end + +--- Register a token handler for the nth tick that can be safely added and removed at runtime. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param tick +-- @param token +function Event.add_removable_nth_tick(tick, token) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + if type(token) ~= 'number' then + error('token must be a number', 2) + end + + local tokens = token_nth_tick_handlers[tick] + if not tokens then + token_nth_tick_handlers[tick] = {token} + else + tokens[#tokens + 1] = token + end + + if handlers_added then + local handler = Token.get(token) + core_on_nth_tick(tick, handler) + end +end + +--- Removes a token handler for the nth tick. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param tick +-- @param token +function Event.remove_removable_nth_tick(tick, token) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + local tokens = token_nth_tick_handlers[tick] + + if not tokens then + return + end + + local handler = Token.get(token) + local handlers = on_nth_tick_event_handlers[tick] + + remove(tokens, token) + remove(handlers, handler) + + if #handlers == 0 then + script_on_nth_tick(tick, nil) + end +end + +--- Register a handler for the nth tick that can be safely added and removed at runtime. +-- The handler must not be a closure, as that is a desync risk. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param tick +-- @param func +function Event.add_removable_nth_tick_function(tick, func) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + if type(func) ~= 'function' then + error('func must be a function', 2) + end + + if Debug.is_closure(func) then + error( + 'func cannot be a closure as that is a desync risk. Consider using Event.add_removable_nth_tick(tick, token) instead.', + 2 + ) + end + + local funcs = function_nth_tick_handlers[tick] + if not funcs then + function_nth_tick_handlers[tick] = {func} + else + funcs[#funcs + 1] = func + end + + if handlers_added then + core_on_nth_tick(tick, func) + end +end + +--- Removes a handler for the nth tick. +-- Do NOT call this method during on_load. +-- See documentation at top of file for details on using events. +-- @param tick +-- @param func +function Event.remove_removable_nth_tick_function(tick, func) + if _LIFECYCLE == stage_load then + error('cannot call during on_load', 2) + end + local funcs = function_nth_tick_handlers[tick] + + if not funcs then + return + end + + local handlers = on_nth_tick_event_handlers[tick] + + remove(funcs, func) + remove(handlers, func) + + if #handlers == 0 then + script_on_nth_tick(tick, nil) + end +end + +local function add_handlers() + for event_name, tokens in pairs(token_handlers) do + for i = 1, #tokens do + local handler = Token.get(tokens[i]) + core_add(event_name, handler) + end + end + + for event_name, funcs in pairs(function_handlers) do + for i = 1, #funcs do + local handler = funcs[i] + core_add(event_name, handler) + end + end + + for tick, tokens in pairs(token_nth_tick_handlers) do + for i = 1, #tokens do + local handler = Token.get(tokens[i]) + core_on_nth_tick(tick, handler) + end + end + + for tick, funcs in pairs(function_nth_tick_handlers) do + for i = 1, #funcs do + local handler = funcs[i] + core_on_nth_tick(tick, handler) + end + end + + handlers_added = true +end + +core_on_init(add_handlers) +core_on_load(add_handlers) + +return Event diff --git a/utils/event_core.lua b/utils/event_core.lua new file mode 100644 index 0000000000..6ea0dac083 --- /dev/null +++ b/utils/event_core.lua @@ -0,0 +1,132 @@ +-- This module exists to break the circular dependency between event.lua and global.lua. +-- It is not expected that any user code would require this module instead event.lua should be required. + +local Public = {} + +local init_event_name = -1 +local load_event_name = -2 + +-- map of event_name to handlers[] +local event_handlers = {} +-- map of nth_tick to handlers[] +local on_nth_tick_event_handlers = {} + +local pcall = pcall +local log = log +local script_on_event = script.on_event +local script_on_nth_tick = script.on_nth_tick + +local function call_handlers(handlers, event) + if _DEBUG then + for i = 1, #handlers do + local handler = handlers[i] + handler(event) + end + else + for i = 1, #handlers do + local handler = handlers[i] + local success, error = pcall(handler, event) + if not success then + log(error) + end + end + end +end + +local function on_event(event) + local handlers = event_handlers[event.name] + call_handlers(handlers, event) +end + +local function on_init() + _LIFECYCLE = 5 -- on_init + local handlers = event_handlers[init_event_name] + call_handlers(handlers) + + event_handlers[init_event_name] = nil + event_handlers[load_event_name] = nil + + _LIFECYCLE = 8 -- Runtime +end + +local function on_load() + _LIFECYCLE = 6 -- on_load + local handlers = event_handlers[load_event_name] + call_handlers(handlers) + + event_handlers[init_event_name] = nil + event_handlers[load_event_name] = nil + + _LIFECYCLE = 8 -- Runtime +end + +local function on_nth_tick_event(event) + local handlers = on_nth_tick_event_handlers[event.nth_tick] + call_handlers(handlers, event) +end + +--- Do not use this function, use Event.add instead as it has safety checks. +function Public.add(event_name, handler) + local handlers = event_handlers[event_name] + if not handlers then + event_handlers[event_name] = {handler} + script_on_event(event_name, on_event) + else + table.insert(handlers, handler) + if #handlers == 1 then + script_on_event(event_name, on_event) + end + end +end + +--- Do not use this function, use Event.on_init instead as it has safety checks. +function Public.on_init(handler) + local handlers = event_handlers[init_event_name] + if not handlers then + event_handlers[init_event_name] = {handler} + script.on_init(on_init) + else + table.insert(handlers, handler) + if #handlers == 1 then + script.on_init(on_init) + end + end +end + +--- Do not use this function, use Event.on_load instead as it has safety checks. +function Public.on_load(handler) + local handlers = event_handlers[load_event_name] + if not handlers then + event_handlers[load_event_name] = {handler} + script.on_load(on_load) + else + table.insert(handlers, handler) + if #handlers == 1 then + script.on_load(on_load) + end + end +end + +--- Do not use this function, use Event.on_nth_tick instead as it has safety checks. +function Public.on_nth_tick(tick, handler) + local handlers = on_nth_tick_event_handlers[tick] + if not handlers then + on_nth_tick_event_handlers[tick] = {handler} + script_on_nth_tick(tick, on_nth_tick_event) + else + table.insert(handlers, handler) + if #handlers == 1 then + script_on_nth_tick(tick, on_nth_tick_event) + end + end +end + +function Public.get_event_handlers() + return event_handlers +end + +function Public.get_on_nth_tick_event_handlers() + return on_nth_tick_event_handlers +end + +return Public diff --git a/utils/game.lua b/utils/game.lua new file mode 100644 index 0000000000..7a151c177e --- /dev/null +++ b/utils/game.lua @@ -0,0 +1,120 @@ +local Global = require 'utils.global' +local Color = require 'resources.color_presets' +local pairs = pairs + +local Game = {} + +local bad_name_players = {} +Global.register( + bad_name_players, + function(tbl) + bad_name_players = tbl + end +) + +--[[ + Due to a bug in the Factorio api the following expression isn't guaranteed to be true. + game.players[player.index] == player + get_player_by_index(index) will always return the correct player. + When looking up players by name or iterating through all players use game.players instead. +]] +function Game.get_player_by_index(index) + local p = game.players[index] + + if not p then + return nil + end + if p.index == index then + return p + end + + p = bad_name_players[index] + if p then + if p.valid then + return p + else + return nil + end + end + + for k, v in pairs(game.players) do + if k == index then + bad_name_players[index] = v + return v + end + end +end + +--- Returns a valid LuaPlayer if given a number, string, or LuaPlayer. Returns nil otherwise. +-- obj +function Game.get_player_from_any(obj) + local o_type = type(obj) + local p + if type == 'number' then + p = Game.get_player_by_index(obj) + elseif o_type == 'string' then + p = game.players[obj] + elseif o_type == 'table' and obj.valid and obj.is_player() then + return obj + end + + if p and p.valid then + return p + end +end + +--- Prints to player or console. +-- @param str table if locale is used +-- @param color
defaults to white +function Game.player_print(str, color) + color = color or Color.white + if game.player then + game.player.print(str, color) + else + print(str) + end +end + +--[[ + @param Position String to display at + @param text String to display + @param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white. + @param surface LuaSurface + + @return the created entity +]] +function Game.print_floating_text(surface, position, text, color) + color = color or Color.white + + return surface.create_entity { + name = 'tutorial-flying-text', + color = color, + text = text, + position = position + } +end + +--[[ + Creates a floating text entity at the player location with the specified color in {r, g, b} format. + Example: "+10 iron" or "-10 coins" + + @param text String to display + @param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white. + + @return the created entity +]] +function Game.print_player_floating_text_position(player_index, text, color, x_offset, y_offset) + local player = Game.get_player_by_index(player_index) + if not player or not player.valid then + return + end + + local position = player.position + return Game.print_floating_text(player.surface, {x = position.x + x_offset, y = position.y + y_offset}, text, color) +end + +function Game.print_player_floating_text(player_index, text, color) + Game.print_player_floating_text_position(player_index, text, color, 0, -1.5) +end + +return Game diff --git a/utils/global.lua b/utils/global.lua new file mode 100644 index 0000000000..4d23bd431f --- /dev/null +++ b/utils/global.lua @@ -0,0 +1,79 @@ +local Event = require 'utils.event_core' +local Token = require 'utils.token' + +local Global = {} + +function Global.register(tbl, callback) + if _LIFECYCLE ~= _STAGE.control then + error('can only be called during the control stage', 2) + end + local token = Token.register_global(tbl) + + Event.on_load( + function() + callback(Token.get_global(token)) + end + ) +end + +function Global.register_init(tbl, init_handler, callback) + if _LIFECYCLE ~= _STAGE.control then + error('can only be called during the control stage', 2) + end + local token = Token.register_global(tbl) + + Event.on_init( + function() + init_handler(tbl) + callback(tbl) + end + ) + + Event.on_load( + function() + callback(Token.get_global(token)) + end + ) +end + +if _DEBUG then + local concat = table.concat + + local names = {} + Global.names = names + + function Global.register(tbl, callback) + local filepath = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) + local token = Token.register_global(tbl) + + names[token] = concat {token, ' - ', filepath} + + Event.on_load( + function() + callback(Token.get_global(token)) + end + ) + end + + function Global.register_init(tbl, init_handler, callback) + local filepath = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) + local token = Token.register_global(tbl) + + names[token] = concat {token, ' - ', filepath} + + Event.on_init( + function() + init_handler(tbl) + callback(tbl) + end + ) + + Event.on_load( + function() + callback(Token.get_global(token)) + end + ) + end +end + +return Global diff --git a/utils/gui.lua b/utils/gui.lua new file mode 100644 index 0000000000..7ff901aa36 --- /dev/null +++ b/utils/gui.lua @@ -0,0 +1,287 @@ +local Token = require 'utils.token' +local Event = require 'utils.event' +local Game = require 'utils.game' +local Global = require 'utils.global' + +local Gui = {} + +local data = {} + +Global.register( + data, + function(tbl) + data = tbl + end +) + +local top_elements = {} +local on_visible_handlers = {} +local on_pre_hidden_handlers = {} + +function Gui.uid_name() + return tostring(Token.uid()) +end + +-- Associates data with the LuaGuiElement. If data is nil then removes the data +function Gui.set_data(element, value) + data[element.player_index * 0x100000000 + element.index] = value +end + +-- Gets the Associated data with this LuaGuiElement if any. +function Gui.get_data(element) + return data[element.player_index * 0x100000000 + element.index] +end + +-- Removes data associated with LuaGuiElement and its children recursively. +function Gui.remove_data_recursively(element) + Gui.set_data(element, nil) + + local children = element.children + + if not children then + return + end + + for _, child in ipairs(children) do + if child.valid then + Gui.remove_data_recursively(child) + end + end +end + +function Gui.remove_children_data(element) + local children = element.children + + if not children then + return + end + + for _, child in ipairs(children) do + if child.valid then + Gui.set_data(child, nil) + Gui.remove_children_data(child) + end + end +end + +function Gui.destroy(element) + Gui.remove_data_recursively(element) + element.destroy() +end + +function Gui.clear(element) + Gui.remove_children_data(element) + element.clear() +end + +local function handler_factory(event_id) + local handlers + + local function on_event(event) + local element = event.element + if not element or not element.valid then + return + end + + local handler = handlers[element.name] + if not handler then + return + end + + local player = Game.get_player_by_index(event.player_index) + if not player or not player.valid then + return + end + event.player = player + + handler(event) + end + + return function(element_name, handler) + if not handlers then + handlers = {} + Event.add(event_id, on_event) + end + + handlers[element_name] = handler + end +end + +local function custom_handler_factory(handlers) + return function(element_name, handler) + handlers[element_name] = handler + end +end + +local function custom_raise(handlers, element, player) + local handler = handlers[element.name] + if not handler then + return + end + + handler({element = element, player = player}) +end + +-- Register a handler for the on_gui_checked_state_changed event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_checked_state_changed = handler_factory(defines.events.on_gui_checked_state_changed) + +-- Register a handler for the on_gui_click event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_click = handler_factory(defines.events.on_gui_click) + +-- Register a handler for the on_gui_closed event for a custom LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_custom_close = handler_factory(defines.events.on_gui_closed) + +-- Register a handler for the on_gui_elem_changed event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_elem_changed = handler_factory(defines.events.on_gui_elem_changed) + +-- Register a handler for the on_gui_selection_state_changed event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_selection_state_changed = handler_factory(defines.events.on_gui_selection_state_changed) + +-- Register a handler for the on_gui_text_changed event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_text_changed = handler_factory(defines.events.on_gui_text_changed) + +-- Register a handler for the on_gui_value_changed event for LuaGuiElements with element_name. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_value_changed = handler_factory(defines.events.on_gui_value_changed) + +-- Register a handler for when the player shows the top LuaGuiElements with element_name. +-- Assuming the element_name has been added with Gui.allow_player_to_toggle_top_element_visibility. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_player_show_top = custom_handler_factory(on_visible_handlers) + +-- Register a handler for when the player hides the top LuaGuiElements with element_name. +-- Assuming the element_name has been added with Gui.allow_player_to_toggle_top_element_visibility. +-- Can only have one handler per element name. +-- Guarantees that the element and the player are valid when calling the handler. +-- Adds a player field to the event table. +Gui.on_pre_player_hide_top = custom_handler_factory(on_pre_hidden_handlers) + +--- Allows the player to show / hide this element. +-- The element must be part in gui.top. +-- This function must be called in the control stage, i.e not inside an event. +-- @param element_name This name must be globally unique. +function Gui.allow_player_to_toggle_top_element_visibility(element_name) + if _LIFECYCLE ~= _STAGE.control then + error('can only be called during the control stage', 2) + end + top_elements[#top_elements + 1] = element_name +end + +local toggle_button_name = Gui.uid_name() + +Event.add( + defines.events.on_player_created, + function(event) + local player = Game.get_player_by_index(event.player_index) + + if not player or not player.valid then + return + end + + local b = + player.gui.top.add { + type = 'button', + name = toggle_button_name, + caption = '<', + tooltip = 'Shows / hides the Redmew Gui buttons.' + } + local style = b.style + style.width = 18 + style.height = 38 + style.left_padding = 0 + style.top_padding = 0 + style.right_padding = 0 + style.bottom_padding = 0 + style.font = 'default-small-bold' + end +) + +Gui.on_click( + toggle_button_name, + function(event) + local button = event.element + local player = event.player + local top = player.gui.top + + if button.caption == '<' then + for i = 1, #top_elements do + local name = top_elements[i] + local ele = top[name] + if ele and ele.valid then + local style = ele.style + + -- if visible is not set it has the value of nil. + -- Hence nil is treated as is visible. + local v = style.visible + if v or v == nil then + custom_raise(on_pre_hidden_handlers, ele, player) + style.visible = false + end + end + end + + button.caption = '>' + button.style.height = 24 + else + for i = 1, #top_elements do + local name = top_elements[i] + local ele = top[name] + if ele and ele.valid then + local style = ele.style + + if not style.visible then + style.visible = true + custom_raise(on_visible_handlers, ele, player) + end + end + end + + button.caption = '<' + button.style.height = 38 + end + end +) + +if _DEBUG then + local concat = table.concat + + local names = {} + Gui.names = names + + function Gui.uid_name() + local info = debug.getinfo(2, 'Sl') + local filepath = info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) + local line = info.currentline + + local token = tostring(Token.uid()) + + local name = concat {token, ' - ', filepath, ':line:', line} + names[token] = name + + return token + end +end + +return Gui diff --git a/utils/inspect.lua b/utils/inspect.lua new file mode 100644 index 0000000000..c13a8cd4be --- /dev/null +++ b/utils/inspect.lua @@ -0,0 +1,342 @@ +local inspect ={ + _VERSION = 'inspect.lua 3.1.0', + _URL = 'http://github.com/kikito/inspect.lua', + _DESCRIPTION = 'human-readable representations of tables', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local tostring = tostring + +inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) +inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) + +-- Apostrophizes the string if it has quotes, but not aphostrophes +-- Otherwise, it returns a regular quoted string +local function smartQuote(str) + if str:match('"') and not str:match("'") then + return "'" .. str .. "'" + end + return '"' .. str:gsub('"', '\\"') .. '"' +end + +-- \a => '\\a', \0 => '\\0', 31 => '\31' +local shortControlCharEscapes = { + ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", + ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" +} +local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 +for i=0, 31 do + local ch = string.char(i) + if not shortControlCharEscapes[ch] then + shortControlCharEscapes[ch] = "\\"..i + longControlCharEscapes[ch] = string.format("\\%03d", i) + end +end + +local function escape(str) + return (str:gsub("\\", "\\\\") + :gsub("(%c)%f[0-9]", longControlCharEscapes) + :gsub("%c", shortControlCharEscapes)) +end + +local function isIdentifier(str) + return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) +end + +local function isSequenceKey(k, sequenceLength) + return type(k) == 'number' + and 1 <= k + and k <= sequenceLength + and math.floor(k) == k +end + +local defaultTypeOrders = { + ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, + ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 +} + +local function sortKeys(a, b) + local ta, tb = type(a), type(b) + + -- strings and numbers are sorted numerically/alphabetically + if ta == tb and (ta == 'string' or ta == 'number') then return a < b end + + local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] + -- Two default types are compared according to the defaultTypeOrders table + if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] + elseif dta then return true -- default types before custom ones + elseif dtb then return false -- custom types after default ones + end + + -- custom types are sorted out alphabetically + return ta < tb +end + +-- For implementation reasons, the behavior of rawlen & # is "undefined" when +-- tables aren't pure sequences. So we implement our own # operator. +local function getSequenceLength(t) + local len = 1 + local v = rawget(t,len) + while v ~= nil do + len = len + 1 + v = rawget(t,len) + end + return len - 1 +end + +local function getNonSequentialKeys(t) + local keys = {} + local sequenceLength = getSequenceLength(t) + for k,_ in pairs(t) do + if not isSequenceKey(k, sequenceLength) then table.insert(keys, k) end + end + table.sort(keys, sortKeys) + return keys, sequenceLength +end + +local function getToStringResultSafely(t, mt) + local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') + local str, ok + if type(__tostring) == 'function' then + ok, str = pcall(__tostring, t) + str = ok and str or 'error: ' .. tostring(str) + end + if type(str) == 'string' and #str > 0 then return str end +end + +local function countTableAppearances(t, tableAppearances) + tableAppearances = tableAppearances or {} + + if type(t) == 'table' then + if not tableAppearances[t] then + tableAppearances[t] = 1 + for k,v in pairs(t) do + countTableAppearances(k, tableAppearances) + countTableAppearances(v, tableAppearances) + end + countTableAppearances(getmetatable(t), tableAppearances) + else + tableAppearances[t] = tableAppearances[t] + 1 + end + end + + return tableAppearances +end + +local copySequence = function(s) + local copy, len = {}, #s + for i=1, len do copy[i] = s[i] end + return copy, len +end + +local function makePath(path, ...) + local keys = {...} + local newPath, len = copySequence(path) + for i=1, #keys do + newPath[len + i] = keys[i] + end + return newPath +end + +local function processRecursive(process, item, path, visited) + + if item == nil then return nil end + if visited[item] then return visited[item] end + + local processed = process(item, path) + if type(processed) == 'table' then + local processedCopy = {} + visited[item] = processedCopy + local processedKey + + for k,v in pairs(processed) do + processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) + if processedKey ~= nil then + processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) + end + end + + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + setmetatable(processedCopy, mt) + processed = processedCopy + end + return processed +end + + + +------------------------------------------------------------------- + +local Inspector = {} +local Inspector_mt = {__index = Inspector} + +function Inspector:puts(...) + local args = {...} + local buffer = self.buffer + local len = #buffer + for i=1, #args do + len = len + 1 + buffer[len] = args[i] + end +end + +function Inspector:down(f) + self.level = self.level + 1 + f() + self.level = self.level - 1 +end + +function Inspector:tabify() + self:puts(self.newline, string.rep(self.indent, self.level)) +end + +function Inspector:alreadyVisited(v) + return self.ids[v] ~= nil +end + +function Inspector:getId(v) + local id = self.ids[v] + if not id then + local tv = type(v) + id = (self.maxIds[tv] or 0) + 1 + self.maxIds[tv] = id + self.ids[v] = id + end + return tostring(id) +end + +function Inspector:putKey(k) + if isIdentifier(k) then return self:puts(k) end + self:puts("[") + self:putValue(k) + self:puts("]") +end + +function Inspector:putTable(t) + if t == inspect.KEY or t == inspect.METATABLE then + self:puts(tostring(t)) + elseif self:alreadyVisited(t) then + self:puts('
') + elseif self.level >= self.depth then + self:puts('{...}') + else + if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end + + local nonSequentialKeys, sequenceLength = getNonSequentialKeys(t) + local mt = getmetatable(t) + local toStringResult = getToStringResultSafely(t, mt) + + self:puts('{') + self:down(function() + if toStringResult then + self:puts(' -- ', escape(toStringResult)) + if sequenceLength >= 1 then self:tabify() end + end + + local count = 0 + for i=1, sequenceLength do + if count > 0 then self:puts(',') end + self:puts(' ') + self:putValue(t[i]) + count = count + 1 + end + + for _,k in ipairs(nonSequentialKeys) do + if count > 0 then self:puts(',') end + self:tabify() + self:putKey(k) + self:puts(' = ') + self:putValue(t[k]) + count = count + 1 + end + + if mt then + if count > 0 then self:puts(',') end + self:tabify() + self:puts(' = ') + self:putValue(mt) + end + end) + + if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing } + self:tabify() + elseif sequenceLength > 0 then -- array tables have one extra space before closing } + self:puts(' ') + end + + self:puts('}') + end +end + +function Inspector:putValue(v) + local tv = type(v) + + if tv == 'string' then + self:puts(smartQuote(escape(v))) + elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or + tv == 'cdata' or tv == 'ctype' then + self:puts(tostring(v)) + elseif tv == 'table' then + self:putTable(v) + else + self:puts('<',tv,' ',self:getId(v),'>') + end +end + +------------------------------------------------------------------- + +function inspect.inspect(root, options) + options = options or {} + + local depth = options.depth or math.huge + local newline = options.newline or '\n' + local indent = options.indent or ' ' + local process = options.process + + if process then + root = processRecursive(process, root, {}, {}) + end + + local inspector = setmetatable({ + depth = depth, + level = 0, + buffer = {}, + ids = {}, + maxIds = {}, + newline = newline, + indent = indent, + tableAppearances = countTableAppearances(root) + }, Inspector_mt) + + inspector:putValue(root) + + return table.concat(inspector.buffer) +end + +setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) + +return inspect + diff --git a/utils/math.lua b/utils/math.lua new file mode 100644 index 0000000000..3a4e36526a --- /dev/null +++ b/utils/math.lua @@ -0,0 +1,54 @@ +--luacheck:ignore global math +local _sin = math.sin +local _cos = math.cos + +math.sqrt2 = math.sqrt(2) +math.inv_sqrt2 = 1 / math.sqrt2 +math.tau = 2 * math.pi + +math.sin = function(x) + return math.floor(_sin(x) * 10000000 + 0.5) / 10000000 +end + +math.cos = function(x) + return math.floor(_cos(x) * 10000000 + 0.5) / 10000000 +end + +-- rounds number (num) to certain number of decimal places (idp) +math.round = function(num, idp) + local mult = 10 ^ (idp or 0) + return math.floor(num * mult + 0.5) / mult +end + +math.clamp = function(num, min, max) + if num < min then + return min + elseif num > max then + return max + else + return num + end +end + +--- Takes two points and calculates the slope of a line +-- @param x1, y1 numbers - cordinates of a point on a line +-- @param x2, y2 numbers - cordinates of a point on a line +-- @return number - the slope of the line +math.calculate_slope = function(x1, y1, x2, y2) + return math.abs((y2 - y1) / (x2 - x1)) +end + +--- Calculates the y-intercept of a line +-- @param x, y numbers - coordinates of point on line +-- @param slope number - the slope of a line +-- @return number - the y-intercept of a line +math.calculate_y_intercept = function(x, y, slope) + return y - (slope * x) +end + +local deg_to_rad = math.tau / 360 +math.degrees = function(angle) + return angle * deg_to_rad +end + +return math diff --git a/utils/player_rewards.lua b/utils/player_rewards.lua new file mode 100644 index 0000000000..69da941ccf --- /dev/null +++ b/utils/player_rewards.lua @@ -0,0 +1,154 @@ +local Global = require 'utils.global' +local Game = require 'utils.game' +local PlayerStats = require 'features.player_stats' +local Command = require 'utils.command' +local Ranks = require 'resources.ranks' + +local format = string.format +local abs = math.abs +local concat = table.concat + +local Public = {} +local reward_token = {global.config.player_rewards.token} or {global.config.market.currency} or {'coin'} + +Global.register( + { + reward_token = reward_token + }, + function(tbl) + reward_token = tbl.reward_token + end +) + +--- Returns the single or plural form of the token name +local function get_token_plural(quantity) + if quantity and quantity > 1 then + return concat({reward_token[1], 's'}) + else + return reward_token[1] + end +end + +--- Set the item to use for rewards +-- @param reward string - item name to use as reward +-- @return boolean true - indicating success +Public.set_reward = function(reward) + if global.config.player_rewards.enabled == false then + return false + end + + reward_token[1] = reward + return true +end + +--- Returns the name of the reward item +Public.get_reward = function() + return reward_token[1] +end + +--- Gives reward tokens to the player +-- @param player +-- @param amount of reward tokens +-- @param message an optional message to send to the affected player +-- @return indicating how many were inserted or if operation failed +Public.give_reward = function(player, amount, message) + if global.config.player_rewards.enabled == false then + return 0 + end + + local player_index + if type(player) == 'number' then + player_index = player + player = Game.get_player_by_index(player) + else + player_index = player.index + end + local reward = {name = reward_token[1], count = amount} + if not player.can_insert(reward) then + return 0 + end + if message then + player.print(message) + end + local coin_difference = player.insert(reward) + if reward_token[1] == 'coin' then + PlayerStats.change_coin_earned(player_index, coin_difference) + end + return coin_difference +end + +--- Removes reward tokens from the player +-- @param player +-- @param amount of reward tokens +-- @param message an optional message to send to the affected player +-- @return indicating how many were removed or if operation failed +Public.remove_reward = function(player, amount, message) + if global.config.player_rewards.enabled == false then + return 0 + end + + local player_index + if type(player) == 'number' then + player_index = player + player = Game.get_player_by_index(player) + else + player_index = player.index + end + local unreward = {name = reward_token[1], count = amount} + if message then + player.print(message) + end + local coin_difference = player.remove_item(unreward) + if reward_token[1] == 'coin' then + PlayerStats.change_coin_earned(player_index, -coin_difference) + end + return coin_difference +end + +Command.add( + 'reward', + { + description = 'Gives a reward to a target player (removes if quantity is negative)', + arguments = {'target', 'quantity', 'reason'}, + default_values = {reason = false}, + required_rank = Ranks.admin, + capture_excess_arguments = true, + allowed_by_server = true, + allowed_by_player = true + }, + function(args, player) + local player_name = 'server' + if player then + player_name = player.name + end + + local target_name = args.target + local target = game.players[target_name] + if not target then + player.print('Target not found.') + return + end + + local quantity = tonumber(args.quantity) + if quantity > 0 then + Public.give_reward(target, quantity) + local string = format('%s has rewarded %s with %s %s', player_name, target_name, quantity, get_token_plural(quantity)) + if args.reason then + string = format('%s for %s', string, args.reason) + end + game.print(string) + elseif quantity < 0 then + quantity = abs(quantity) + Public.remove_reward(target, quantity) + local string = format('%s has punished %s by taking %s %s', player_name, target_name, quantity, get_token_plural(quantity)) + if args.reason then + string = format('%s for %s', string, args.reason) + end + game.print(string) + else + Game.player_print(" A reward of 0 is neither a reward nor a punishment, it's just dumb. Try harder.") + end + end +) + +return Public diff --git a/utils/print_override.lua b/utils/print_override.lua new file mode 100644 index 0000000000..848c91b2c2 --- /dev/null +++ b/utils/print_override.lua @@ -0,0 +1,13 @@ +local Public = {} + +local locale_string = {'', '[PRINT] ', nil} +local raw_print = print + +function print(str) + locale_string[3] = str + log(locale_string) +end + +Public.raw_print = raw_print + +return Public diff --git a/utils/priority_queue.lua b/utils/priority_queue.lua new file mode 100644 index 0000000000..bccd23588f --- /dev/null +++ b/utils/priority_queue.lua @@ -0,0 +1,74 @@ +local PriorityQueue = {} + +function PriorityQueue.new() + return {} +end + +local function default_comp(a, b) + return a < b +end + +local function HeapifyFromEndToStart(queue, comp) + comp = comp or default_comp + local pos = #queue + while pos > 1 do + local parent = bit32.rshift(pos, 1) -- integer division by 2 + if comp(queue[pos], queue[parent]) then + queue[pos], queue[parent] = queue[parent], queue[pos] + pos = parent + else + break + end + end +end + +local function HeapifyFromStartToEnd(queue, comp) + comp = comp or default_comp + local parent = 1 + local smallest = 1 + while true do + local child = parent * 2 + if child > #queue then + break + end + if comp(queue[child], queue[parent]) then + smallest = child + end + child = child + 1 + if child <= #queue and comp(queue[child], queue[smallest]) then + smallest = child + end + + if parent ~= smallest then + queue[parent], queue[smallest] = queue[smallest], queue[parent] + parent = smallest + else + break + end + end +end + +function PriorityQueue.size(queue) + return #queue +end + +function PriorityQueue.push(queue, element, comp) + table.insert(queue, element) + HeapifyFromEndToStart(queue, comp) +end + +function PriorityQueue.pop(queue, comp) + local element = queue[1] + + queue[1] = queue[#queue] + queue[#queue] = nil + HeapifyFromStartToEnd(queue, comp) + + return element +end + +function PriorityQueue.peek(queue) + return queue[1] +end + +return PriorityQueue diff --git a/utils/queue.lua b/utils/queue.lua new file mode 100644 index 0000000000..1907c30bf5 --- /dev/null +++ b/utils/queue.lua @@ -0,0 +1,34 @@ +local Queue = {} + +function Queue.new() + local queue = {_head = 0, _tail = 0} + return queue +end + +function Queue.size(queue) + return queue._tail - queue._head +end + +function Queue.push(queue, element) + local index = queue._head + queue[index] = element + queue._head = index - 1 +end + +function Queue.peek(queue) + return queue[queue._tail] +end + +function Queue.pop(queue) + local index = queue._tail + + local element = queue[index] + queue[index] = nil + + if element then + queue._tail = index - 1 + end + return element +end + +return Queue diff --git a/utils/recipe_locker.lua b/utils/recipe_locker.lua new file mode 100644 index 0000000000..ce754b5b69 --- /dev/null +++ b/utils/recipe_locker.lua @@ -0,0 +1,58 @@ +-- A module to prevent recipes from being unlocked by research. Accessed via the public functions. +local Event = require 'utils.event' +local Global = require 'utils.global' + +local Public = {} + +local recipes = {} + +Global.register( + { + recipes = recipes + }, + function(tbl) + recipes = tbl.recipes + end +) + +Event.add( + defines.events.on_research_finished, + function(event) + local p_force = game.forces.player + local r = event.research + for _, effect in pairs(r.effects) do + local recipe = effect.recipe + if recipe and recipes[recipe] then + p_force.recipes[recipe].enabled = false + end + end + end +) + +Event.on_init( + function() + for recipe in pairs(recipes) do + game.forces.player.recipes[recipe].enabled = false + end + end +) + +--- Locks recipes, preventing them from being enabled by research. +-- Does not check if they should be enabled/disabled by existing research. +-- @param tbl
an array of recipe strings +function Public.lock_recipes(tbl) + for i = 1, #tbl do + recipes[tbl[i]] = true + end +end + +--- Unlocks recipes, allowing them to be enabled by research. +-- Does not check if they should be enabled/disabled by existing research. +-- @param tbl
an array of recipe strings +function Public.unlock_recipes(tbl) + for i = 1, #tbl do + recipes[tbl[i]] = nil + end +end + +return Public diff --git a/utils/redmew_settings.lua b/utils/redmew_settings.lua new file mode 100644 index 0000000000..9ddc7971fc --- /dev/null +++ b/utils/redmew_settings.lua @@ -0,0 +1,178 @@ +local Global = require 'utils.global' +local type = type +local error = error +local tonumber = tonumber +local tostring = tostring +local pairs = pairs +local format = string.format + +--- Contains a set of callables that will attempt to sanitize and transform the input +local settings_type = { + fraction = function (input) + input = tonumber(input) + + if input == nil then + return false, 'fraction setting type requires the input to be a valid number between 0 and 1.' + end + + if input < 0 then + input = 0 + end + + if input > 1 then + input = 1 + end + + return true, input + end, + string = function (input) + if input == nil then + return true, '' + end + + local input_type = type(input) + if input_type == 'string' then + return true, input + end + + if input_type == 'number' or input_type == 'boolean' then + return true, tostring(input) + end + + return false, 'string setting type requires the input to be either a valid string or something that can be converted to a string.' + end, + boolean = function (input) + local input_type = type(input) + + if input_type == 'boolean' then + return true, input + end + + if input_type == 'string' then + if input == '0' or input == '' or input == 'false' or input == 'no' then + return true, false + end + if input == '1' or input == 'true' or input == 'yes' then + return true, true + end + + return true, tonumber(input) ~= nil + end + + if input_type == 'number' then + return true, input ~= 0 + end + + return false, 'boolean setting type requires the input to be either a boolean, number or string that can be transformed to a boolean.' + end, +} + +local settings = {} +local memory = {} + +Global.register(memory, function (tbl) memory = tbl end) + +local Public = {} + +Public.types = {fraction = 'fraction', string = 'string', boolean = 'boolean'} + +---Register a specific setting with a sensitization setting type. +--- +--- Available setting types: +--- - fraction (number between 0 and 1) in either number or string form +--- - string a string or anything that can be cast to a string +--- - boolean, 1, 0, yes, no, true, false or an empty string for false +--- +--- This function must be called in the control stage, i.e. not inside an event. +--- +---@param name string +---@param setting_type string +---@param default mixed +function Public.register(name, setting_type, default) + if _LIFECYCLE ~= _STAGE.control then + error(format('You can only register setting names in the control stage, i.e. not inside events. Tried setting "%s" with type "%s".', name, setting_type), 2) + end + + if settings[name] then + error(format('Trying to register setting for "%s" while it has already been registered.', name), 2) + end + + local callback = settings_type[setting_type] + if not callback then + error(format('Trying to register setting for "%s" with type "%s" while this type does not exist.', name, setting_type), 2) + end + + local setting = { + default = default, + callback = callback, + } + + settings[name] = setting + + return setting +end + +---Sets a setting to a specific value for a player. +--- +---In order to get a setting value, it has to be registered via the "register" function. +--- +---@param player_index number +---@param name string +---@param value mixed +function Public.set(player_index, name, value) + local setting = settings[name] + if not setting then + return error(format('Setting "%s" does not exist.', name), 2) + end + + local success, sanitized_value = setting.callback(value) + + if not success then + error(format('Setting "%s" failed: %s', name, sanitized_value), 2) + end + + local player_settings = memory[player_index] + if not player_settings then + player_settings = {} + memory[player_index] = player_settings + end + + player_settings[name] = sanitized_value + + return sanitized_value +end + +---Returns the value of a setting for this player. +--- +---In order to set a setting value, it has to be registered via the "register" function. +--- +---@param player_index number +---@param name string +function Public.get(player_index, name) + local setting = settings[name] + if not setting then + return error(format('Setting "%s" does not exist.', name), 2) + end + + local player_settings = memory[player_index] + if not player_settings then + return setting.default + end + + local player_setting = player_settings[name] + return player_setting ~= nil and player_setting or setting.default +end + +---Returns a table of all settings for a given player in a key => value setup +---@param player_index number +function Public.all(player_index) + local player_settings = memory[player_index] or {} + local output = {} + for name, data in pairs(settings) do + output[name] = player_settings[name] or data.default + end + + return output +end + +return Public diff --git a/utils/state_machine.lua b/utils/state_machine.lua new file mode 100644 index 0000000000..a3295cafad --- /dev/null +++ b/utils/state_machine.lua @@ -0,0 +1,119 @@ +--- This module provides a classical mealy/moore state machine. +-- Each machine in constructed by calling new() +-- States and Transitions are lazily added to the machine as transition handlers and state tick handlers are registered. +-- However the state machine must be fully defined after init is done. Dynamic machine changes are currently unsupported +-- An example usage can be found here: map_gen\combined\tetris\control.lua + +local Module = {} + +local Debug = require 'utils.debug' + +local in_state_callbacks = {} +local transaction_callbacks = {} +local max_stack_depth = 20 +local machine_count = 0 +local control_stage = _STAGE.control + +--- Transitions the supplied machine into a given state and executes all transaction_callbacks +-- @param self StateMachine +-- @param new_state number/string The new state to transition to +function Module.transition(self, new_state) + Debug.print(string.format('Transitioning from state %d to state %d.', self.state, new_state)) + local old_state = self.state + + local stack_depth = self.stack_depth + self.stack_depth = stack_depth + 1 + if stack_depth > max_stack_depth then + if _DEBUG then + error('[WARNING] Stack overflow at:' .. debug.traceback()) + else + log('[WARNING] Stack overflow at:' .. debug.traceback()) + end + end + + local exit_callbacks = transaction_callbacks[self.id][old_state] + if exit_callbacks then + local entry_callbacks = exit_callbacks[new_state] + if entry_callbacks then + for i = 1, #entry_callbacks do + local callback = entry_callbacks[i] + if callback then + callback() + end + end + end + end + self.state = new_state +end + +--- Is this machine in this state? +-- @param self StateMachine +-- @param state number/string +-- @return boolean +function Module.in_state(self, state) + return self.state == state +end + +--- Invoke a machine tick. Will execute all in_state_callbacks of the given machine +-- @param self StateMachine the machine, whose handlers will be invoked +function Module.machine_tick(self) + local callbacks = in_state_callbacks[self.id][self.state] + if callbacks then + for i=1, #callbacks do + local callback = callbacks[i] + if callback then + callback() + end + end + end + self.stack_depth = 0 +end + +--- Register a handler that will be invoked by StateMachine.machine_tick +-- You may register multiple handlers for the same transition +-- NOTICE: This function will invoke an error if called after init. Dynamic machine changes are currently unsupported +-- @param self StateMachine the machine +-- @param state number/string The state, that the machine will be in, when callback is invoked +-- @param callback function +function Module.register_state_tick_callback(self, state, callback) + if _LIFECYCLE ~= control_stage then + error('Calling StateMachine.register_state_tick_callback after the control stage is unsupported due to desyncs.', 2) + end + in_state_callbacks[self.id][state] = in_state_callbacks[self.id][state] or {} + table.insert(in_state_callbacks[self.id][state], callback) +end + +--- Register a handler that will be invoked by StateMachine.transition +-- You may register multiple handlers for the same transition +-- NOTICE: This function will invoke an error if called after init. Dynamic machine changes are currently unsupported +-- @param self StateMachine the machine +-- @param state number/string exiting state +-- @param state number/string entering state +-- @param callback function +function Module.register_transition_callback(self, old, new, callback) + if _LIFECYCLE ~= control_stage then + error('Calling StateMachine.register_transition_callback after the control stage is unsupported due to desyncs.', 2) + end + transaction_callbacks[self.id][old] = transaction_callbacks[self.id][old] or {} + transaction_callbacks[self.id][old][new] = transaction_callbacks[self.id][old][new] or {} + table.insert(transaction_callbacks[self.id][old][new], callback) +end + +--- Constructs a new state machine +-- @param init_state number/string The starting state of the machine +-- @return StateMachine The constructed state machine object +function Module.new(init_state) + if _LIFECYCLE ~= control_stage then + error('Calling StateMachine.new after the control stage is unsupported due to desyncs.', 2) + end + machine_count = machine_count + 1 + in_state_callbacks[machine_count] = {} + transaction_callbacks[machine_count] = {} + return { + state = init_state, + stack_depth = 0, + id = machine_count, + } +end + +return Module diff --git a/utils/table.lua b/utils/table.lua new file mode 100644 index 0000000000..b828f8a6be --- /dev/null +++ b/utils/table.lua @@ -0,0 +1,265 @@ +--luacheck:ignore global table +local random = math.random +local floor = math.floor +local remove = table.remove +local tonumber = tonumber +local pairs = pairs +local table_size = table_size + +--- Searches a table to remove a specific element without an index +-- @param t
to search +-- @param table element to search for +function table.remove_element(t, element) + for k, v in pairs(t) do + if v == element then + remove(t, k) + break + end + end +end + +--- Removes an item from an array in O(1) time. +-- The catch is that fast_remove doesn't guarantee to maintain the order of items in the array. +-- @param tbl
arrayed table +-- @param index Must be >= 0. The case where index > #tbl is handled. +function table.fast_remove(tbl, index) + local count = #tbl + if index > count then + return + elseif index < count then + tbl[index] = tbl[count] + end + + tbl[count] = nil +end + +--- Adds the contents of table t2 to table t1 +-- @param t1
to insert into +-- @param t2
to insert from +function table.add_all(t1, t2) + for k, v in pairs(t2) do + if tonumber(k) then + t1[#t1 + 1] = v + else + t1[k] = v + end + end +end + +--- Checks if a table contains an element +-- @param t
+-- @param e table element +-- @returns the index of the element or nil +function table.index_of(t, e) + for k, v in pairs(t) do + if v == e then + return k + end + end + return nil +end + +--- Checks if the arrayed portion of a table contains an element +-- @param t
+-- @param e table element +-- @returns the index of the element or nil +function table.index_of_in_array(t, e) + for i = 1, #t do + if t[i] == e then + return i + end + end + return nil +end + +local index_of = table.index_of +--- Checks if a table contains an element +-- @param t
+-- @param e table element +-- @returns indicating success +function table.contains(t, e) + return index_of(t, e) and true or false +end + +local index_of_in_array = table.index_of_in_array +--- Checks if the arrayed portion of a table contains an element +-- @param t
+-- @param e table element +-- @returns indicating success +function table.array_contains(t, e) + return index_of_in_array(t, e) and true or false +end + +--- Adds an element into a specific index position while shuffling the rest down +-- @param t
to add into +-- @param index the position in the table to add to +-- @param element to add to the table +function table.set(t, index, element) + local i = 1 + for k in pairs(t) do + if i == index then + t[k] = element + return nil + end + i = i + 1 + end + error('Index out of bounds', 2) +end + +--- Chooses a random entry from a table +-- because this uses math.random, it cannot be used outside of events +-- @param t
+-- @param key to indicate whether to return the key or value +-- @return a random element of table t +function table.get_random_dictionary_entry(t, key) + local target_index = random(1, table_size(t)) + local count = 1 + for k, v in pairs(t) do + if target_index == count then + if key then + return k + else + return v + end + end + count = count + 1 + end +end + +--- Chooses a random entry from a weighted table +-- because this uses math.random, it cannot be used outside of events +-- @param weight_table
of tables with items and their weights +-- @param item_index of the index of items, defaults to 1 +-- @param weight_index of the index of the weights, defaults to 2 +-- @return table element +-- @see features.chat_triggers::hodor +function table.get_random_weighted(weighted_table, item_index, weight_index) + local total_weight = 0 + item_index = item_index or 1 + weight_index = weight_index or 2 + + for _, w in pairs(weighted_table) do + total_weight = total_weight + w[weight_index] + end + + local index = random() * total_weight + local weight_sum = 0 + for _, w in pairs(weighted_table) do + weight_sum = weight_sum + w[weight_index] + if weight_sum >= index then + return w[item_index] + end + end +end + +--- Creates a fisher-yates shuffle of a sequential number-indexed table +-- because this uses math.random, it cannot be used outside of events if no rng is supplied +-- from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items +-- @param t
to shuffle +function table.shuffle_table(t, rng) + local rand = rng or math.random + local iterations = #t + if iterations == 0 then + error('Not a sequential table') + return + end + local j + + for i = iterations, 2, -1 do + j = rand(i) + t[i], t[j] = t[j], t[i] + end +end + +--- Clears all existing entries in a table +-- @param t
to clear +-- @param array to indicate whether the table is an array or not +function table.clear_table(t, array) + if array then + for i = 1, #t do + t[i] = nil + end + else + for i in pairs(t) do + t[i] = nil + end + end +end + +--[[ + Returns the index where t[index] == target. + If there is no such index, returns a negative value such that bit32.bnot(value) is + the index that the value should be inserted to keep the list ordered. + t must be a list in ascending order for the return value to be valid. + + Usage example: + local t = {1,3,5,7,9} + local x = 5 + local index = table.binary_search(t, x) + if index < 0 then + game.print("value not found, smallest index where t[index] > x is: " .. bit32.bnot(index)) + else + game.print("value found at index: " .. index) + end +]] +function table.binary_search(t, target) + --For some reason bit32.bnot doesn't return negative numbers so I'm using ~x = -1 - x instead. + + local lower = 1 + local upper = #t + + if upper == 0 then + return -2 -- ~1 + end + + repeat + local mid = floor((lower + upper) * 0.5) + local value = t[mid] + if value == target then + return mid + elseif value < target then + lower = mid + 1 + else + upper = mid - 1 + end + until lower > upper + + return -1 - lower -- ~lower +end + +-- add table-related functions that exist in base factorio/util to the 'table' table +require 'util' + +--- Similar to serpent.block, returns a string with a pretty representation of a table. +-- Notice: This method is not appropriate for saving/restoring tables. It is meant to be used by the programmer mainly while debugging a program. +-- @param table
the table to serialize +-- @param options
options are depth, newline, indent, process +-- depth sets the maximum depth that will be printed out. When the max depth is reached, inspect will stop parsing tables and just return {...} +-- process is a function which allow altering the passed object before transforming it into a string. +-- A typical way to use it would be to remove certain values so that they don't appear at all. +-- return the prettied table +table.inspect = require 'utils.inspect' + +--- Takes a table and returns the number of entries in the table. (Slower than #table, faster than iterating via pairs) +table.size = table_size + +--- Creates a deepcopy of a table. Metatables and LuaObjects inside the table are shallow copies. +-- Shallow copies meaning it copies the reference to the object instead of the object itself. +-- @param object
the object to copy +-- @return
the copied object +table.deep_copy = table.deepcopy + +--- Merges multiple tables. Tables later in the list will overwrite entries from tables earlier in the list. +-- Ex. merge({{1, 2, 3}, {[2] = 0}, {[3] = 0}}) will return {1, 0, 0} +-- @param tables
takes a table of tables to merge +-- @return
a merged table +table.merge = util.merge + +--- Determines if two tables are structurally equal. +-- Notice: tables that are LuaObjects or contain LuaObjects won't be compared correctly, use == operator for LuaObjects +-- @param tbl1
+-- @param tbl2
+-- @return +table.equals = table.compare + +return table diff --git a/utils/task.lua b/utils/task.lua new file mode 100644 index 0000000000..a43c3174c9 --- /dev/null +++ b/utils/task.lua @@ -0,0 +1,115 @@ +-- Threading simulation module +-- Task.sleep() +-- @author Valansch and Grilledham +-- github: https://github.com/Refactorio/RedMew +-- ======================================================= -- + +local Queue = require 'utils.queue' +local PriorityQueue = require 'utils.priority_queue' +local Event = require 'utils.event' +local Token = require 'utils.token' + +local Task = {} + +global.callbacks = global.callbacks or PriorityQueue.new() +global.next_async_callback_time = -1 +global.task_queue = global.task_queue or Queue.new() +global.total_task_weight = 0 +global.task_queue_speed = 1 + +local function comp(a, b) + return a.time < b.time +end + +global.tpt = global.task_queue_speed +local function get_task_per_tick() + if game.tick % 300 == 0 then + local size = global.total_task_weight + global.tpt = math.floor(math.log10(size + 1)) * global.task_queue_speed + if global.tpt < 1 then + global.tpt = 1 + end + end + return global.tpt +end + +local function on_tick() + local queue = global.task_queue + for i = 1, get_task_per_tick() do + local task = Queue.peek(queue) + if task ~= nil then + -- result is error if not success else result is a boolean for if the task should stay in the queue. + local success, result = pcall(Token.get(task.func_token), task.params) + if not success then + if _DEBUG then + error(result) + else + log(result) + end + Queue.pop(queue) + global.total_task_weight = global.total_task_weight - task.weight + elseif not result then + Queue.pop(queue) + global.total_task_weight = global.total_task_weight - task.weight + end + end + end + + local callbacks = global.callbacks + local callback = PriorityQueue.peek(callbacks) + while callback ~= nil and game.tick >= callback.time do + local success, result = pcall(Token.get(callback.func_token), callback.params) + if not success then + if _DEBUG then + error(result) + else + log(result) + end + end + PriorityQueue.pop(callbacks, comp) + callback = PriorityQueue.peek(callbacks) + end +end + +--- Allows you to set a timer (in ticks) after which the tokened function will be run with params given as an argument +-- Cannot be called before init +-- @param ticks +-- @param func_token a token for a function store via the token system +-- @param params the argument to send to the tokened function +function Task.set_timeout_in_ticks(ticks, func_token, params) + if not game then + error('cannot call when game is not available', 2) + end + local time = game.tick + ticks + local callback = {time = time, func_token = func_token, params = params} + PriorityQueue.push(global.callbacks, callback, comp) +end + +--- Allows you to set a timer (in seconds) after which the tokened function will be run with params given as an argument +-- Cannot be called before init +-- @param sec +-- @param func_token a token for a function store via the token system +-- @param params the argument to send to the tokened function +function Task.set_timeout(sec, func_token, params) + if not game then + error('cannot call when game is not available', 2) + end + Task.set_timeout_in_ticks(60 * sec, func_token, params) +end + +--- Queueing allows you to split up heavy tasks which don't need to be completed in the same tick. +-- Queued tasks are generally run 1 per tick. If the queue backs up, more tasks will be processed per tick. +-- @param func_token a token for a function stored via the token system +-- If this function returns `true` it will run again the next tick, delaying other queued tasks (see weight) +-- @param params the argument to send to the tokened function +-- @param weight (defaults to 1) weight is the number of ticks a task is expected to take. +-- Ex. if the task is expected to repeat multiple times (ie. the function returns true and loops several ticks) +function Task.queue_task(func_token, params, weight) + weight = weight or 1 + global.total_task_weight = global.total_task_weight + weight + Queue.push(global.task_queue, {func_token = func_token, params = params, weight = weight}) +end + +Event.add(defines.events.on_tick, on_tick) + +return Task diff --git a/utils/timestamp.lua b/utils/timestamp.lua new file mode 100644 index 0000000000..9af76e5d17 --- /dev/null +++ b/utils/timestamp.lua @@ -0,0 +1,152 @@ +--- source https://github.com/daurnimator/luatz/blob/master/luatz/timetable.lua +-- edited down to just what is needed. + +local Public = {} + +local floor = math.floor +local strformat = string.format + +local function borrow(tens, units, base) + local frac = tens % 1 + units = units + frac * base + tens = tens - frac + return tens, units +end + +local function carry(tens, units, base) + if units >= base then + tens = tens + floor(units / base) + units = units % base + elseif units < 0 then + tens = tens + floor(units / base) + units = (base + units) % base + end + return tens, units +end + +local function is_leap(y) + if (y % 4) ~= 0 then + return false + elseif (y % 100) ~= 0 then + return true + else + return (y % 400) == 0 + end +end + +local mon_lengths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + +-- Number of days in year until start of month; not corrected for leap years +local months_to_days_cumulative = {0} +for i = 2, 12 do + months_to_days_cumulative[i] = months_to_days_cumulative[i - 1] + mon_lengths[i - 1] +end + +local function month_length(m, y) + if m == 2 then + return is_leap(y) and 29 or 28 + else + return mon_lengths[m] + end +end + +local function day_of_year(day, month, year) + local yday = months_to_days_cumulative[month] + if month > 2 and is_leap(year) then + yday = yday + 1 + end + return yday + day +end + +local function leap_years_since(year) + return floor(year / 4) - floor(year / 100) + floor(year / 400) +end + +local leap_years_since_1970 = leap_years_since(1970) + +local function normalise(year, month, day, hour, min, sec) + -- `month` and `day` start from 1, need -1 and +1 so it works modulo + month, day = month - 1, day - 1 + + -- Convert everything (except seconds) to an integer + -- by propagating fractional components down. + year, month = borrow(year, month, 12) + -- Carry from month to year first, so we get month length correct in next line around leap years + year, month = carry(year, month, 12) + month, day = borrow(month, day, month_length(floor(month + 1), year)) + day, hour = borrow(day, hour, 24) + hour, min = borrow(hour, min, 60) + min, sec = borrow(min, sec, 60) + + -- Propagate out of range values up + -- e.g. if `min` is 70, `hour` increments by 1 and `min` becomes 10 + -- This has to happen for all columns after borrowing, as lower radixes may be pushed out of range + min, sec = carry(min, sec, 60) -- TODO: consider leap seconds? + hour, min = carry(hour, min, 60) + day, hour = carry(day, hour, 24) + -- Ensure `day` is not underflowed + -- Add a whole year of days at a time, this is later resolved by adding months + -- TODO[OPTIMIZE]: This could be slow if `day` is far out of range + while day < 0 do + month = month - 1 + if month < 0 then + year = year - 1 + month = 11 + end + day = day + month_length(month + 1, year) + end + year, month = carry(year, month, 12) + + -- TODO[OPTIMIZE]: This could potentially be slow if `day` is very large + while true do + local i = month_length(month + 1, year) + if day < i then + break + end + day = day - i + month = month + 1 + if month >= 12 then + month = 0 + year = year + 1 + end + end + + -- Now we can place `day` and `month` back in their normal ranges + -- e.g. month as 1-12 instead of 0-11 + month, day = month + 1, day + 1 + + return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} +end + +--- Converts unix epoch timestamp into table {year: number, month: number, day: number, hour: number, min: number, sec: number} +-- @param sec unix epoch timestamp +-- @return {year: number, month: number, day: number, hour: number, min: number, sec: number} +function Public.to_timetable(secs) + return normalise(1970, 1, 1, 0, 0, secs) +end + +--- Converts timetable into unix epoch timestamp +-- @param timetable
{year: number, month: number, day: number, hour: number, min: number, sec: number} +-- @return number +function Public.from_timetable(timetable) + local tt = normalise(timetable.year, timetable.month, timetable.day, timetable.hour, timetable.min, timetable.sec) + + local year, month, day, hour, min, sec = tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec + + local days_since_epoch = + day_of_year(day, month, year) + 365 * (year - 1970) + -- Each leap year adds one day + (leap_years_since(year - 1) - leap_years_since_1970) - + 1 + + return days_since_epoch * (60 * 60 * 24) + hour * (60 * 60) + min * 60 + sec +end + +--- Converts unix epoch timestamp into human readable string. +-- @param secs unix epoch timestamp +-- @return string +function Public.to_string(secs) + local tt = normalise(1970, 1, 1, 0, 0, secs) + return strformat('%04u-%02u-%02u %02u:%02u:%02d', tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec) +end + +return Public diff --git a/utils/token.lua b/utils/token.lua new file mode 100644 index 0000000000..f9d511b7fb --- /dev/null +++ b/utils/token.lua @@ -0,0 +1,55 @@ +local Token = {} + +local tokens = {} + +local counter = 0 + +--- Assigns a unquie id for the given var. +-- This function cannot be called after on_init() or on_load() has run as that is a desync risk. +-- Typically this is used to register functions, so the id can be stored in the global table +-- instead of the function. This is becasue closures cannot be safely stored in the global table. +-- @param var +-- @return number the unique token for the variable. +function Token.register(var) + if _LIFECYCLE == 8 then + error('Calling Token.register after on_init() or on_load() has run is a desync risk.', 2) + end + + counter = counter + 1 + + tokens[counter] = var + + return counter +end + +function Token.get(token_id) + return tokens[token_id] +end + +global.tokens = {} + +function Token.register_global(var) + local c = #global.tokens + 1 + + global.tokens[c] = var + + return c +end + +function Token.get_global(token_id) + return global.tokens[token_id] +end + +function Token.set_global(token_id, var) + global.tokens[token_id] = var +end + +local uid_counter = 0 + +function Token.uid() + uid_counter = uid_counter + 1 + + return uid_counter +end + +return Token