diff --git a/src/rmod/Main.lua b/src/rmod/Main.lua index 87e11cb..bc6a6b5 100644 --- a/src/rmod/Main.lua +++ b/src/rmod/Main.lua @@ -1,7 +1,7 @@ --- Royal Mod ---@author Royal Modding ----@version 1.4.0.0 +---@version 1.5.0.0 ---@date 03/12/2020 --- Initialize RoyalMod diff --git a/src/rmod/RoyalMod.lua b/src/rmod/RoyalMod.lua index f411588..902b23c 100644 --- a/src/rmod/RoyalMod.lua +++ b/src/rmod/RoyalMod.lua @@ -1,33 +1,64 @@ --- Royal Mod ---@author Royal Modding ----@version 1.4.0.0 +---@version 1.5.0.0 ---@date 03/12/2020 ---@class RoyalMod ----@field directory string mod directory ----@field userProfileDirectory string user profile directory ----@field name string mod name ----@field mod table g_modManager mod object ----@field version string mod version ----@field author string mod author ----@field modEnv table mod scripting environment ----@field gameEnv table game scripting environment ----@field super table mod super class ----@field debug boolean mod debug state +---@field onWriteStream fun(self: RoyalMod, streamId: integer) +---@field onReadStream fun(self: RoyalMod, streamId: integer) +---@field onUpdateTick fun(self: RoyalMod, dt: number) +---@field onWriteUpdateStream fun(self: RoyalMod, streamId: integer, connection: Connection, dirtyMask: integer) +---@field onReadUpdateStream fun(self: RoyalMod, streamId: integer, timestamp: number, connection: Connection) +---@field onLoadMap fun(self: RoyalMod, mapNode: integer, mapFile: string) +---@field onDeleteMap fun(self: RoyalMod) +---@field onDraw fun(self: RoyalMod) +---@field onUpdate fun(self: RoyalMod, dt: number) +---@field onMouseEvent fun(self: RoyalMod, posX: number, posY: number, isDown: boolean, isUp: boolean, button: integer) +---@field onKeyEvent fun(self: RoyalMod, unicode: integer, sym: integer, modifier: integer, isDown: boolean) +---@field initialize fun(self: RoyalMod) +---@field onValidateVehicleTypes fun(self: RoyalMod, vtm: VehicleTypeManager, addSpecialization: fun(specName: string), addSpecializationBySpecialization: fun(specName: string, requiredSpecName: string), addSpecializationByVehicleType: fun(specName: string, requiredVehicleTypeName: string), addSpecializationByFunction: fun(specName: string, func: function)) +---@field onMissionInitialize fun(self: RoyalMod, baseDirectory: string, missionCollaborators: MissionCollaborators) +---@field onSetMissionInfo fun(self: RoyalMod, missionInfo: MissionInfo, missionDynamicInfo: table) +---@field onLoad fun(self: RoyalMod) +---@field onPreLoadMap fun(self: RoyalMod, mapFile: string) +---@field onCreateStartPoint fun(self: RoyalMod, startPointNode: integer) +---@field onPostLoadMap fun(self: RoyalMod, mapNode: integer, mapFile: string) +---@field onLoadSavegame fun(self: RoyalMod, savegameDirectory: string, savegameIndex: integer) +---@field onPreLoadVehicles fun(self: RoyalMod, xmlFile: integer, resetVehicles: boolean) +---@field onPreLoadItems fun(self: RoyalMod, xmlFile: integer) +---@field onPreLoadOnCreateLoadedObjects fun(self: RoyalMod, xmlFile: integer) +---@field onLoadFinished fun(self: RoyalMod) +---@field onStartMission fun(self: RoyalMod) +---@field onMissionStarted fun(self: RoyalMod) +---@field onPreDeleteMap fun(self: RoyalMod) +---@field onPreSaveSavegame fun(self: RoyalMod, savegameDirectory: string, savegameIndex: integer) +---@field onPostSaveSavegame fun(self: RoyalMod, savegameDirectory: string, savegameIndex: integer) +---@field onLoadHelpLine fun(self: RoyalMod): string +--@field directory string mod directory +--@field userProfileDirectory string user profile directory +--@field name string mod name +--@field mod table g_modManager mod object +--@field version string mod version +--@field author string mod author +--@field modEnv table mod scripting environment +--@field gameEnv table game scripting environment +--@field super table mod super class +--@field debug boolean mod debug state RoyalMod = {} ---@param debug boolean defines if debug is enabled ---@param mpSync boolean defines if mp sync is enabled ---@return RoyalMod function RoyalMod.new(debug, mpSync) + ---@type RoyalMod local mod = {} mod.directory = g_currentModDirectory mod.userProfileDirectory = getUserProfileAppPath() mod.name = g_currentModName - mod.mod = g_modManager:getModByName(mod.name) - mod.version = mod.mod.version - mod.author = mod.mod.author + mod.modManagerMod = g_modManager:getModByName(mod.name) + mod.version = mod.modManagerMod.version + mod.author = mod.modManagerMod.author mod.modEnv = getfenv() mod.gameEnv = getfenv(0) mod.super = {} @@ -35,11 +66,13 @@ function RoyalMod.new(debug, mpSync) if mod.debug then mod.gameEnv["g_showDevelopmentWarnings"] = true + mod.gameEnv["g_addTestCommands"] = true --mod.gameEnv["g_isDevelopmentConsoleScriptModTesting"] = true end mod.super.oldFunctions = {} + ---@param error string mod.super.errorHandle = function(error) g_logManager:devError("RoyalMod caught error from %s (%s)", mod.name, mod.version) g_logManager:error(error) @@ -61,6 +94,8 @@ function RoyalMod.new(debug, mpSync) if mpSync then mod.super.sync = Object:new(g_server ~= nil, g_client ~= nil, Class(nil, Object)) + ---@param self Object + ---@param streamId integer mod.super.sync.writeStream = function(self, streamId) self:superClass().writeStream(self, streamId) if mod.onWriteStream ~= nil then @@ -72,6 +107,8 @@ function RoyalMod.new(debug, mpSync) end end + ---@param self Object + ---@param streamId integer mod.super.sync.readStream = function(self, streamId) self:superClass().readStream(self, streamId) if mod.onReadStream ~= nil then @@ -83,6 +120,8 @@ function RoyalMod.new(debug, mpSync) end end + ---@param self Object + ---@param dt number mod.super.sync.updateTick = function(self, dt) self:superClass().updateTick(self, dt) if mod.onUpdateTick ~= nil then @@ -90,6 +129,10 @@ function RoyalMod.new(debug, mpSync) end end + ---@param self Object + ---@param streamId integer + ---@param connection Connection + ---@param dirtyMask integer mod.super.sync.writeUpdateStream = function(self, streamId, connection, dirtyMask) self:superClass().writeUpdateStream(self, streamId, connection, dirtyMask) if mod.onWriteUpdateStream ~= nil then @@ -97,6 +140,10 @@ function RoyalMod.new(debug, mpSync) end end + ---@param self Object + ---@param streamId integer + ---@param timestamp number + ---@param connection Connection mod.super.sync.readUpdateStream = function(self, streamId, timestamp, connection) self:superClass().readUpdateStream(self, streamId, timestamp, connection) if mod.onReadUpdateStream ~= nil then @@ -105,36 +152,53 @@ function RoyalMod.new(debug, mpSync) end end + ---@param _ table + ---@param mapFile string mod.super.loadMap = function(_, mapFile) if mod.onLoadMap ~= nil then xpcall(mod.onLoadMap, mod.super.errorHandle, mod, mod.mapNode, mapFile) end end + ---@param _ table mod.super.deleteMap = function(_) if mod.onDeleteMap ~= nil then xpcall(mod.onDeleteMap, mod.super.errorHandle, mod) end end + ---@param _ table mod.super.draw = function(_) if mod.onDraw ~= nil then xpcall(mod.onDraw, mod.super.errorHandle, mod) end end + ---@param _ table + ---@param dt number mod.super.update = function(_, dt) if mod.onUpdate ~= nil then xpcall(mod.onUpdate, mod.super.errorHandle, mod, dt) end end + ---@param _ table + ---@param posX number + ---@param posY number + ---@param isDown boolean + ---@param isUp boolean + ---@param button integer mod.super.mouseEvent = function(_, posX, posY, isDown, isUp, button) if mod.onMouseEvent ~= nil then xpcall(mod.onMouseEvent, mod.super.errorHandle, mod, posX, posY, isDown, isUp, button) end end + ---@param _ table + ---@param unicode integer + ---@param sym integer + ---@param modifier integer + ---@param isDown boolean mod.super.keyEvent = function(_, unicode, sym, modifier, isDown) if mod.onKeyEvent ~= nil then xpcall(mod.onKeyEvent, mod.super.errorHandle, mod, unicode, sym, modifier, isDown) @@ -143,6 +207,14 @@ function RoyalMod.new(debug, mpSync) mod.super.oldFunctions.VehicleTypeManagervalidateVehicleTypes = VehicleTypeManager.validateVehicleTypes VehicleTypeManager.validateVehicleTypes = function(self, ...) + ---@type table + local global = mod.gameEnv["g_i18n"].texts + ---@type string + for key, text in pairs(g_i18n.texts) do + if global[key] == nil then + global[key] = text + end + end if mod.initialize ~= nil then --- g_currentMission is still nil here --- All mods are loaded here @@ -167,6 +239,7 @@ function RoyalMod.new(debug, mpSync) mod.super.errorHandle, mod, self, + ---@param specName string function(specName) if not specAddAllowed then g_logManager:devError("[%s] addSpecialization is no more allowed", mod.name) @@ -174,6 +247,8 @@ function RoyalMod.new(debug, mpSync) end table.insert(specs, {name = string.format("%s.%s", mod.name, specName), addedTo = {}}) end, + ---@param specName string + ---@param requiredSpecName string function(specName, requiredSpecName) if not specAddAllowed then g_logManager:devError("[%s] addSpecializationBySpecialization is no more allowed", mod.name) @@ -181,6 +256,8 @@ function RoyalMod.new(debug, mpSync) end table.insert(specsBySpec, {name = string.format("%s.%s", mod.name, specName), requiredSpecName = requiredSpecName, addedTo = {}}) end, + ---@param specName string + ---@param requiredVehicleTypeName string function(specName, requiredVehicleTypeName) if not specAddAllowed then g_logManager:devError("[%s] addSpecializationByVehicleType is no more allowed", mod.name) @@ -188,6 +265,8 @@ function RoyalMod.new(debug, mpSync) end table.insert(specsByType, {name = string.format("%s.%s", mod.name, specName), requiredVehicleTypeName = requiredVehicleTypeName, addedTo = {}}) end, + ---@param specName string + ---@param func function function(specName, func) if not specAddAllowed then g_logManager:devError("[%s] addSpecializationByFunction is no more allowed", mod.name) @@ -201,6 +280,7 @@ function RoyalMod.new(debug, mpSync) specAddAllowed = false -- remove invalid specs + for i, spec in pairs(specs) do if g_specializationManager:getSpecializationByName(spec.name) == nil then g_logManager:devError("[%s] Can't find specialization %s", mod.name, spec.name) @@ -327,13 +407,12 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00new = Mission00.new + ---@param self Mission00 + ---@param baseDirectory string + ---@param customMt? table + ---@param missionCollaborators MissionCollaborators + ---@return Mission00 Mission00.new = function(self, baseDirectory, customMt, missionCollaborators, ...) - local global = mod.gameEnv["g_i18n"].texts - for key, text in pairs(g_i18n.texts) do - if global[key] == nil then - global[key] = text - end - end if mod.onMissionInitialize ~= nil then --- g_currentMission is still nil here xpcall(mod.onMissionInitialize, mod.super.errorHandle, mod, baseDirectory, missionCollaborators) @@ -342,6 +421,9 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00setMissionInfo = Mission00.setMissionInfo + ---@param self Mission00 + ---@param missionInfo FSCareerMissionInfo + ---@param missionDynamicInfo table Mission00.setMissionInfo = function(self, missionInfo, missionDynamicInfo, ...) g_currentMission:addLoadFinishedListener(mod.super) g_currentMission:registerObjectToCallOnMissionStart(mod.super) @@ -353,6 +435,7 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00load = Mission00.load + ---@param self Mission00 Mission00.load = function(self, ...) if mod.onLoad ~= nil then xpcall(mod.onLoad, mod.super.errorHandle, mod) @@ -361,6 +444,12 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.FSBaseMissionloadMap = FSBaseMission.loadMap + ---@param self FSBaseMission + ---@param mapFile string + ---@param addPhysics boolean + ---@param asyncCallbackFunction function + ---@param asyncCallbackObject table + ---@param asyncCallbackArguments table FSBaseMission.loadMap = function(self, mapFile, addPhysics, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments, ...) if mod.onPreLoadMap ~= nil then xpcall(mod.onPreLoadMap, mod.super.errorHandle, mod, mapFile) @@ -369,6 +458,8 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00onCreateStartPoint = Mission00.onCreateStartPoint + ---@param self Mission00 + ---@param startPointNode integer Mission00.onCreateStartPoint = function(self, startPointNode, ...) mod.super.oldFunctions.Mission00onCreateStartPoint(self, startPointNode, ...) if mod.super.sync ~= nil then @@ -381,6 +472,10 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.BaseMissionloadMapFinished = BaseMission.loadMapFinished + ---@param self BaseMission + ---@param mapNode integer + ---@param arguments table + ---@param callAsyncCallback boolean BaseMission.loadMapFinished = function(self, mapNode, arguments, callAsyncCallback, ...) mod.mapNode = mapNode local mapFile, _, _, _ = unpack(arguments) @@ -391,6 +486,9 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00loadMission00Finished = Mission00.loadMission00Finished + ---@param self Mission00 + ---@param mapNode integer + ---@param arguments table Mission00.loadMission00Finished = function(self, mapNode, arguments, ...) if mod.onLoadSavegame ~= nil then xpcall(mod.onLoadSavegame, mod.super.errorHandle, mod, mod.super.getSavegameDirectory(), g_currentMission.missionInfo.savegameIndex) @@ -399,6 +497,9 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00loadVehicles = Mission00.loadVehicles + ---@param self Mission00 + ---@param xmlFile integer + ---@param resetVehicles boolean Mission00.loadVehicles = function(self, xmlFile, resetVehicles, ...) if mod.onPreLoadVehicles ~= nil then xpcall(mod.onPreLoadVehicles, mod.super.errorHandle, mod, xmlFile, resetVehicles) @@ -407,6 +508,8 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00loadItems = Mission00.loadItems + ---@param self Mission00 + ---@param xmlFile integer Mission00.loadItems = function(self, xmlFile, ...) if mod.onPreLoadItems ~= nil then xpcall(mod.onPreLoadItems, mod.super.errorHandle, mod, xmlFile) @@ -415,6 +518,8 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00loadOnCreateLoadedObjects = Mission00.loadOnCreateLoadedObjects + ---@param self Mission00 + ---@param xmlFile integer Mission00.loadOnCreateLoadedObjects = function(self, xmlFile, ...) if mod.onPreLoadOnCreateLoadedObjects ~= nil then xpcall(mod.onPreLoadOnCreateLoadedObjects, mod.super.errorHandle, mod, xmlFile) @@ -430,6 +535,7 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00onStartMission = Mission00.onStartMission + ---@param self Mission00 Mission00.onStartMission = function(self, ...) if mod.onStartMission ~= nil then xpcall(mod.onStartMission, mod.super.errorHandle, mod) @@ -444,6 +550,7 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.Mission00delete = Mission00.delete + ---@param self Mission00 Mission00.delete = function(self, ...) if mod.onPreDeleteMap ~= nil then xpcall(mod.onPreDeleteMap, mod.super.errorHandle, mod) @@ -452,6 +559,7 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.FSBaseMissionsaveSavegame = FSBaseMission.saveSavegame + ---@param self FSBaseMission FSBaseMission.saveSavegame = function(self, ...) if mod.onPreSaveSavegame ~= nil then -- before all vhicles, items and onCreateObjects are saved @@ -465,6 +573,10 @@ function RoyalMod.new(debug, mpSync) end mod.super.oldFunctions.HelpLineManagerloadMapData = HelpLineManager.loadMapData + ---@param self HelpLineManager + ---@param xmlFile integer + ---@param missionInfo FSCareerMissionInfo + ---@return boolean HelpLineManager.loadMapData = function(self, xmlFile, missionInfo) if mod.super.oldFunctions.HelpLineManagerloadMapData(self, xmlFile, missionInfo) then if mod.onLoadHelpLine ~= nil then diff --git a/src/utility/Array.lua b/src/utility/Array.lua index 8361ef8..e32a149 100644 --- a/src/utility/Array.lua +++ b/src/utility/Array.lua @@ -1,10 +1,10 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 26/02/2021 ----@alias Array table tables with numeric indexes only, always ordered and sequential +---@alias Array table tables with numeric indexes only, always ordered and sequential --- Array utilities class built with performances in mind (with 'array' we mean tables with numeric indexes only, always ordered and sequential) ---@class ArrayUtility @@ -13,12 +13,14 @@ ArrayUtility = ArrayUtility or {} --- Remove matching elements from an array ---@param array Array ---@param removeFunc fun(array: Array, index: number, moveAt: number): boolean | "function(array, index, moveAt) local element = array[index] return true end" ----@return Array +---@return number removedCount count of removed elements function ArrayUtility.remove(array, removeFunc) + local removedCount = 0 local moveAt, length = 1, #array for index = 1, length do if removeFunc(array, index, moveAt) then array[index] = nil + removedCount = removedCount + 1 else -- move kept element's value to moveAt's position, if it's not already there if (index ~= moveAt) then @@ -29,7 +31,7 @@ function ArrayUtility.remove(array, removeFunc) moveAt = moveAt + 1 end end - return array + return removedCount end --- Remove element at the given index from an array diff --git a/src/utility/Debug.lua b/src/utility/Debug.lua index 83f6559..de1888c 100644 --- a/src/utility/Debug.lua +++ b/src/utility/Debug.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 05/01/2021 ---@class DebugUtility diff --git a/src/utility/DelayedCallBack.lua b/src/utility/DelayedCallBack.lua new file mode 100644 index 0000000..6cadd59 --- /dev/null +++ b/src/utility/DelayedCallBack.lua @@ -0,0 +1,63 @@ +--- Royal Utility + +---@author Royal Modding +---@version 2.0.3.0 +---@date 08/03/17 + +---@class DelayedCallBack +DelayedCallBack = {} + +---@param callback function +---@param callbackObject any +---@return DelayedCallBack +function DelayedCallBack:new(callback, callbackObject) + if DelayedCallBack_mt == nil then + DelayedCallBack_mt = Class(DelayedCallBack) + end + + ---@type DelayedCallBack + local dcb = setmetatable({}, DelayedCallBack_mt) + dcb.callBack = callback + dcb.callbackObject = callbackObject + dcb.callbackCalled = true + dcb.delay = 0 + dcb.timer = 0 + dcb.skipOneFrame = false + return dcb +end + +---@param dt number +function DelayedCallBack:update(dt) + if not self.callbackCalled then + if not self.skipOneFrame then + self.timer = self.timer + dt + end + if self.timer >= self.delay then + self:callCallBack() + end + if self.skipOneFrame then + self.timer = self.timer + dt + end + end +end + +---@param delay number +function DelayedCallBack:call(delay, ...) + self.callbackCalled = false + self.callbackParams = {...} + if delay == nil or delay == 0 then + self:callCallBack() + else + self.delay = delay + self.timer = 0 + end +end + +function DelayedCallBack:callCallBack() + if self.callbackObject ~= nil then + self.callBack(self.callbackObject, unpack(self.callbackParams)) + else + self.callBack(unpack(self.callbackParams)) + end + self.callbackCalled = true +end diff --git a/src/utility/Entity.lua b/src/utility/Entity.lua index 0237187..3ea059e 100644 --- a/src/utility/Entity.lua +++ b/src/utility/Entity.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 05/01/2021 ---@class EntityUtility diff --git a/src/utility/FadeEffect.lua b/src/utility/FadeEffect.lua new file mode 100644 index 0000000..1c03a7a --- /dev/null +++ b/src/utility/FadeEffect.lua @@ -0,0 +1,153 @@ +--- Royal Utility + +---@author Royal Modding +---@version 2.0.3.0 +---@date 17/02/2017 + +---@class FadeEffect +FadeEffect = {} + +FadeEffect.STATES = {} +FadeEffect.STATES.FADEIN = 1 +FadeEffect.STATES.STAY = 2 +FadeEffect.STATES.FADEOUT = 3 +FadeEffect.STATES.IDLE = 4 + +FadeEffect.ALIGNS = {} +FadeEffect.ALIGNS.LEFT = 0 +FadeEffect.ALIGNS.TOP = 0 +FadeEffect.ALIGNS.CENTER = 1 +FadeEffect.ALIGNS.RIGHT = 2 +FadeEffect.ALIGNS.BOTTOM = 2 + +---@class FadeEffectSettings +FadeEffect.defaultSettings = { + color = { + r = 1, + g = 1, + b = 1 + }, + position = { + x = 0.5, + y = 0.5 + }, + align = { + x = FadeEffect.ALIGNS.CENTER, + y = FadeEffect.ALIGNS.CENTER + }, + bold = true, + size = 0.025, + text = "Fade Effect", + shadow = false, + shadowPosition = { + x = 0, + y = 0 + }, + initialAlpha = 0, + statesTime = {1, 1, 1}, + statesAlpha = {1, 1, 0}, + loop = false +} + +---@param settings FadeEffectSettings +---@return FadeEffect +function FadeEffect:new(settings) + if FadeEffect_mt == nil then + FadeEffect_mt = Class(FadeEffect) + end + + ---@type FadeEffect + local fe = setmetatable({}, FadeEffect_mt) + + ---@type FadeEffectSettings + fe.settings = {} + + for k, v in pairs(self.defaultSettings) do + fe.settings[k] = v + end + + for k, v in pairs(settings) do + fe.settings[k] = v + end + + fe:play(fe.settings.text) + fe.state = FadeEffect.STATES.IDLE + + return fe +end + +function FadeEffect:alignText() + self.settings.position.alignedX = self.settings.position.x + self.settings.position.alignedY = self.settings.position.y + if self.settings.align.x == FadeEffect.ALIGNS.CENTER then + self.settings.position.alignedX = self.settings.position.x - (getTextWidth(self.settings.size, self.settings.text) / 2) + end + if self.settings.align.x == FadeEffect.ALIGNS.RIGHT then + self.settings.position.alignedX = self.settings.position.x - getTextWidth(self.settings.size, self.settings.text) + end + if self.settings.align.y == FadeEffect.ALIGNS.CENTER then + self.settings.position.alignedY = self.settings.position.y - (getTextHeight(self.settings.size, self.settings.text) / 2) + end + if self.settings.align.y == FadeEffect.ALIGNS.TOP then + self.settings.position.alignedY = self.settings.position.y - getTextHeight(self.settings.size, self.settings.text) + end +end + +---@param text string +function FadeEffect:setText(text) + self.settings.text = text + self:alignText() +end + +---@param text string +function FadeEffect:play(text) + if text ~= nil then + self.settings.text = text + self:alignText() + end + self.alpha = self.settings.initialAlpha + self.initialAlpha = self.settings.initialAlpha + self.state = FadeEffect.STATES.FADEIN + self.tmpStateTime = 0 +end + +function FadeEffect:stop() + self.state = FadeEffect.STATES.IDLE +end + +function FadeEffect:draw() + if self.state ~= FadeEffect.STATES.IDLE then + setTextBold(self.settings.bold) + if self.settings.shadow then + setTextColor(0, 0, 0, self.alpha) + renderText(self.settings.position.alignedX + self.settings.shadowPosition.x, self.settings.position.alignedY - self.settings.shadowPosition.y, self.settings.size, self.settings.text) + end + setTextColor(self.settings.color.r, self.settings.color.g, self.settings.color.b, self.alpha) + renderText(self.settings.position.alignedX, self.settings.position.alignedY, self.settings.size, self.settings.text) + setTextBold(false) + setTextColor(1, 1, 1, 1) + end +end + +---@param dt number +function FadeEffect:update(dt) + if self.state ~= FadeEffect.STATES.IDLE then + local stateTime = self.settings.statesTime[self.state] * 1000 + if (self.tmpStateTime + dt) >= stateTime then + self.tmpStateTime = (self.tmpStateTime + dt - stateTime) + self.alpha = self.settings.statesAlpha[self.state] + self.initialAlpha = self.alpha + self.state = self.state + 1 + if self.settings.loop and self.state == FadeEffect.STATES.IDLE then + self.state = 1 + end + else + self.tmpStateTime = self.tmpStateTime + dt + end + if self.initialAlpha == self.settings.statesAlpha[self.state] then + self.alpha = self.settings.statesAlpha[self.state] + else + self.alpha = math.abs(self.initialAlpha - (1 / stateTime) * self.tmpStateTime) + end + end +end diff --git a/src/utility/Gameplay.lua b/src/utility/Gameplay.lua index 7aed06b..6b4a414 100644 --- a/src/utility/Gameplay.lua +++ b/src/utility/Gameplay.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 05/01/2021 ---@class GameplayUtility diff --git a/src/utility/Interpolator.lua b/src/utility/Interpolator.lua index 5668e48..2e7cfd1 100644 --- a/src/utility/Interpolator.lua +++ b/src/utility/Interpolator.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 11/01/2021 --- Interpolators utilities class diff --git a/src/utility/Main.lua b/src/utility/Main.lua index 8f8a9c8..751e0a3 100644 --- a/src/utility/Main.lua +++ b/src/utility/Main.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 21/11/2020 --- Initialize RoyalUtility @@ -15,6 +15,8 @@ function InitRoyalUtility(utilityDirectory) source(Utils.getFilename("Table.lua", utilityDirectory)) source(Utils.getFilename("Interpolator.lua", utilityDirectory)) source(Utils.getFilename("Array.lua", utilityDirectory)) + source(Utils.getFilename("FadeEffect.lua", utilityDirectory)) + source(Utils.getFilename("DelayedCallBack.lua", utilityDirectory)) g_logManager:devInfo("Royal Utility loaded successfully by " .. g_currentModName) return true end diff --git a/src/utility/String.lua b/src/utility/String.lua index 803b69d..ccd825f 100644 --- a/src/utility/String.lua +++ b/src/utility/String.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 05/01/2021 --- String utilities class diff --git a/src/utility/Table.lua b/src/utility/Table.lua index a5b4d27..c026921 100644 --- a/src/utility/Table.lua +++ b/src/utility/Table.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 05/01/2021 --- Table utilities class @@ -50,6 +50,18 @@ function TableUtility.contains(t, value) return false end +--- Map a table to a new table +---@param t table source table +---@param func function | "function(e) return { f1 = e.f1, f2 = e.f2 } end" mapping function +---@return table mapped mapped table +function TableUtility.map(t, func) + local mapped = {} + for k, v in pairs(t) do + mapped[k] = func(v) + end + return mapped +end + --- Get if a matching element exists ---@param t table ---@param func function | "function(e) return true end" diff --git a/src/utility/Utility.lua b/src/utility/Utility.lua index 599dc3c..d1569fa 100644 --- a/src/utility/Utility.lua +++ b/src/utility/Utility.lua @@ -1,7 +1,7 @@ --- Royal Utility ---@author Royal Modding ----@version 1.9.0.0 +---@version 2.0.3.0 ---@date 09/11/2020 --- Utilities class @@ -20,6 +20,28 @@ function Utility.clamp(minValue, value, maxValue) return math.max(minValue, math.min(maxValue, value)) end +--- Get random number sign (1 or -1) +---@return number +function Utility.randomSign() + if math.random(2) > 1 then + return -1 + else + return 1 + end +end + +--- Normalize value by given maximum and minimum +---@param minValue number +---@param value number +---@param maxValue number +---@return number +function Utility.normalize(minValue, value, maxValue) + minValue = minValue or 0 + maxValue = maxValue or 1 + value = value or 0.5 + return (value - minValue) / (maxValue - minValue) +end + ---@param target table ---@param name string ---@param newFunc function