local CUSTOM = true local PREDEFINED = false ZO_CHROMA_EFFECT_DRAW_LEVEL = { FALLBACK = 0, --Blanket layer, lowest level, there to make sure there's always something genericly lit UNDERLAY_LOW = 1, --Blanket layer, like fallback but more specific, e.g.: alliance color when known UNDERLAY_HIGH = 2, --Blanket layer, an extra underlay that goes overtop of UNDERLAY_LOW, e.g.: specialized hot zones ANIMATION = 300, --Ripples and highlights, usually blending with effects underneath ACTIVE_KEY_ACTION = 400, --For lighting up relevant keys, typically regardless of the effects underneath, but can blend if necessary ACTIVE_KEY_UI = 410, --For lighting up relevant keys, typically regardless of the effects underneath, but can blend if necessary DEATH = 450, --The glows for death cover pretty much everything else, with the exception of COVER COVER = 500, --For when you need to just cover up all the other effects } ZO_CHROMA_CUSTOM_EFFECT_VALID_CELL = true -------------- --Animations-- -------------- ZO_ChromaAnimationTimer = ZO_Object:Subclass() function ZO_ChromaAnimationTimer:New(...) local object = ZO_Object:New(self) object:Initialize(...) return object end function ZO_ChromaAnimationTimer:Initialize(animationTimerData) self.minValue = animationTimerData.minValue self.maxValue = animationTimerData.maxValue self.valueRange = self.maxValue - self.minValue self.startValue = animationTimerData.startValue self.deleteOnComplete = animationTimerData.deleteOnComplete self.timeline = ANIMATION_MANAGER:CreateTimelineFromVirtual(animationTimerData.animationName) self.timeline.object = self end function ZO_ChromaAnimationTimer:PlayFromStart() self.value = self.startValue self.isComplete = false self.timeline:PlayFromStart() end function ZO_ChromaAnimationTimer:SetProgress(progress) self.value = self.minValue + (self.valueRange * progress) end function ZO_ChromaAnimationTimer:GetValue() return self.value end function ZO_ChromaAnimationTimer:OnAnimationComplete() self.isComplete = true end function ZO_ChromaAnimationTimer:IsPlaying() return self.timeline:IsPlaying() end function ZO_ChromaAnimationTimer:IsComplete() return self.isComplete end --Pulsate-- ZO_ChromaPulsateTimer = ZO_ChromaAnimationTimer:Subclass() function ZO_ChromaPulsateTimer:New(...) return ZO_ChromaAnimationTimer.New(self, ...) end function ZO_ChromaPulsateTimer:OnAnimationComplete() self.timeline:PlayFromStart() end function ZO_ChromaAnimation_SetProgress(animation, progress) animation:GetTimeline().object:SetProgress(progress) end function ZO_ChromaAnimation_OnStop(timeline, completedPlaying) if completedPlaying then timeline.object:OnAnimationComplete() end end ZO_CHROMA_ANIMATION_TIMER_DATA = { DEATH_FADE_OUT = { animationClass = ZO_ChromaAnimationTimer, animationName = "ZO_ChromaDeathFadeOutAnimation", minValue = .33, maxValue = 1, startValue = 1, useAlpha = false, restartOnAdd = true, deleteOnComplete = false, }, DEATH_PULSATE = { animationClass = ZO_ChromaPulsateTimer, animationName = "ZO_ChromaDeathPulsateAnimation", minValue = .33, maxValue = 1, startValue = .33, useAlpha = false, restartOnAdd = false, deleteOnComplete = false, }, QUICKSLOT_ONE_PULSE = { animationClass = ZO_ChromaAnimationTimer, animationName = "ZO_ChromaOnePulseAnimation", minValue = .11, maxValue = 1, startValue = .33, useAlpha = true, restartOnAdd = true, deleteOnComplete = true, }, ULTIMATE_ONE_PULSE = { animationClass = ZO_ChromaAnimationTimer, animationName = "ZO_ChromaOnePulseAnimation", minValue = .5, maxValue = 1, startValue = .5, useAlpha = false, restartOnAdd = true, deleteOnComplete = false, }, KEYBIND_PROMPT_PULSATE = { animationClass = ZO_ChromaPulsateTimer, animationName = "ZO_ChromaSteadyPulsateAnimation", minValue = .3, maxValue = 1, startValue = .3, useAlpha = false, restartOnAdd = true, deleteOnComplete = false, }, } do local ANIMATION_TIMERS = {} function ZO_GetChromaAnimationTimer(animationTimerData) local animationTimer = ANIMATION_TIMERS[animationTimerData] if not animationTimer then animationTimer = animationTimerData.animationClass:New(animationTimerData) ANIMATION_TIMERS[animationTimerData] = animationTimer end return animationTimer end end ------------------------ --Base template effect-- ------------------------ ZO_ChromaEffectBaseTemplate = ZO_Object:Subclass() function ZO_ChromaEffectBaseTemplate:New(...) local object = ZO_Object.New(self) object:Initialize(...) return object end function ZO_ChromaEffectBaseTemplate:Initialize(deviceType, drawLevel, isCustom) self.deviceType = deviceType self.drawLevel = drawLevel self.isCustom = isCustom local function OnUpdate(timeMs, callbackManager) self:OnUpdate(timeMs, callbackManager) end self.onUpdate = OnUpdate end function ZO_ChromaEffectBaseTemplate:IsCustom() return self.isCustom end function ZO_ChromaEffectBaseTemplate:SetIsCStyle() self.isCStyle = true end function ZO_ChromaEffectBaseTemplate:IsCStyle() return self.isCStyle end function ZO_ChromaEffectBaseTemplate:GetDrawLevel() return self.drawLevel end function ZO_ChromaEffectBaseTemplate:GetDeviceType() return self.deviceType end function ZO_ChromaEffectBaseTemplate:HandleAddEffect(callbackManager) self.addedTimeMs = GetFrameTimeMilliseconds() self.elapsedTimeMs = 0 callbackManager:RegisterCallback("OnUpdate", self.onUpdate) end function ZO_ChromaEffectBaseTemplate:HandleRemoveEffect(callbackManager) callbackManager:UnregisterCallback("OnUpdate", self.onUpdate) end function ZO_ChromaEffectBaseTemplate:SetOnUpdateCallback(updateCallback) self.updateCallback = updateCallback end function ZO_ChromaEffectBaseTemplate:OnUpdate(timeMs, callbackManager) self.elapsedTimeMs = timeMs - self.addedTimeMs if self.updateCallback then self.updateCallback(timeMs, callbackManager, self) end end ---------------------- --Custom effect Base-- ---------------------- ZO_ChromaCustomEffectBase = ZO_ChromaEffectBaseTemplate:Subclass() function ZO_ChromaCustomEffectBase:New(...) return ZO_ChromaEffectBaseTemplate.New(self, ...) end function ZO_ChromaCustomEffectBase:Initialize(deviceType, drawLevel, color, blendMode, animationTimerData, isFullGrid) ZO_ChromaEffectBaseTemplate.Initialize(self, deviceType, drawLevel, CUSTOM) self.color = color self.blendMode = blendMode self.isFullGrid = isFullGrid self.animationTimerData = animationTimerData --Don't create the timer unless we actually end up needing it self.animationTimer = nil end function ZO_ChromaCustomEffectBase:GetColor(rowIndex, columnIndex) assert(false, "You must override the GetColor function in your ChromaCustomEffect") end function ZO_ChromaCustomEffectBase:GetColorRGB(rowIndex, columnIndex) assert(false, "You must override the GetColorRGB function in your ChromaCustomEffect") end function ZO_ChromaCustomEffectBase:GetBlendMode() return self.blendMode end function ZO_ChromaCustomEffectBase:IsFullGrid() return self.isFullGrid end function ZO_ChromaCustomEffectBase:HandleAddEffect(...) ZO_ChromaEffectBaseTemplate.HandleAddEffect(self, ...) if self.animationTimerData then if not self.animationTimer then self.animationTimer = ZO_GetChromaAnimationTimer(self.animationTimerData) end if not self.animationTimer:IsPlaying() or self.animationTimerData.restartOnAdd then self.animationTimer:PlayFromStart() end self:RefreshColor() end end function ZO_ChromaCustomEffectBase:OnUpdate(timeMs, callbackManager) ZO_ChromaEffectBaseTemplate.OnUpdate(self, timeMs, callbackManager) if self.animationTimer then if self.animationTimer:IsPlaying() then callbackManager:MarkDirty(self.deviceType) end self:RefreshColor() end end function ZO_ChromaCustomEffectBase:RefreshColor() --To be overriden end function ZO_ChromaCustomEffectBase:GetCurrentAnimationValue() return self.animationTimer and self.animationTimer:GetValue() or 0 end ---------------------- --Custom effect Full-- ---------------------- ZO_ChromaCustomEffectFull = ZO_ChromaCustomEffectBase:Subclass() function ZO_ChromaCustomEffectFull:New(...) return ZO_ChromaCustomEffectBase.New(self, ...) end function ZO_ChromaCustomEffectFull:Initialize(deviceType, drawLevel, color, blendMode, animationTimerData) ZO_ChromaCustomEffectBase.Initialize(self, deviceType, drawLevel, color, blendMode, animationTimerData, true) end function ZO_ChromaCustomEffectFull:GetColor(rowIndex, columnIndex) return ZO_CHROMA_CUSTOM_EFFECT_VALID_CELL, self.color end function ZO_ChromaCustomEffectFull:GetCellValid(rowIndex, columnIndex) return ZO_CHROMA_CUSTOM_EFFECT_VALID_CELL end function ZO_ChromaCustomEffectFull:GetColorRGB(rowIndex, columnIndex) return ZO_CHROMA_CUSTOM_EFFECT_VALID_CELL, self.color:UnpackRGBA() end ----------------------- --Custom effect Cells-- ----------------------- ZO_ChromaCustomEffectCells = ZO_ChromaCustomEffectBase:Subclass() function ZO_ChromaCustomEffectCells:New(...) return ZO_ChromaCustomEffectBase.New(self, ...) end function ZO_ChromaCustomEffectCells:Initialize(deviceType, drawLevel, color, blendMode, animationTimerData) ZO_ChromaCustomEffectBase.Initialize(self, deviceType, drawLevel, color, blendMode, animationTimerData, false) self.cells = { } end function ZO_ChromaCustomEffectCells:SetCellActive(rowIndex, columnIndex, isActive) local row = self.cells[rowIndex] if not row then if not isActive then -- Cell is already inactive return end row = { } self.cells[rowIndex] = row end row[columnIndex] = isActive or nil end function ZO_ChromaCustomEffectCells:GetColor(rowIndex, columnIndex) local validCell = self.cells[rowIndex] and self.cells[rowIndex][columnIndex] return validCell, self.color end --------------------------- --Full custom fade effect-- --------------------------- ZO_ChromaCustomEffectFullFadeAnimation = ZO_ChromaCustomEffectFull:Subclass() function ZO_ChromaCustomEffectFullFadeAnimation:New(...) return ZO_ChromaCustomEffectFull.New(self, ...) end function ZO_ChromaCustomEffectFullFadeAnimation:Initialize(deviceType, drawLevel, color, blendMode, animationTimerData) ZO_ChromaCustomEffectFull.Initialize(self, deviceType, drawLevel, color, blendMode, animationTimerData) self.initColor = color self.color = ZO_ColorDef:New(color:UnpackRGB()) end function ZO_ChromaCustomEffectFullFadeAnimation:RefreshColor() local currentValue = self:GetCurrentAnimationValue() if self.animationTimerData.useAlpha then self.color:SetAlpha(currentValue) else local initColor = self.initColor self.color:SetRGB(self.initColor.r * currentValue, self.initColor.g * currentValue, self.initColor.b * currentValue) end end ---------------------------- --Cells custom fade effect-- ---------------------------- ZO_ChromaCustomEffectCellsFadeAnimation = ZO_ChromaCustomEffectCells:Subclass() function ZO_ChromaCustomEffectCellsFadeAnimation:New(...) return ZO_ChromaCustomEffectCells.New(self, ...) end function ZO_ChromaCustomEffectCellsFadeAnimation:Initialize(deviceType, drawLevel, color, blendMode, animationTimerData) ZO_ChromaCustomEffectCells.Initialize(self, deviceType, drawLevel, color, blendMode, animationTimerData) self.initColor = color self.color = ZO_ColorDef:New(color:UnpackRGB()) end function ZO_ChromaCustomEffectCellsFadeAnimation:RefreshColor() local currentValue = self:GetCurrentAnimationValue() if self.animationTimerData.useAlpha then self.color:SetAlpha(currentValue) else local initColor = self.initColor self.color:SetRGB(self.initColor.r * currentValue, self.initColor.g * currentValue, self.initColor.b * currentValue) end end ------------------------- --C-Style Custom Effect-- ------------------------- --Base-- ZO_ChromaCStyleCustomEffect = ZO_ChromaEffectBaseTemplate:Subclass() function ZO_ChromaCStyleCustomEffect:New(...) return ZO_ChromaEffectBaseTemplate.New(self, ...) end function ZO_ChromaCStyleCustomEffect:Initialize(deviceType, drawLevel, gridStyle, animationTimerData) ZO_ChromaEffectBaseTemplate.Initialize(self, deviceType, drawLevel, CUSTOM) self:SetIsCStyle(true) self.effectId = ChromaGenerateCustomEffect(deviceType, self:GetEffectType(), gridStyle) self.animationTimerData = animationTimerData --Don't create the timer unless we actually end up needing it self.animationTimer = nil end function ZO_ChromaCStyleCustomEffect:GetEffectId() return self.effectId end function ZO_ChromaCStyleCustomEffect:GetEffectType() assert(false, "You must override GetEffectType for this effect") end function ZO_ChromaCStyleCustomEffect:SetCellActive(row, column, isActive) ChromaSetCustomEffectCellActive(self:GetEffectId(), row, column, isActive) end function ZO_ChromaCStyleCustomEffect:SetDeleteEffectCallback(callback) self.deleteEffectCallback = callback end --Single Color-- ZO_ChromaCStyleCustomSingleColorEffect = ZO_ChromaCStyleCustomEffect:Subclass() function ZO_ChromaCStyleCustomSingleColorEffect:New(...) return ZO_ChromaCStyleCustomEffect.New(self, ...) end function ZO_ChromaCStyleCustomSingleColorEffect:Initialize(deviceType, drawLevel, gridStyle, animationTimerData, color, blendMode) ZO_ChromaCStyleCustomEffect.Initialize(self, deviceType, drawLevel, gridStyle, animationTimerData) ChromaSetCustomEffectSingleColorRGBA(self.effectId, color:UnpackRGBA()) ChromaSetCustomEffectSingleColorBlendMode(self.effectId, blendMode) end function ZO_ChromaCStyleCustomSingleColorEffect:GetEffectType() return CHROMA_CUSTOM_EFFECT_TYPE_SINGLE_COLOR end --Single Color Fading-- ZO_ChromaCStyleCustomSingleColorFadingEffect = ZO_ChromaCStyleCustomSingleColorEffect:Subclass() function ZO_ChromaCStyleCustomSingleColorFadingEffect:New(...) return ZO_ChromaCStyleCustomSingleColorEffect.New(self, ...) end function ZO_ChromaCStyleCustomSingleColorFadingEffect:Initialize(deviceType, drawLevel, gridStyle, animationTimerData, color, blendMode) ZO_ChromaCStyleCustomSingleColorEffect.Initialize(self, deviceType, drawLevel, gridStyle, animationTimerData, color, blendMode) assert(animationTimerData, "Please provide animation timer data for this fading effect") ChromaSetCustomSingleColorFadingEffectUsesAlphaChannel(self.effectId, animationTimerData.useAlpha) end function ZO_ChromaCStyleCustomSingleColorFadingEffect:GetEffectType() return CHROMA_CUSTOM_EFFECT_TYPE_SINGLE_COLOR_FADING end function ZO_ChromaCStyleCustomSingleColorFadingEffect:HandleAddEffect(...) ZO_ChromaEffectBaseTemplate.HandleAddEffect(self, ...) if self.animationTimerData then if not self.animationTimer then self.animationTimer = ZO_GetChromaAnimationTimer(self.animationTimerData) end if not self.animationTimer:IsPlaying() or self.animationTimerData.restartOnAdd then self.animationTimer:PlayFromStart() end self:RefreshColor() end end function ZO_ChromaCStyleCustomSingleColorFadingEffect:OnUpdate(timeMs, callbackManager) ZO_ChromaEffectBaseTemplate.OnUpdate(self, timeMs, callbackManager) if self.animationTimer then if self.animationTimer:IsPlaying() then callbackManager:MarkDirty(self.deviceType) elseif self.animationTimer:IsComplete() and self.animationTimerData.deleteOnComplete then if self.deleteEffectCallback then self.deleteEffectCallback() else ChromaDeleteCustomEffectById(self.effectId) callbackManager:RemoveEffect(self) callbackManager:MarkDirty(self.deviceType) end end self:RefreshColor() end end function ZO_ChromaCStyleCustomSingleColorFadingEffect:RefreshColor() ChromaSetCustomSingleColorFadingEffectValue(self.effectId, self:GetCurrentAnimationValue()) end function ZO_ChromaCStyleCustomSingleColorFadingEffect:GetCurrentAnimationValue() return self.animationTimer and self.animationTimer:GetValue() or 0 end --------------------- --Predefined Effect-- --------------------- ZO_ChromaPredefinedEffect = ZO_ChromaEffectBaseTemplate:Subclass() function ZO_ChromaPredefinedEffect:New(...) return ZO_ChromaEffectBaseTemplate.New(self, ...) end function ZO_ChromaPredefinedEffect:Initialize(deviceType, drawLevel, createFunction, ...) ZO_ChromaEffectBaseTemplate.Initialize(self, deviceType, drawLevel, PREDEFINED) self.createFunction = createFunction self.args = { ... } end function ZO_ChromaPredefinedEffect:FireCreateFunction() return self.createFunction(unpack(self.args)) end