myspace / CommonLua /Classes /FXPreset.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
19.9 kB
local function ActionFXTypesCombo()
local list_back = { "Inherit Action", "Inherit Moment", "Inherit Actor", "FX Remove" }
local added = { [""] = true, ["any"] = true }
for i = 1, #list_back do
added[list_back[i]] = true
end
local list = {}
ClassDescendantsList("ActionFX", function(name, class)
if not added[class.fx_type] then
list[#list+1] = class.fx_type
added[class.fx_type] = true
end
end)
table.sort(list, CmpLower)
table.insert(list, 1, "any")
for i = 1, #list_back do
list[#list+1] = list_back[i]
end
return list
end
local fx_class_list = false
function OnMsg.ClassesBuilt()
fx_class_list = {}
ClassDescendantsList("ActionFX", function(name, class)
if class.fx_type ~= "" and not class:IsKindOf("ModItem") then
fx_class_list[#fx_class_list+1] = class
end
end)
ClassDescendantsList("ActionFXInherit", function(name, class)
if class.fx_type ~= "" then
fx_class_list[#fx_class_list+1] = class
end
end)
table.sort(fx_class_list, function(c1, c2) return c1.fx_type < c2.fx_type end)
end
local function GetInheritActionFX(action)
local fxlist = FXLists.ActionFXInherit_Action or {}
if action == "any" then
return table.copy(fxlist)
end
local rules = (FXInheritRules_Actions or RebuildFXInheritActionRules())[action]
if not rules then return end
local inherit = { [action] = true}
for i = 1, #rules do
inherit[rules[i]] = true
end
local list = {}
for i = 1, #fxlist do
local fx = fxlist[i]
if inherit[fx.Action] then
list[#list+1] = fx
end
end
return list
end
local function GetInheritMomentFX(moment)
local fxlist = FXLists.ActionFXInherit_Moment or {}
if moment == "any" then
return table.copy(fxlist)
end
local rules = (FXInheritRules_Moments or RebuildFXInheritMomentRules())[moment]
if not rules then return end
local inherit = { [moment] = true}
for i = 1, #rules do
inherit[rules[i]] = true
end
local list = {}
for i = 1, #fxlist do
local fx = fxlist[i]
if inherit[fx.Moment] then
list[#list+1] = fx
end
end
return list
end
local function GetInheritActorFX(actor)
local fxlist = FXLists.ActionFXInherit_Actor or {}
if actor == "any" then
return table.copy(fxlist)
end
local rules = (FXInheritRules_Actors or RebuildFXInheritActorRules())[actor]
if not rules then return end
local inherit = { [actor] = true}
for i = 1, #rules do
inherit[rules[i]] = true
end
local list = {}
for i = 1, #fxlist do
local fx = fxlist[i]
if inherit[fx.Actor] then
list[#list+1] = fx
end
end
return list
end
if FirstLoad then
DuplicatedFX = {}
end
local function MatchActionFX(actionFXClass, actionFXMoment, actorFXClass, targetFXClass, source, game_states, fx_type, match_type, detail_level, save_in, duplicates)
local list = {}
local remove_ids
local inherit_actions = actionFXClass and (FXInheritRules_Actions or RebuildFXInheritActionRules())[actionFXClass]
local inherit_moments = actionFXMoment and (FXInheritRules_Moments or RebuildFXInheritMomentRules())[actionFXMoment]
local inherit_actors = actorFXClass and (FXInheritRules_Actors or RebuildFXInheritActorRules() )[actorFXClass]
local inherit_targets = targetFXClass and (FXInheritRules_Actors or RebuildFXInheritActorRules() )[targetFXClass]
detail_level = detail_level or 0
local i, action
if actionFXClass == "any" then
action = next(FXRules)
else
i, action = 0, actionFXClass
end
local duplicated = DuplicatedFX
while action do
local rules1 = FXRules[action]
if rules1 then
local i, moment
if actionFXMoment == "any" then
moment = next(rules1)
else
i, moment = 0, actionFXMoment
end
while moment do
local rules2 = rules1[moment]
if rules2 then
local i, actor
if actorFXClass == "any" then
actor = next(rules2)
else
i, actor = 0, actorFXClass
end
while actor do
local rules3 = actor and rules2[actor]
if rules3 then
local i, target
if targetFXClass == "any" then
target = next(rules3)
else
i, target = 0, targetFXClass
end
while target do
local rules4 = target and rules3[target]
if rules4 then
for i = 1, #rules4 do
local fx = rules4[i]
local match = not IsKindOf(fx, "ActionFX") or fx:GameStatesMatched(game_states)
match = match and (not fx_type or fx_type == "any" or fx_type == fx.fx_type)
match = match and (detail_level == 0 or detail_level == fx.DetailLevel)
match = match and (not save_in or save_in == fx.save_in)
match = match and (not duplicates or duplicated[fx])
match = match and (source == "any" or fx.Source == source)
if match then
list[fx] = true
end
end
end
if targetFXClass == "any" then
target = next(rules3, target)
else
if target == "any" or match_type == "Exact" then break end
i = i + 1
target = inherit_targets and inherit_targets[i] or match_type ~= "NoAny" and "any"
end
end
end
if actorFXClass == "any" then
actor = next(rules2, actor)
else
if actor == "any" or match_type == "Exact" then break end
i = i + 1
actor = inherit_actors and inherit_actors[i] or match_type ~= "NoAny" and "any"
end
end
end
if actionFXMoment == "any" then
moment = next(rules1, moment)
else
if moment == "any" or match_type == "Exact" then break end
i = i + 1
moment = inherit_moments and inherit_moments[i] or match_type ~= "NoAny" and "any"
end
end
end
if actionFXClass == "any" then
action = next(FXRules, action)
else
if action == "any" or match_type == "Exact" then break end
i = i + 1
action = inherit_actions and inherit_actions[i] or match_type ~= "NoAny" and "any"
end
end
return list
end
local function GetFXListForEditor(filter)
filter = filter or ActionFXFilter -- to get defaults
filter:ResetDebugFX()
if filter.Type == "Inherit Action" then
return GetInheritActionFX(filter.Action) or {}
elseif filter.Type == "Inherit Moment" then
return GetInheritMomentFX(filter.Moment) or {}
elseif filter.Type == "Inherit Actor" then
return GetInheritActorFX(filter.Actor) or {}
else
return MatchActionFX(
filter.Action, filter.Moment, filter.Actor, filter.Target, filter.Source,
filter.GameStatesFilters, filter.Type, filter.MatchType,
filter.DetailLevel, filter.SaveIn, filter.Duplicates)
end
end
if FirstLoad or ReloadForDlc then
FXLists = {}
end
DefineClass.FXPreset = {
__parents = { "Preset", "InitDone"},
properties = {
{ id = "Id", editor = false, no_edit = true, },
},
-- Preset
PresetClass = "FXPreset",
id = "",
EditorView = Untranslated("<DescribeForEditor>"),
GedEditor = "GedFXEditor",
EditorMenubarName = "FX Editor",
EditorShortcut = "Ctrl-Alt-F",
EditorMenubar = "Editors.Art",
EditorIcon = "CommonAssets/UI/Icons/atom electron molecule nuclear science.png",
FilterClass = "ActionFXFilter",
}
function FXPreset:Init()
local list = FXLists[self.class]
if not list then
list = {}
FXLists[self.class] = list
end
list[#list+1] = self
end
function FXPreset:Done()
table.remove_value(FXLists and FXLists[self.class], self)
end
function FXPreset:GetError()
if self.Source == "UI" and self.GameTime then
return "UI FXs should not be GameTime"
end
end
function FXPreset:GetPresetStatusText()
local ged = FindPresetEditor("FXPreset")
if not ged then return end
local sel = ged:ResolveObj("SelectedPreset")
if IsKindOf(sel, "GedMultiSelectAdapter") then
local count_by_type = {}
for _, fx in ipairs(sel.__objects) do
local fx_type = fx.fx_type
count_by_type[fx_type] = (count_by_type[fx_type] or 0) + 1
end
local t = {}
for _, fx_type in ipairs(ActionFXTypesCombo()) do
local count = count_by_type[fx_type]
if count then
t[#t + 1] = string.format("%d %s%s", count, fx_type, (count == 1 or fx_type:ends_with("s")) and "" or "s")
end
end
return table.concat(t, ", ") .. " selected"
end
return ""
end
function FXPreset:SortPresets()
local presets = Presets[self.PresetClass or self.class] or empty_table
table.sort(presets, function(a, b) return a[1].group < b[1].group end)
local keys = {}
for _, group in ipairs(presets) do
for _, preset in ipairs(group) do
keys[preset] = preset:DescribeForEditor()
end
end
for _, group in ipairs(presets) do
table.stable_sort(group, function(a, b)
return keys[a] < keys[b]
end)
end
ObjModified(presets)
end
function FXPreset:GetSavePath()
local folder = self:GetSaveFolder()
if not folder then return end
return string.format("%s/%s/%s.lua", folder, self.PresetClass, self.class)
end
function FXPreset:SaveAll(...)
local used_handles = {}
ForEachPresetExtended(FXPreset, function(fx)
while used_handles[fx.id] do
fx.id = fx:GenerateUniquePresetId()
end
used_handles[fx.id] = true
end)
return Preset.SaveAll(self, ...)
end
function FXPreset:GenerateUniquePresetId()
return random_encode64(48)
end
function FXPreset:OnEditorNew()
if self:IsKindOf("ActionFX") then
self:AddInRules()
elseif self.class == "ActionFXInherit_Action" then
RebuildFXInheritActionRules()
elseif self.class == "ActionFXInherit_Moment" then
RebuildFXInheritMomentRules()
elseif self.class == "ActionFXInherit_Actor" then
RebuildFXInheritActorRules()
end
end
function FXPreset:OnDataReloaded()
RebuildFXRules()
end
local function format_match(action, moment, actor, target)
return string.format("%s-%s-%s-%s", action, moment, actor, target)
end
function FXPreset:DescribeForEditor()
local str_desc = ""
local str_info = ""
local class = IsKindOf(self, "ModItem") and self.ModdedPresetClass or self.class
if class == "ActionFXParticles" then
str_desc = string.format("%s", self.Particles)
elseif class == "ActionFXUIParticles" then
str_desc = string.format("%s", self.Particles)
elseif class == "ActionFXObject" or class == "ActionFXDecal" then
str_desc = string.format("%s", self.Object)
str_info = string.format("%s", self.Animation)
elseif class == "ActionFXSound" then
str_desc = string.format("%s", self.Sound) .. (self.DistantSound ~= "" and " "..self.DistantSound or "")
elseif class == "ActionFXLight" then
local r, g, b, a = GetRGBA(self.Color)
str_desc = string.format("<color %d %d %d>%d %d %d %s</color>", r, g, b, r, g, b, a ~= 255 and tostring(a) or "")
str_info = string.format("%d", self.Intensity)
elseif class == "ActionFXRadialBlur" then
str_desc = string.format("Strength %s", self.Strength)
str_info = string.format("Duration %s", self.Duration)
elseif class == "ActionFXControllerRumble" then
str_desc = string.format("%s", self.Power)
str_info = string.format("Duration %s", self.Duration)
elseif class == "ActionFXCameraShake" then
str_desc = string.format("%s", self.Preset)
elseif class == "ActionFXInherit_Action" then
local str_match = string.format("Inherit Action: %s -> %s", self.Action, self.Inherit)
return string.format("<color blue>%s</color>", str_match)
elseif class == "ActionFXInherit_Moment" then
local str_match = string.format("Inherit Moment: %s -> %s", self.Moment, self.Inherit)
return string.format("<color blue>%s</color>", str_match)
elseif class == "ActionFXInherit_Actor" then
local str_match = string.format("Inherit Actor: %s -> %s", self.Actor, self.Inherit)
return string.format("<color blue>%s</color>", str_match)
end
if self.Source ~= "" and self.Spot ~= "" then
local space = str_info ~= "" and " " or ""
str_info = str_info .. space .. string.format("%s.%s", self.Source, self.Spot)
end
if self.Solo then
str_info = string.format("%s (Solo)", str_info)
end
local str_match = format_match(self.Action, self.Moment, self.Actor, self.Target)
local clr_match = self.Disabled and "255 0 0" or "75 105 198"
local str_preset = self.Comment ~= "" and (" <color 0 128 0>" .. self.Comment .. "</color>") or ""
if self.save_in ~= "" and self.save_in ~= "none" then
str_preset = str_preset .. " <color 128 128 128> - " .. self.save_in .. "</color>"
end
local fx_type = IsKindOf(self, "ModItem") and "" or string.format("<color 128 128 128>%s</color> ", self.fx_type)
str_desc = str_desc ~= "" and str_desc.." " or ""
if fx_type == "" and str_desc == "" and str_info == "" and (self.FxId or "") == "" then
return string.format("<color %s>%s</color>%s", clr_match, str_match, str_preset)
end
return string.format("<color %s>%s</color>%s\n%s%s<color 128 128 128>%s</color> <color 0 128 0>%s</color>", clr_match, str_match, str_preset, fx_type, str_desc, str_info, self.FxId or "")
end
function FXPreset:delete()
Preset.delete(self)
InitDone.delete(self)
end
function FXPreset:EditorContext()
local context = Preset.EditorContext(self)
table.remove_value(context.Classes, self.PresetClass)
table.remove_value(context.Classes, "ActionFX")
table.remove_value(context.Classes, "ActionFXInherit")
return context
end
-- for ValidatePresetDataIntegrity
function FXPreset:GetIdentification()
return self:DescribeForEditor():strip_tags()
end
DefineClass.ActionFXFilter = {
__parents = { "GedFilter" },
properties = {
{ id = "DebugFX", category = "Match", default = false, editor = "bool", },
{ id = "Duplicates", category = "Match", default = false, editor = "bool", help = "Works only after using the tool 'Check duplicates'!" },
{ id = "Action", category = "Match", default = "any", editor = "combo", items = function(fx) return ActionFXClassCombo(fx) end },
{ id = "Moment", category = "Match", default = "any", editor = "combo", items = function(fx) return ActionMomentFXCombo(fx) end },
{ id = "Actor", category = "Match", default = "any", editor = "combo", items = function(fx) return ActorFXClassCombo(fx) end },
{ id = "Target", category = "Match", default = "any", editor = "combo", items = function(fx) return TargetFXClassCombo(fx) end },
{ id = "Source", category = "Match", default = "any", editor = "choice", items = { "UI", "Actor", "ActorParent", "ActorOwner", "Target", "ActionPos", "Camera" } },
{ id = "SaveIn", name = "Save in", category = "Match", editor = "choice", default = false, items = function(fx)
local locs = GetDefaultSaveLocations()
table.insert(locs, 1, { text = "All", value = false })
return locs
end, },
{ id = "GameStatesFilter", name="Game State", category = "Match", editor = "set", default = set(), three_state = true,
items = function() return GetGameStateFilter() end
},
{ id = "DetailLevel", category = "Match", default = 0, editor = "combo", items = function()
local levels = table.copy(ActionFXDetailLevelCombo())
table.insert(levels, 1, {value = 0, text = "any"})
return levels
end },
{ id = "Type", category = "Match", editor = "choice", items = ActionFXTypesCombo, default = "any", buttons = {{name = "Create New", func = "CreateNew"}}},
{ id = "MatchType", category = "Match", default = "Exact", editor = "choice", items = { "All", "Exact", "NoAny" }, },
{ id = "ResetButton", category = "Match", editor = "buttons", buttons = {{name = "Reset filter", func = "ResetAction"} }, default = false },
{ id = "FxCounter", category = "Match", editor = "number", default = 0, read_only = true, },
},
fx_counter = false,
last_lists = false,
}
function ActionFXFilter:TryReset(ged, op, to_view)
if op == GedOpPresetDelete then
return
end
if to_view and #to_view == 2 and type(to_view[1]) == "table" then
-- check if the new item is hidden and only then reset the filter
local obj = ged:ResolveObj("root", table.unpack(to_view[1]))
local matched_fxs = GetFXListForEditor(self)
if not matched_fxs[obj] then
return GedFilter.TryReset(self, ged, op, to_view)
end
else
return GedFilter.TryReset(self, ged, op, to_view)
end
end
function ActionFXFilter:ResetAction(root, prop_id, ged)
if self:TryReset(ged) then
self:ResetTarget(ged)
end
end
function ActionFXFilter:CreateNew(root, prop_id, ged)
if self.Type == "any" then
print("Please specify the fx TYPE first")
return
end
local idx = table.find(fx_class_list, "fx_type", self.Type)
if idx then
local old_value = self.Type
ged:Op(nil, "GedOpNewPreset", "root", { false, fx_class_list[idx].class })
self.Type = old_value
ObjModified(self)
end
end
function ActionFXFilter:GetFxCounter()
if not self.fx_counter then
local counter = 0
for _, group in ipairs(Presets.FXPreset) do
counter = counter + #group
end
self.fx_counter = counter
end
return self.fx_counter
end
function ActionFXFilter:FilterObject(obj)
if obj:IsKindOf("ActionFXInherit") then
return
obj:IsKindOf("ActionFXInherit_Action") and (self.Action == "any" or obj.Action == self.Action or obj.Inherit == self.Action) or
obj:IsKindOf("ActionFXInherit_Moment") and (self.Moment == "any" or obj.Moment == self.Moment or obj.Inherit == self.Moment) or
obj:IsKindOf("ActionFXInherit_Actor") and (self.Actor == "any" or obj.Actor == self.Actor or obj.Inherit == self.Actor )
end
if self.last_lists then
return self.last_lists[obj]
end
return true
end
function ActionFXFilter:ResetDebugFX()
if self.DebugFX then
DebugFX = self.Actor ~= "any" and self.Actor or true
DebugFXAction = self.Action ~= "any" and self.Action or false
DebugFXMoment = self.Moment ~= "any" and self.Moment or false
DebugFXTarget = self.Target ~= "any" and self.Target or false
else
DebugFX = false
DebugFXAction = false
DebugFXMoment = false
DebugFXTarget = false
end
end
function ActionFXFilter:PrepareForFiltering()
self.last_lists = GetFXListForEditor(self)
end
function ActionFXFilter:DoneFiltering(count)
if self.fx_counter ~= count then
self.fx_counter = count
ObjModified(self)
end
end
function OnMsg.GedClosing(ged_id)
local ged = GedConnections[ged_id]
if ged.app_template == "GedFXEditor" then
local filter = ged:FindFilter("root")
filter.DebugFX = false
filter:ResetDebugFX()
end
end
function GedOpFxUseAsFilter(ged, root, sel)
local preset = root[sel[1]][sel[2]]
if preset then
local filter = ged:FindFilter("root")
filter.Action = preset.Action
filter.Moment = preset.Moment
filter.Actor = preset.Actor
filter.Target = preset.Target
filter.SaveIn = preset.SaveIn
filter:ResetTarget(ged)
end
end
function CheckForDuplicateFX()
local count = 0
local type_to_props = {}
local ignore_classes = {
ActionFXBehavior = true,
}
local ignore_props = {
id = true,
}
local duplicated = {}
DuplicatedFX = duplicated
for action_id, actions in pairs(FXRules) do
for moment_id, moments in pairs(actions) do
for actor_id, actors in pairs(moments) do
for target_id, targets in pairs(actors) do
local str_to_fx = {}
for _, fx in ipairs(targets) do
local class = fx.class
if not ignore_classes[class] then
local str = pstr(class, 1024)
local props = type_to_props[class]
if not props then
props = {}
type_to_props[class] = props
for _, prop in ipairs(g_Classes[class]:GetProperties()) do
local id = prop.id
if not ignore_props[id] then
props[#props + 1] = id
end
end
end
for _, id in ipairs(props) do
str:append("\n")
ValueToLuaCode(fx:GetProperty(id), "", str)
end
local key = tostring(str)
local prev_fx = str_to_fx[key]
if prev_fx then
GameTestsError("Duplicate FX:", fx.fx_type, action_id, moment_id, actor_id, target_id)
count = count + 1
duplicated[prev_fx] = true
duplicated[fx] = true
else
str_to_fx[key] = fx
end
end
end
end
end
end
end
GameTestsPrintf("%d duplicated FX found!", count)
return count
end
function GameTests.TestActionFX()
CheckForDuplicateFX()
end
function GedOpFxCheckDuplicates(ged, root, sel)
CheckForDuplicateFX()
end