myspace / Data /ClassDef-PresetDefs.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
199 kB
-- ========== GENERATED BY ClassDef Editor (Ctrl-Alt-F3) DO NOT EDIT MANUALLY! ==========
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/video",
DefEditorMenubar = "Combat",
DefEditorName = "Action Camera Editor",
DefHasGroups = false,
id = "ActionCameraDef",
PlaceObj('PropertyDefNumber', {
'id', "EyeZOffset",
'help', "Z offset of camera eye from attacker Groin spot",
'default', 1200,
'scale', "cm",
}),
PlaceObj('PropertyDefNumber', {
'id', "EyeBackOffset",
'help', "Offset behind the back of the attacker, vector <target, attacker>",
'default', 3000,
'scale', "m",
}),
PlaceObj('PropertyDefNumber', {
'id', "EyeAttackerOffset",
'help', "Distance between camera eye and attacker, perpendicular to attacker-target vector",
'default', 800,
'scale', "cm",
}),
PlaceObj('PropertyDefNumber', {
'id', "AttackerTargetDistParam",
'help', "Parameter used to determine offsets LookAtTargetOffset and LookAtZOffset",
'default', 20000,
'scale', "m",
}),
PlaceObj('PropertyDefNumber', {
'id', "LookAtTargetOffset",
'help', "Distance between camera LookAt and target for <AttackerTargetDistParam> attacker-target distance, perpendicular to attacker-target vector",
'default', 4200,
'scale', "cm",
}),
PlaceObj('PropertyDefNumber', {
'id', "LookAtZOffset",
'help', "Z offset of camera lookat from target Groin spot",
'default', -1000,
'scale', "cm",
}),
PlaceObj('PropertyDefNumber', {
'id', "FovX",
'help', "Horizontal field of view angle in action camera mode",
'default', 2400,
'scale', "deg",
}),
PlaceObj('PropertyDefNumber', {
'id', "FloatSphereRadius",
'help', 'The camera eye "floats" between random points from the sphere surface',
'default', 50,
'scale', "cm",
}),
PlaceObj('PropertyDefNumber', {
'id', "FloatInterpolationTime",
'help', "Time for moving camera between two points from the float sphere surface",
'default', 1200,
}),
PlaceObj('PropertyDefCombo', {
'id', "FloatEasing",
'help', "Float interpolation uses this easing",
'default', 7,
'items', function (self) return const.EasingCombo end,
}),
PlaceObj('PropertyDefCombo', {
'id', "HidingMode",
'name', "Object Hiding Mode",
'help', "CMT is the system that hides tree tops, walls etc.",
'default', "NoCMT",
'items', function (self) return ActionCameraHidingModeCombo end,
}),
PlaceObj('PropertyDefButtons', {
'id', "btn_test",
'dont_save', true,
'read_only', true,
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Test",
'FuncName', "ExecTestActionCamera",
}),
},
}),
PlaceObj('PropertyDefBool', {
'category', "Stances",
'id', "Standing",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "NoRotate",
'name', "NoRotate",
}),
PlaceObj('PropertyDefBool', {
'category', "Stances",
'id', "Crouch",
'name', "Crouched",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Stances",
'id', "Prone",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Stances",
'id', "CoverLow",
'name', "Low Cover",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Stances",
'id', "CoverHigh",
'name', "High Cover",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "SetPieceOnly",
'name', "Setpiece only",
'help', "Can only be used in setpieces, never chosen in gameplay",
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFStrengthNear",
'name', "Strength Near",
'default', 0,
'slider', true,
'min', 0,
'max', 1000,
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFStrengthFar",
'name', "Strength Far",
'default', 0,
'slider', true,
'min', 0,
'max', 1000,
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFNear",
'name', "Scaling Near Dist",
'help', "in promiles, 0 = camera, 1000 = attacker(dist to camera), 2000 = enemy(dist to camera + attacker dist)",
'default', 800,
'slider', true,
'min', 0,
'max', 2500,
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFFar",
'name', "Scaling Far Dist",
'help', "in promiles, 0 = camera, 1000 = attacker(dist to camera), 2000 = enemy(dist to camera+attacker dist)",
'default', 2000,
'slider', true,
'min', 0,
'max', 2500,
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFNearSpread",
'name', "Spread Near",
'help', "%",
'default', 150,
'scale', 1000,
'slider', true,
'min', 0,
'max', 2000,
}),
PlaceObj('PropertyDefNumber', {
'category', "DOF Settings",
'id', "DOFFarSpread",
'name', "Spread Far",
'help', "%",
'default', 150,
'scale', 1000,
'slider', true,
'min', 0,
'max', 2000,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
local props = {"DOFStrengthNear", "DOFStrengthFar", "DOFNear", "DOFFar"}
if table.find(props, prop_id) then
self:SetDOFParams(0)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "SetDOFParams",
'params', "time, attacker, target, camera_pos",
'code', function (self, time, attacker, target, camera_pos)
attacker = attacker or MapGetFirst("map", "ActionCameraTestDummy_Player")
target = target or MapGetFirst("map", "ActionCameraTestDummy_Enemy")
if not attacker or not target then
CreateMessageBox(nil, T(634182240966, "Error"), T(626828916856, "ActionCameraTestDummy_Player or ActionCameraTestDummy_Target do not exist on the map"))
return
end
if not IsPoint(attacker) then
local headSpotIdx = attacker:GetSpotBeginIndex("Head")
attacker = headSpotIdx and headSpotIdx ~= -1 and attacker:GetSpotLoc(headSpotIdx) or attacker:GetVisualPos()
end
if not IsPoint(target) then
local headSpotIdx = target:GetSpotBeginIndex("Head")
target = headSpotIdx and headSpotIdx ~= -1 and target:GetSpotLoc(headSpotIdx) or target:GetVisualPos()
end
camera_pos = camera_pos or camera.GetPos()
hr.EnablePostProcDOF = 1
local function CalcGUIM_Distance(value_0_2000)
local attacker_distance = (attacker - camera_pos):Len()
local target_distance = (target - camera_pos):Len() + 1000
if value_0_2000 <= 1000 then
return MulDivRound(value_0_2000, attacker_distance, 1000)
else
local attacker_to_target = abs(target_distance - attacker_distance)
return attacker_distance + MulDivRound(value_0_2000 - 1000, attacker_to_target, 1000)
end
end
local near_distance = CalcGUIM_Distance(self.DOFNear)
local far_distance = CalcGUIM_Distance(self.DOFFar)
local defocus_near = MulDivRound(near_distance, self.DOFNearSpread, 1000)
local defocus_far = MulDivRound(far_distance, self.DOFFarSpread, 1000)
SetDOFParams(self.DOFStrengthNear, near_distance - defocus_near, near_distance,
self.DOFStrengthFar, far_distance, far_distance + defocus_far, 0)
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "AnimationStyles",
id = "AnimationStyle",
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "Unit",
'items', function (self) return GetAnimationStyleUnits() end,
}),
PlaceObj('PropertyDefText', {
'category', "Animations",
'id', "VariationGroup",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Animations",
'id', "Name",
'translate', false,
}),
PlaceObj('PropertyDefSet', {
'category', "Conditions",
'id', "GameStates",
'items', function (self) return GetGameStateFilter() end,
'three_state', true,
}),
PlaceObj('PropertyDefNumber', {
'category', "Conditions",
'id', "Weight",
'default', 100,
'min', 0,
'max', 1000000,
}),
PlaceObj('PropertyDefFunc', {
'category', "Conditions",
'id', "CanPlay",
'params', "self, unit",
'default', function (self, unit)
return true
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetRandomAnimId",
'params', "id, unit",
'code', function (self, id, unit)
local animations = self[id]
local count = animations and #animations or 0
local total_weight = count > 0 and animations[count].total_weight or 0
if total_weight == 0 then
return
end
local idx
if count > 1 then
local roll = unit:Random(total_weight)
idx = GetRandomItemByWeight(animations, roll, "total_weight")
end
return animations[idx or 1].Animation
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetMainAnimId",
'params', "id",
'code', function (self, id)
local best_weight, best_anim = 0
for _, anim in ipairs(self[id]) do
if anim.Weight > best_weight then
best_anim = anim.Animation
end
end
return best_anim
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateTotalWeight",
'params', "id",
'code', function (self, id)
local total_weight = 0
for _, data in ipairs(self[id]) do
if data.Animation then
total_weight = total_weight + data.Weight
end
data.total_weight = total_weight
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "AnimationsCombo",
'code', function (self)
local entity = GetAnimationStyleUnitEntity(self.Unit)
if not entity then return end
local states = GetStates(entity)
for i = #states, 1, -1 do
local state = states[i]
if string.starts_with(state, "_") or IsErrorState(entity, GetStateIdx(state)) then
table.remove(states, i)
end
end
table.sort(states)
return states
end,
}),
PlaceObj('ClassMethodDef', {
'name', "SetUnit",
'params', "value",
'code', function (self, value)
self.Unit = value
self:GenerateUniqueStyleId()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "SetVariationGroup",
'params', "value",
'code', function (self, value)
self.VariationGroup = value
self:GenerateUniqueStyleId()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "SetName",
'params', "value",
'code', function (self, value)
self.Name = value
self:GenerateUniqueStyleId()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateUniqueStyleId",
'code', function (self)
if self.group ~= "AmbientLifeMarker - WIP - DON'T USE" then
self:SetGroup(string.format("%s: %s", self.Unit, self.VariationGroup))
end
local name = string.format("%s: %s", self.Unit, self.Name)
self.id = self:GenerateUniquePresetId(name)
if self.id ~= name then
self.Name = string.sub(self.id, #self.Unit + 2)
end
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "GetAnimationStyleCombo(set, class)",
'code', function ()
function GetAnimationStyleCombo(set, class)
local items = {}
local insert = table.insert_unique
for k, variations in ipairs(Presets.AnimationStyle) do
for i, style in ipairs(variations) do
if (not set or style.Unit == set) and (not class or style.class == class) then
insert(items, style.Name)
end
end
end
table.sort(items)
table.insert(items, 1, "")
return items
end
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "GetAnimationStyle(unit, name)",
'code', function ()
function GetAnimationStyle(unit, name)
if name and name ~= "" then
local set = unit:GetAnimationStyleUnit()
local id = set and string.format("%s: %s", set, name)
return AnimationStyles[id]
end
end
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "GetRandomAnimationStyle(unit, variation_group)",
'code', function ()
function GetRandomAnimationStyle(unit, variation_group)
local set = unit:GetAnimationStyleUnit()
local groupname = string.format("%s: %s", set, variation_group)
local list = Presets.AnimationStyle[groupname]
local total_weight = 0
for i, entry in ipairs(list) do
if entry:CanPlay(unit) and MatchGameState(entry.GameStates) then
total_weight = total_weight + entry.Weight
end
end
if total_weight == 0 then
return
end
local style = list[1]
if #list > 1 then
local roll = unit:Random(total_weight)
for i, entry in ipairs(list) do
if entry:CanPlay(unit) and MatchGameState(entry.GameStates) then
roll = roll - entry.Weight
if roll < 0 then
style = entry
break
end
end
end
end
return style
end
end,
}),
PlaceObj('PropertyDefText', {
'id', "EditorView",
'no_edit', true,
'default', T(951373618311, --[[PresetDef AnimationStyle default]] "<Name> <color 45 138 138>(Weight: <Weight>)"),
}),
PlaceObj('PropertyDefText', {
'category', "Preset",
'id', "Id",
'read_only', true,
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Preset",
'id', "Group",
'read_only', true,
'translate', false,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "AnimationStyleAnim",
PlaceObj('PropertyDefCombo', {
'id', "Animation",
'items', function (self)
local obj = GetParentTableOfKind(self, "AnimationStyle")
if not obj then return end
return obj:AnimationsCombo()
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "Weight",
'default', 100,
'min', 0,
'max', 1000000,
}),
PlaceObj('PropertyDefNumber', {
'id', "total_weight",
'help', "Hidden value. It allows binary search to speed up random choice.",
'no_edit', true,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/chat comment review text",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "3000",
DefEditorName = "Banters",
DefGedEditor = "BanterEditor",
DefGlobalMap = "Banters",
DefModItem = true,
DefModItemName = "Banter",
DefModItemSubmenu = "Campaign & Maps",
DefParentClassList = {
"Preset",
"CampaignSpecific",
},
id = "BanterDef",
PlaceObj('PropertyDefText', {
'id', "Id",
'translate', false,
}),
PlaceObj('PropertyDefButtons', {
'id', "banterDebug",
'name', "Debug",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Why Is This Banter Not Playing?",
'FuncName', "DebugSpecificBanter",
}),
},
}),
PlaceObj('PropertyDefBool', {
'id', "loggable",
'name', "Log",
'help', "Whether to log banter lines.",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "FilePerGroup",
'name', "FilePerGroup",
'extra_code', 'default = "BantersDef"',
}),
PlaceObj('PropertyDefBool', {
'id', "SingleFile",
'name', "SingleFile",
}),
PlaceObj('PropertyDefBool', {
'id', "isRadio",
'name', "Radio",
}),
PlaceObj('PropertyDefBool', {
'id', "Once",
'name', "OncePerCampaign",
}),
PlaceObj('PropertyDefText', {
'id', "banterGroup",
'name', "Interrupt Association Id",
'help', "Banter's of the same interrupt id will interrupt each other. Banters interrupt actors playing other banters by default.",
'translate', false,
}),
PlaceObj('PropertyDefNumber', {
'id', "cooldown",
'name', "Cooldown",
'help', "Banter cooldown - if the banter is on cooldown it won't play",
}),
PlaceObj('PropertyDefBool', {
'id', "disabledInConflict",
'name', "Do not play during conflict",
'help', "Disable banter while in conflict. NotNow VR plays if no other is available.",
}),
PlaceObj('PropertyDefBool', {
'id', "KillOnAnyActorAware",
'name', "Kill On Combat Start",
'help', "Kill if any actor becomes aware",
}),
PlaceObj('PropertyDefCombo', {
'id', "FX",
'name', "FX",
'items', function (self) return BanterFXCombo end,
}),
PlaceObj('PropertyDefNestedList', {
'id', "conditions",
'name', "Conditions",
'help', "The banter is only playable if all conditions are met.",
'base_class', "Condition",
}),
PlaceObj('PropertyDefNestedList', {
'id', "Lines",
'base_class', "BanterLine",
'inclusive', true,
}),
PlaceObj('PropertyDefFunc', {
'id', "OnEditorSetProperty",
'no_edit', true,
'default', function (self)
if self.group == "MercBanters" and not self.cooldown then
self.cooldown = 2629746000 -- One month default cooldown
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'code', function (self)
for i, l in ipairs(self.Lines) do
if l.MultipleTexts and l.Text and l.Text ~= "" then
l.Text = false
end
if l.MultipleTexts and l.Character then
l.Character = "any"
end
end
end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Creates a new banter preset that is played between a defined set of actors. See the New Quest sample mod in the Sample Mods section for an example on how to build a banter.",
}),
})
PlaceObj('PresetDef', {
DefHasSortKey = true,
DefModItemName = "BobbyRayShopCategory mod",
DefModItemSubmenu = "Item",
DefStoreAsTable = "inherit",
group = "PresetDefs",
id = "BobbyRayShopCategory",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
}),
PlaceObj('PropertyDefText', {
'id', "UrlSuffix",
'translate', false,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetSubCategories",
'name', "",
}),
PlaceObj('PropertyDefFunc', {
'id', "BelongsInCategory",
'params', "self, item",
'default', function (self, item)
return item:GetCategory() == self
end,
}),
})
PlaceObj('PresetDef', {
DefHasGroups = false,
DefHasSortKey = true,
DefModItemName = "BobbyRayShopCategory mod",
DefModItemSubmenu = "Item",
DefStoreAsTable = "inherit",
group = "PresetDefs",
id = "BobbyRayShopDeliveryDef",
PlaceObj('PropertyDefNumber', {
'id', "MinTime",
'help', "in days",
}),
PlaceObj('PropertyDefNumber', {
'id', "MaxTime",
'help', "in days",
}),
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('PropertyDefText', {
'id', "TimeDescription",
'name', "",
}),
PlaceObj('PropertyDefNumber', {
'id', "Price",
}),
})
PlaceObj('PresetDef', {
DefHasSortKey = true,
DefModItemName = "BobbyRayShopSubCategory mod",
DefModItemSubmenu = "Item",
DefStoreAsTable = "inherit",
group = "PresetDefs",
id = "BobbyRayShopSubCategory",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
}),
PlaceObj('PropertyDefCombo', {
'id', "Category",
'template', true,
'default', "Other",
'items', function (self) return PresetArray("BobbyRayShopCategory") end,
}),
PlaceObj('PropertyDefFunc', {
'id', "BelongsInSubCategory",
'params', "self, item",
'default', function (self, item)
return item:GetSubCategory() == self
end,
}),
})
PlaceObj('PresetDef', {
DefModItem = true,
DefModItemName = "Caliber mod",
DefModItemSubmenu = "Item",
DefParentClassList = {
"ListPreset",
},
id = "Caliber",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('PropertyDefNumber', {
'id', "ImpactForce",
'help', "impact force modifier",
'default', 0,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Defines a new caliber type that an inventory item of type Ammo could use.",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/chart map paper sheet travel.png",
DefEditorMenubar = "Scripting",
DefEditorName = "Campaign",
DefGlobalMap = "CampaignPresets",
id = "CampaignPreset",
PlaceObj('PropertyDefPoint', {
'category', "Satellite Settings",
'id', "sectors_offset",
'name', "Sectors offset",
'default', point(0, 0, 0),
}),
PlaceObj('PropertyDefPoint', {
'category', "Satellite Settings",
'id', "sector_size",
'name', "Sector size",
'read_only', true,
'default', point(356, 356),
}),
PlaceObj('PropertyDefPoint', {
'category', "Satellite Settings",
'id', "map_size",
'name', "Map size",
'default', point(0, 0),
}),
PlaceObj('PropertyDefText', {
'category', "Preset",
'id', "DisplayName",
'name', "Display name",
}),
PlaceObj('PropertyDefUIImage', {
'category', "Satellite Settings",
'id', "map_file",
'name', "Map image",
}),
PlaceObj('PropertyDefUIImage', {
'category', "Satellite Settings",
'id', "underground_file",
'name', "Underground map image",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Satellite Settings",
'id', "decorations",
'name', "Custom images on map",
'base_class', "SatelliteViewDecorationDef",
}),
PlaceObj('PropertyDefText', {
'category', "Preset",
'id', "Description",
'name', "Description",
'default', "",
}),
PlaceObj('ClassConstDef', {
'name', "editing_size",
}),
PlaceObj('PropertyDefChoice', {
'category', "Map Size & Sectors",
'id', "InheritSectorsFrom",
'name', "Inherit sectors from",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return self.save_in == "" or IsKindOf(self, "ModItem") end,
'no_validate', true,
'items', function (self)
-- can inherit the sectors from any CampaignPreset with the save id in the base game, or another DLC
local ret = { { text = "", value = false } }
ForEachPresetExtended("CampaignPreset", function(preset)
if preset.id == self.id and preset.save_in ~= self.save_in then
table.insert(ret, { text = preset.save_in ~= "" and preset.save_in or "<base game>", value = preset.save_in })
end
end)
return ret
end,
}),
PlaceObj('PropertyDefText', {
'category', "Map Size & Sectors",
'id', "sector_topleft",
'name', "Top-left sector",
'read_only', "expression",
'read_only_expression', function (self, prop_meta) return next(self.Sectors or empty_table) and not self.editing_size end,
'validate', function (self, value) return ValidateSectorId(value) end,
'default', "A1",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Map Size & Sectors",
'id', "sector_bottomright",
'name', "Bottom-right sector",
'read_only', "sector_topleft.read_only",
'validate', function (self, value) return ValidateSectorId(value) end,
'default', "A1",
'translate', false,
}),
PlaceObj('PropertyDefButtons', {
'category', "Map Size & Sectors",
'id', "size_btns",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Edit range of defined sectors",
'FuncName', "EditSize",
'IsHidden', function (self) return self.editing_size end,
}),
PlaceObj('PropertyDefPropButton', {
'Name', "Confirm new size",
'FuncName', "UpdateSize",
'IsHidden', function (self) return not self.editing_size end,
}),
},
}),
PlaceObj('ClassMethodDef', {
'name', "EditSize",
'params', "root, prop_id, ged",
'code', function (self, root, prop_id, ged)
self.editing_size = true
CreateRealTimeThread(function()
Sleep(100)
ged:Send("rfnApp", "FocusProperty", "SelectedObject", "sector_topleft")
end)
ObjModified(self)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "ValidateSize",
'code', function (self)
local x1, y1 = sector_unpack(self.sector_topleft)
local x2, y2 = sector_unpack(self.sector_bottomright)
if x2 < x1 or y2 < y1 then
self.sector_bottomright = self.sector_topleft
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "UpdateSize",
'code', function (self)
self:ValidateSize()
self:PostLoad()
ObjModified(self.Sectors)
ObjModified(self)
end,
}),
PlaceObj('PropertyDefText', {
'category', "Map Size & Sectors",
'id', "SectorRange",
'name', "Sector range",
'help', "Total range of sectors",
'dont_save', true,
'read_only', true,
'translate', false,
}),
PlaceObj('ClassMethodDef', {
'name', "GetSectorRange",
'code', function (self)
local x1, y1 = self.sector_rowsstart, 1
local x2, y2 = self.sector_rows, self.sector_columns
return string.format("%s-%s", sector_pack(x1, y1), sector_pack(x2, y2))
end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Map Size & Sectors",
'id', "sector_columns",
'name', "Sector columns",
'dont_save', true,
'read_only', true,
'default', 1,
}),
PlaceObj('PropertyDefNumber', {
'category', "Map Size & Sectors",
'id', "sector_rowsstart",
'name', "Sector rows start",
'dont_save', true,
'read_only', true,
'default', 1,
}),
PlaceObj('PropertyDefNumber', {
'category', "Map Size & Sectors",
'id', "sector_rows",
'name', "Sector rows end",
'dont_save', true,
'read_only', true,
'default', 1,
}),
PlaceObj('PropertyDefText', {
'category', "Map Size & Sectors",
'id', "InitialSector",
'name', "Initial sector",
'help', "The sector in which the campaign starts",
'validate', function (self, value)
local err = ValidateSectorId(value)
if err then return err end
local x, y = sector_unpack(value)
if x < self.sector_rowsstart or x > self.sector_rows or y < 1 or y > self.sector_columns then
return "The starting sector is not withing the map boundaries."
end
end,
'default', "A1",
'translate', false,
}),
PlaceObj('PropertyDefButtons', {
'category', "Map Size & Sectors",
'id', "map_editor_btn",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Edit sectors for current Game's campaign",
'FuncName', "OpenGedSatelliteSectorEditor",
'IsHidden', function (self) return not Game or not next(gv_Sectors) end,
}),
},
}),
PlaceObj('PropertyDefNestedList', {
'id', "Cities",
'base_class', "CampaignCity",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Sectors",
'no_edit', true,
'no_validate', true,
'base_class', "SatelliteSector",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'id', "EffectsOnStart",
'name', "Effects on campaign start",
'help', "Effects that are executed when the campaign is started.",
'base_class', "Effect",
'inclusive', true,
}),
PlaceObj('ClassConstDef', {
'name', "EnableReloading",
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
if ged and prop_id:starts_with("starting") then
self.starting_timestamp = os.time {
year = self.starting_year,
month = self.starting_month,
day = self.starting_day,
hour = self.starting_hour
}
end
if prop_id == "InheritSectorsFrom" then
self:PostLoad()
ObjModified(self.Sectors)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorNew",
'params', "parent, ged, is_paste",
'code', function (self, parent, ged, is_paste)
if not is_paste then
self.starting_timestamp = os.time {
year = self.starting_year,
month = self.starting_month,
day = self.starting_day,
hour = self.starting_hour
}
end
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "Initialize",
'help', "Called once when the campaign starts for the first time.",
'default', function (self)
RevealAllSectors()
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "FirstRunInterface",
'help', "Called after initialize, setups the initial interface.",
'params', "self, interfaceType",
'default', function (self, interfaceType)
--used for debugging
if interfaceType == "QuickStart" then
TutorialHintsState.LandingPageShown = true
Game.CampaignTime = Game.CampaignTimeStart + const.Satellite.MercArrivalTime / 2
SetUILCustomTime(Game.CampaignTime)
return
end
SetCampaignSpeed(0, "UI")
g_PDALoadingFlavor = false
if not gv_SatelliteView then OpenSatelliteView(nil, "openLandingPage") end
OpenAIMAndSelectMerc()
g_PDALoadingFlavor = true
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnStartCampaign",
'params', "...",
'code', function (self, ...)
ExecuteEffectList(self.EffectsOnStart, self)
self:Initialize(...)
self:FirstRunInterface(...)
Game.CampaignStarted = true
Msg("CampaignStarted", self.id)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "FindInheritSectorsPreset",
'params', "current",
'code', function (self, current)
local parent
ForEachPresetExtended("CampaignPreset", function(preset)
if preset.id == self.id and preset.save_in == current.InheritSectorsFrom then
parent = preset
end
end)
return parent
end,
}),
PlaceObj('ClassMethodDef', {
'name', "RoundOutSectors",
'comment', "Inherited sectors for DLC campaign extension, add empty sectors at each point within the map where a sector doesn't exist",
'code', function (self)
self.Sectors = self.Sectors or {}
-- calculate bounding box of all sectors into 'bbox'
local bbox = box(
point(sector_unpack(self.sector_topleft)),
point(sector_unpack(self.sector_bottomright)) + point(1, 1)
)
-- build inheritance list (of campaign presets, by order of inheritance)
local parents, current = { self }, self
local sector_by_id = {}
repeat
-- create id to sector map for each campaign preset
local sectors = {}
for _, sector in ipairs(current.Sectors) do
local x, y = sector_unpack(sector.Id)
bbox = Extend(bbox, point(x, y))
sectors[sector.Id] = sector
end
sector_by_id[current] = sectors
current = self:FindInheritSectorsPreset(current)
if current then
if table.find(parents, current) then break end -- prevent infinite loop in case of a cycle
table.insert(parents, current)
end
until not current
-- update size properties, according to the total bounding box
self.sector_rowsstart = bbox:minx()
self.sector_rows = bbox:maxx() - 1
self.sector_columns = bbox:maxy() - 1
-- perform sector inheritance
local function inherit_sector(sector_id)
for _, campaign_preset in ipairs(parents) do
local sector = sector_by_id[campaign_preset][sector_id]
if sector then
if campaign_preset ~= self then
sector = sector:Clone()
sector.inherited = true
table.insert(self.Sectors, sector)
UpdateParentTable(sector, self.Sectors)
end
return true
end
end
end
for y = 1, self.sector_columns do
for x = self.sector_rowsstart, self.sector_rows do
local sector_id = sector_pack(x, y)
if not inherit_sector(sector_id) then -- no sector at that point
local sector = GenerateEmptySector(sector_id)
table.insert(self.Sectors, sector)
UpdateParentTable(sector, self.Sectors)
end
inherit_sector(sector_id .. "_Underground")
end
end
table.sortby_field(self.Sectors, "Id")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "RemoveGeneratedSectors",
'comment', "Remove generated & inherited sectors added by RoundOutSectors",
'code', function (self)
local sectors = self.Sectors or {}
for idx = #sectors, 1, -1 do
if sectors[idx].generated or sectors[idx].inherited then
table.remove(sectors, idx)
end
end
self.editing_size = nil
end,
}),
PlaceObj('ClassMethodDef', {
'name', "PostLoad",
'comment', "Add generated sectors",
'code', function (self)
self:RemoveGeneratedSectors()
self:RoundOutSectors()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'comment', "Remove generated sectors",
'code', function (self)
self:ValidateSize()
self:RemoveGeneratedSectors()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPostSave",
'comment', "Add back generated sectors",
'code', function (self)
self:RoundOutSectors()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
if self.InheritSectorsFrom and not self:FindInheritSectorsPreset(self) then
return "Unable to find DLC to inherit sectors from."
end
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "starting_year",
'name', "Starting date, year",
'default', 2001,
}),
PlaceObj('PropertyDefNumber', {
'id', "starting_month",
'name', "Starting date, month, 1-12",
'default', 4,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Creates a new campaign which you can associate with new sectors, quests, conversations, banters and many more features.",
}),
PlaceObj('ClassConstDef', {
'name', "DocumentationLink",
'type', "text",
'value', "Docs/ModTools/index.md.html",
}),
PlaceObj('PropertyDefNumber', {
'id', "starting_day",
'name', "Starting date, day, 1-31",
'default', 1,
}),
PlaceObj('PropertyDefNumber', {
'id', "starting_hour",
'name', "Starting date, hour, 0-23",
'help', "Enter local time and it will be converted to GMT; if you want the campaign to start at 06:00 and you're in GMT+02 (Sofia winter), enter 8",
'default', 8,
}),
PlaceObj('PropertyDefNumber', {
'id', "starting_timestamp",
'name', "Starting time",
'read_only', true,
'default', 0,
}),
PlaceObj('PropertyDefText', {
'id', "DisclaimerOnStart",
'name', "Disclaimer on start",
'lines', 2,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/bullseye focus goal target.png",
DefEditorMenubar = "Combat",
DefHasParameters = true,
id = "ChanceToHitModifier",
PlaceObj('PropertyDefText', {
'id', "display_name",
'name', "Display Name",
}),
PlaceObj('PropertyDefBool', {
'id', "RequireTarget",
'name', "Require Target",
}),
PlaceObj('PropertyDefChoice', {
'id', "RequireActionType",
'name', "Require Action Type",
'default', "Any Attack",
'items', function (self) return CombatActionAttacksCombo end,
}),
PlaceObj('PropertyDefFunc', {
'id', "CalcValue",
'params', "self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/focus goal marketing target.png",
DefEditorMenubar = "Combat",
DefEditorMenubarSortKey = "-9",
DefEditorName = "Combat Actions",
DefGlobalMap = "CombatActions",
DefHasParameters = true,
DefHasSortKey = true,
id = "CombatAction",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
'name', "DisplayName",
}),
PlaceObj('PropertyDefText', {
'id', "DisplayNameShort",
'name', "DisplayNameShort",
'help', "Shortened display name. Used for firing modes and such.",
}),
PlaceObj('PropertyDefText', {
'id', "Description",
'name', "Description",
'lines', 1,
'max_lines', 5,
}),
PlaceObj('PropertyDefBool', {
'id', "basicAttack",
'name', "Basic Attack",
}),
PlaceObj('PropertyDefBool', {
'id', "CostBasedOnWeapon",
'name', "Cost based on weapon",
}),
PlaceObj('PropertyDefNumber', {
'id', "ActionPoints",
'extra_code', "no_edit = function(self) return self.CostBasedOnWeapon end",
'default', 0,
'scale', "AP",
}),
PlaceObj('PropertyDefNumber', {
'id', "ActionPointDelta",
'extra_code', "no_edit = function(self) return not self.CostBasedOnWeapon end",
'default', 0,
'scale', "AP",
}),
PlaceObj('PropertyDefBool', {
'id', "SimultaneousPlay",
'name', "Can play simultaneously with other units",
}),
PlaceObj('PropertyDefBool', {
'id', "LocalChoiceAction",
'name', "Can play in the co-op unit move",
'help', "Used for interactions that opens local dialog (looting). Such actions do not wait the other units order to finish first",
}),
PlaceObj('PropertyDefBool', {
'id', "DisableAimAnim",
'name', "No Aim Animation",
'help', "If checked the unit wont play aim animations",
}),
PlaceObj('PropertyDefBool', {
'id', "InterruptInExploration",
'name', "Interrupt Action in Exploration",
}),
PlaceObj('PropertyDefBool', {
'id', "IsTargetableAttack",
'name', "Is Targetable Attack",
'help', "Melee and AOE attacks marked with this will allow the user to choose a body part to attack. Single target attacks marked with this allow for aiming *and* choosing body parts (otherwise the crosshair will open, but the only option will be the default body part)",
}),
PlaceObj('PropertyDefBool', {
'id', "IsAimableAttack",
'name', "Is Aimable Attack",
'help', "Whether the attack can be aimed. Only works if the attack also triggers the crosshair (is a single attack or AOE attack set as Targetable)",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "StealthAttack",
'name', "Stealth Attack",
'help', "Whether the attack can be executed as a Stealth Attack. Stealth Attacks have a chance to kill non-Lieutenant enemies instantly and have increased Critical Chance against Lieutenants.",
}),
PlaceObj('PropertyDefBool', {
'id', "MoveStep",
'name', "Move Before Targeting",
'help', "Whether the attack has an incorporated optional move step before targeting, allowing the player to try out different positions before attacking.",
}),
PlaceObj('PropertyDefBool', {
'id', "UseFreeMove",
'name', "Use Free Move",
'help', "Whether the action uses AP provided by the Free Move status",
}),
PlaceObj('PropertyDefBool', {
'id', "AlwaysHits",
'name', "Always Hits",
'help', "Whether the attack always hits (skips CtH)",
}),
PlaceObj('PropertyDefBool', {
'id', "DontShowWith",
'name', "Dont Show With in Badge",
'help', 'Whether to show "With" text in interactables when multiple units are to perform this action.',
}),
PlaceObj('PropertyDefChoice', {
'id', "RequireState",
'name', "Require State",
'help', "What gamestate this action requires to be displayed to the player.",
'default', "combat",
'items', function (self) return { "any", "combat", "exploration" } end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'params', "by_user_request, ged",
'code', function (self, by_user_request, ged)
self.IdDefault = self.id .. "default"
Preset.OnPreSave(self, by_user_request, ged)
end,
}),
PlaceObj('PropertyDefChoice', {
'id', "MultiSelectBehavior",
'name', "Multi-Select Behavior",
'help', "What happens when multiple units are selected in exploration mode and the action is executed.",
'default', "all",
'items', function (self) return { "all", "hidden", "nearest", "first" } end,
}),
PlaceObj('PropertyDefBool', {
'id', "RequireTargets",
'name', "Require Targets",
'help', "If the action can only be used if a valid target is present.",
}),
PlaceObj('PropertyDefBool', {
'id', "RequireWeapon",
'name', "Require Weapon",
'help', "If the action requires a weapon to be displayed to the player.",
}),
PlaceObj('PropertyDefBool', {
'id', "ActionCamera",
}),
PlaceObj('PropertyDefBool', {
'id', "InteractionLoadingBar",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
'default', "UI/Icons/Hud/placeholder.dds",
}),
PlaceObj('PropertyDefUIImage', {
'id', "IconFiringMode",
'default', "UI/Hud/fire_mode_button",
}),
PlaceObj('PropertyDefChoice', {
'id', "ShowIn",
'default', "CombatActions",
'items', function (self) return {false, "CombatActions", "Stances", "Special", "SignatureAbilities"} end,
}),
PlaceObj('PropertyDefChoice', {
'id', "ActionType",
'name', "Action Type",
'default', "Other",
'items', function (self) return {"Melee Attack", "Ranged Attack", "Other", "Passive", "Toggle"} end,
}),
PlaceObj('PropertyDefChoice', {
'id', "AimType",
'name', "Aim Type",
'default', "none",
'items', function (self) return {"none", "line", "cone", "mobile", "melee", "melee-charge", "parabola aoe", "line aoe", "allies-attack"} end,
}),
PlaceObj('PropertyDefChoice', {
'id', "ActivePauseBehavior",
'default', "unpause",
'items', function (self) return {"unpause", "queue", "instant"} end,
}),
PlaceObj('PropertyDefText', {
'id', "QueuedBadgeText",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return self.ActivePauseBehavior ~= "queue" end,
'template', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Keybindings",
'id', "ConfigurableKeybind",
'default', true,
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "ActionShortcut",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "ActionShortcutDev",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "KeybindingFromAction",
'translate', false,
}),
PlaceObj('PropertyDefPresetId', {
'id', "FiringModeMember",
'name', "Member of Firing Mode",
'preset_class', "CombatAction",
'preset_group', "FiringModeMetaAction",
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "ActionShortcut2",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "ActionGamepad",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'category', "Keybindings",
'id', "KeybindingSortId",
'default', "2500",
'translate', false,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetUIState",
'help', 'Returns if the CombatAction is available for execution. Possible values: "enabled", "disabled", "hidden".',
'params', "self, units, args",
'default', function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost, self.id, args) then
return "disabled", AttackDisableReasons.NoAP
end
return "enabled"
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetVisibility",
'no_edit', true,
'params', "self, units, target",
'default', function (self, units, target)
if gv_Deployment then return "hidden" end
local real_action = self:ResolveAction(units)
if not real_action then return "hidden" end
self = real_action
--check game state
if self.RequireState == "combat" and not g_Combat then return "hidden" end
if self.RequireState == "exploration" and g_Combat then return "hidden" end
if #units > 1 and self.MultiSelectBehavior == "hidden" then return "hidden" end
--check weapon
if not units[1] or self.RequireWeapon and not self:GetAttackWeapons(units[1]) then
return "hidden"
end
-- check availability first so that we don't end up disabled when GetUIState says hidden
local state, reason = self:GetUIState(units, { target = target })
if state == "enabled" or (state ~= "hidden" and not reason) then
--check targets
if self.RequireTargets and (not IsValid(target) and not IsPoint(target)) and not self:GetAnyTarget(units) then
return "disabled", AttackDisableReasons.NoTarget
end
end
--check availability
--return self:GetUIState(units, { target = target })
return state, reason
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetTargets",
'help', "Generates an array of possible targets.",
'params', "self, units",
'default', function (self, units)
return CombatActionGetAttackableEnemies(self, units and units[1])
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetAnyTarget",
'params', "self, units",
'default', function (self, units)
return CombatActionGetOneAttackableEnemy(self, units and units[1])
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "EvalTarget",
'help', "Highest evaluated target will be chosen automatically (on actions that use it).",
'params', "self, units, target, args",
'default', function (self, units, target, args)
--return units[1]:CalcChanceToHit(target, self, args, "chance_only")
if not units or not units[1] then return 0 end
local unitList = g_unitOrder[units[1]]
if not unitList then return 0 end
local orderIdx = unitList[target]
if orderIdx then return -orderIdx end
return 0
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetDefaultTarget",
'help', "Gets the default target for this action",
'params', "self, unit",
'default', function (self, unit)
local best_eval, best_target
local units = {unit}
local targets = self:GetTargets(units)
local distance_to_best = 0
for _, target in ipairs(targets or empty_table) do
local eval = self:EvalTarget(units, target)
if not best_eval or eval > best_eval then
distance_to_best = IsKindOf(target, "Unit") and unit:GetDist(target:GetPos()) or 0
best_target, best_eval = target, eval
elseif eval == best_eval then
local distance_to_this = IsKindOf(target, "Unit") and unit:GetDist(target:GetPos()) or 0
if distance_to_this < distance_to_best then
distance_to_best = distance_to_this
best_target = target
end
end
end
return best_target, best_eval
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "UIBegin",
'help', "Called when this action is selected from the UI; intended use is to switch to a custom targeting mode\n\nOptionally can provide a target.",
'params', "self, units, args",
'default', function (self, units, args)
MultiTargetExecute(self.MultiSelectBehavior, units, function (unit)
self:Execute({unit}, args)
end, args and args.target)
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "Execute",
'help', "Order an action. Run will be called in the first possible moment.",
'params', "self, units, args",
'default', function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "Run",
'help', "Performs the ordered action in Execute",
'params', "self, unit, ap, ...",
'default', function (self, unit, ap, ...)
assert(not "Run should be predefined'")
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetAPCost",
'params', "self, unit, args",
'default', function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetMinAimRange",
'help', "",
'params', "self, unit, weapon",
'default', function (self, unit, weapon)
return false
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not self.DisplayName then return "CombatActions must have a DisplayName" end
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetActionResults",
'help', "",
'params', "self, unit, args",
'default', function (self, unit, args)
return {}
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetActionDamage",
'help', "Currently only used for display purposes, but that could change.",
'params', "self, unit, target, args",
'default', function (self, unit, target, args)
return 0
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetMaxAimRange",
'help', "",
'params', "self, unit, weapon",
'default', function (self, unit, weapon)
return false
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetAttackWeapons",
'params', "self, unit, args",
'default', function (self, unit, args)
return args and args.weapon or unit:GetActiveWeapons()
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetActionDescription",
'params', "self, units",
'default', function (self, units)
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return description
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetActionDisplayName",
'params', "self, units",
'default', function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetActionIcon",
'params', "self, units",
'default', function (self, units)
return self.Icon
end,
}),
PlaceObj('PropertyDefText', {
'id', "IdDefault",
'translate', false,
}),
PlaceObj('PropertyDefFunc', {
'id', "ResolveAction",
'params', "self, context",
'default', function (self, context)
return self
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetAimParams",
'params', "self, unit, weapon",
'default', function (self, unit, weapon)
if self.AimType == "cone" then
return weapon:GetAreaAttackParams(self.id, unit)
elseif self.AimType == "mobile" then
local shots = self:ResolveValue("mobile_num_shots") or 1
local move_ap = self:ResolveValue("mobile_move_ap")
assert(move_ap)
return { num_shots = shots, move_ap = move_ap * const.Scale.AP}
elseif self.AimType == "parabola aoe" or self.AimType == "line aoe" then
return weapon.AreaOfEffect
end
return 0
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "IsToggledOn",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return self.ActionType ~= "Toggle" end,
'params', "self, unit",
'default', function (self, unit)
return false
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'code', function ()
function CombatActionAttacksCombo()
local items = { "Any Attack", "Any Melee Attack", "Any Ranged Attack" }
ForEachPreset("CombatAction", function(item)
if item.ActionType ~= "Other" then
items[#items + 1] = item.id
end
end)
return items
end
function GetConfigurableKeybindCombatActions()
local ids = table.keys2(CombatActions)
return table.ifilter(ids, function(idx, id)
return CombatActions[id].ConfigurableKeybind or CombatActions[id].ActionShortcut
end)
end
end,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/human male man people person.png",
DefEditorMenubar = "Combat",
id = "CombatStance",
PlaceObj('PropertyDefText', {
'id', "display_name",
'name', "Display Name",
}),
PlaceObj('PropertyDefText', {
'id', "idle_anim",
'name', "Stance Anim",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'id', "move_anim",
'name', "Movement Anim",
'translate', false,
}),
PlaceObj('PropertyDefNumber', {
'id', "Noise",
'help', "Range (in tiles) in which the unit alerts unaware enemies when moving in this stance",
'default', 3,
'min', 0,
'max', 100,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/info large outline",
DefEditorMenubar = "Scripting",
DefEditorName = "Satellite Conflict Descriptions",
DefGlobalMap = "ConflictDescriptionDefs",
id = "ConflictDescription",
PlaceObj('PropertyDefText', {
'id', "description",
'name', "Description",
'help', "Will fallback to default if missing.",
}),
PlaceObj('PropertyDefText', {
'id', "title",
'name', "Title",
'help', "Will fallback to default if missing.",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "ContainerNames",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
'name', "Display Name",
}),
})
PlaceObj('PresetDef', {
DefContainerClass = "ConversationPhrase",
DefEditorCustomActions = {
PlaceObj('EditorCustomActionDef', {
'Name', "Test",
}),
PlaceObj('EditorCustomActionDef', {
'Name', "Test conversation",
'FuncName', "TestConversation",
'Toolbar', "main",
'Menubar', "Test",
'Shortcut', "Ctrl-T",
'Icon', "CommonAssets/UI/Ged/play",
}),
},
DefEditorIcon = "CommonAssets/UI/Icons/baloon chat conversation texting.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "3010",
DefEditorName = "Conversations",
DefFilterClass = "ConversationEditorFilter",
DefGedEditor = "ConversationEditor",
DefGlobalMap = "Conversations",
DefHasParameters = true,
DefParentClassList = {
"Preset",
"CampaignSpecific",
},
DefSingleFile = false,
DefSubItemFilterClass = "ConversationEditorPhraseFilter",
id = "Conversation",
PlaceObj('PropertyDefCombo', {
'category', "Preset",
'id', "Id",
'validate', function (self, value) return ValidateIdentifier(self, value) end,
'items', function (self) return GetConversationCharactersCombo end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "DefaultActor",
'name', "Default actor",
'help', "The default non-player unit talking in this conversation.",
'preset_class', "UnitDataCompositeDef",
}),
PlaceObj('PropertyDefCombo', {
'id', "AssignToGroup",
'name', "Assign to group",
'help', "Assign the conversation to units from this group.",
'items', function (self) return GetUnitGroups() end,
}),
PlaceObj('PropertyDefUIImage', {
'id', "DefaultActorPortraitOverride",
'name', "Override Default Actor Portrait",
}),
PlaceObj('PropertyDefNestedList', {
'id', "Conditions",
'name', "Conditions",
'help', "Assign the conversation only if these are true.",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefBool', {
'id', "Enabled",
'help', "To disable conversation for test purposes.",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "disabledInConflict",
'name', "Do not play during conflict",
'help', "Disable conversation while in conflict. NotNow VR plays instead.",
}),
PlaceObj('PropertyDefStringList', {
'id', "StartOnMsg",
'name', "Start OnMsg",
'help', "Starts when any of these messages is invoked.",
'arbitrary_value', true,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorNew",
'params', "parent, ged, is_paste, duplicate_id",
'code', function (self, parent, ged, is_paste, duplicate_id)
if is_paste then
if duplicate_id then
for _, condition in ipairs(self.Conditions or empty_table) do
if rawget(condition, "Conversation")==duplicate_id then
condition.Conversation = self.Id
end
end
self:ForEachSubObject("ConversationPhrase", function(obj, parents)
for _, condition in ipairs(obj.Conditions or empty_table) do
if rawget(condition, "Conversation")==duplicate_id then
condition.Conversation = self.id
end
end
for _, effect in ipairs(obj.Effects or empty_table) do
if rawget(effect, "Conversation")==duplicate_id then
effect.Conversation = self.id
end
end
end)
end
return
end
self[1] = ConversationPhrase:new { id = "Greeting", Keyword = "Greeting", KeywordT = T(774381032385, "Greeting") }
self[2] = ConversationPhrase:new { id = "Goodbye", Keyword = "Goodbye", KeywordT = T(557225474228, "Goodbye") }
self[1]:OnAfterEditorNew()
self[2]:OnAfterEditorNew()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
if prop_id == "DefaultActor" then
self:ForEachSubObject("ConversationLine", function(obj, parents)
if obj.Character == old_value or obj.Character == self.id then
obj.Character = self.DefaultActor
end
end)
end
if prop_id == "Id" then
CreateRealTimeThread(function()
local msg = "This will update the references to this conversation from within itself,\nbut external references will NOT be updated!"
if ged:WaitQuestion("Rename", msg, "Yes", "No") ~= "ok" then
self:SetId(old_value)
ObjModified(self)
return
end
self:ForEachSubObject(function(obj)
for _, prop in ipairs(obj:GetProperties()) do
if prop.editor == "preset_id" and prop.preset_class == "Conversation" and
obj:GetProperty(prop.id) == old_value
then
obj:SetProperty(prop.id, self.id)
end
end
end)
ObjModified(self)
end)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'params', "user_requested",
'code', function (self, user_requested)
self:ForEachSubObject("ConversationLine", function(obj, parents)
if self.DefaultActor and (obj.Character == "<default>" or obj.Character == self.id) then
obj.Character = self.DefaultActor
end
end)
RebuildGroupToConversation()
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not self.DefaultActor then
return "Please specify the default actor."
end
local has_end_phrase
self:ForEachSubObject("ConversationPhrase", function(phrase)
if phrase.GoTo == "<end conversation>" then
has_end_phrase = true
end
end)
if not has_end_phrase then
return "Conversation doesn't have any phrase with <end conversation> GoTo property."
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
--using default portrait for goldmaster is only a warning (mods)
if not config.ModdingToolsInUserMode then return end
return self:UsingDefaultBigPortrait()
end,
}),
PlaceObj('ClassConstDef', {
'name', "EditorView",
'type', "text",
'value', "<id><color 0 128 0><opt(u(Comment),' ','')><color 128 128 128><opt(u(save_in),' - ','')>",
'untranslated', true,
}),
PlaceObj('ClassMethodDef', {
'name', "UsingDefaultBigPortrait",
'code', function (self)
local defaults = {}
self:ForEachSubObject("ConversationLine", function(obj, parents, key, defaults)
local unit_def = UnitDataDefs[obj.Character]
if obj.Character and unit_def and
unit_def:IsDefaultPropertyValue("BigPortrait", unit_def:GetPropertyMetadata("BigPortrait"), unit_def:GetProperty("BigPortrait")) then
table.insert_unique(defaults, obj.Character)
end
end, defaults)
if next(defaults) then
return "Using default BigPortrait property for: " .. table.concat(defaults, ",")
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetSaveData",
'params', "file_path, presets, ...",
'code', function (self, file_path, presets, ...)
for idx, preset in ipairs(presets) do
self:CreatePresetDiffFile(preset, string.gsub(file_path, ".lua", ".diff.txt"))
end
return Preset.GetSaveData(self, file_path, presets, ...)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "CreatePresetDiffFile",
'params', "preset, diff_path",
'code', function (self, preset, diff_path)
local diffText = { }
for _, conv in ipairs(preset) do
diffText[#diffText + 1] = conv:GetReadableText(0)
end
SaveSVNFile(diff_path, table.concat(diffText, "\n"))
end,
}),
PlaceObj('PropertyDefBool', {
'id', "IncludeInVoiceScripts",
'name', "Include in voice recording scripts",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return config.ModdingToolsInUserMode end,
'default', true,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Allows adding a new conversation triggered by an actor or a group of actors. See the New Quest sample mod in the Sample Mods section for an example on how to build a conversation.",
}),
PlaceObj('ClassConstDef', {
'name', "DocumentationLink",
'type', "text",
'value', "Docs/ModTools/index.md.html",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "ConversationInterjection",
PlaceObj('PropertyDefNestedList', {
'id', "Lines",
'base_class', "ConversationLine",
}),
PlaceObj('PropertyDefNestedList', {
'id', "Conditions",
'help', "All conditions must be true for the phrase to be available.",
'base_class', "Condition",
}),
PlaceObj('PropertyDefNestedList', {
'id', "Effects",
'help', "Effects that are executed after the phrase is displayed.",
'base_class', "Effect",
}),
PlaceObj('PropertyDefBool', {
'id', "AlwaysInterject",
'help', "Allows the interjection to be played again, even if the player has already heard it.",
}),
PlaceObj('ClassConstDef', {
'name', "StoreAsTable",
'value', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local actors = {}
for _, line in ipairs(self.Lines or empty_table) do
if line.Character ~= "<default>" then
table.insert_unique(actors, line.Character)
end
end
return "<color 160 64 160>" .. table.concat(actors, " & ") .. "</color>"
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetReadableText",
'params', "indentation_level",
'code', function (self, indentation_level)
local diffText = { }
for _,line in ipairs(self.Lines) do
diffText[#diffText + 1] = line:GetReadableText(indentation_level + 1)
end
return table.concat(diffText, "\n")
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"ConversationLineBase",
},
group = "PresetDefs",
id = "ConversationInterjectionList",
PlaceObj('PropertyDefNumber', {
'id', "MaxPlayed",
'name', "Max played",
'default', 1,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Interjections",
'base_class', "ConversationInterjection",
'inclusive', true,
'auto_expand', true,
}),
PlaceObj('ClassConstDef', {
'name', "StoreAsTable",
'value', true,
}),
PlaceObj('ClassConstDef', {
'name', "EditorView",
'type', "text",
'untranslated', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local list = { "Interjections" }
if self.MaxPlayed > 1 then
list[#list + 1] = string.format("(max %d)", self.MaxPlayed)
end
for _, item in ipairs(self.Interjections or empty_table) do
list[#list + 1] = "["..item:GetEditorView().."]"
end
return table.concat(list, " ")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnAfterEditorNew",
'params', "root, ged, is_paste",
'code', function (self, root, ged, is_paste)
if not is_paste then
self.Interjections = { ConversationInterjection:new() }
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetReadableText",
'params', "indentation_level",
'code', function (self, indentation_level)
local diffText = { }
for _,i in ipairs(self.Interjections) do
diffText[#diffText + 1] = i:GetReadableText(indentation_level)
end
return table.concat(diffText, "\n")
end,
}),
})
PlaceObj('PresetDef', {
Comment = "stores combo items",
DefGedEditor = "",
DefGlobalMap = "ConversationKeywords",
id = "ConversationKeyword",
})
PlaceObj('ClassDef', {
DefParentClassList = {
"ConversationLineBase",
},
group = "PresetDefs",
id = "ConversationLine",
PlaceObj('PropertyDefChoice', {
'id', "Character",
'help', "The character that says this line.",
'default', "<default>",
'items', function (self) return GetConversationCharactersCombo end,
}),
PlaceObj('PropertyDefCombo', {
'id', "Annotation",
'help', 'Extra context for voice actors, e.g. "angry", "sad", etc.',
'items', function (self) return PresetsPropCombo("Conversation", "Annotation", "", "recursive") end,
}),
PlaceObj('PropertyDefBrowse', {
'id', "SoundBefore",
'name', "Sound before",
'help', "Play sound before line and line voice over",
'folder', "Sounds/ConversationEffects/",
'filter', "",
}),
PlaceObj('PropertyDefBrowse', {
'id', "SoundAfter",
'name', "Sound after",
'help', "Play sound after line and line voice over",
'folder', "Sounds/ConversationEffects/",
'filter', "",
}),
PlaceObj('PropertyDefPresetId', {
'id', "SoundType",
'name', "Sound Type",
'preset_class', "SoundTypePreset",
'preset_group', "VoiceoverConversations",
'default', "ConversationsSFX",
}),
PlaceObj('PropertyDefText', {
'id', "Text",
'extra_code', 'context = ConversationLineContext("Character", "Annotation")',
'lines', 1,
'max_lines', 7,
}),
PlaceObj('PropertyDefBool', {
'id', "AlwaysInterject",
'help', "Allows the interjection to be played again, even if the player has already heard it.",
}),
PlaceObj('ClassConstDef', {
'name', "StoreAsTable",
'value', true,
}),
PlaceObj('ClassConstDef', {
'name', "EditorView",
'type', "text",
'value', "<if(not_eq(Character,'<default>'))><Character>:</if> \"<Text>\"",
'untranslated', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetReadableText",
'params', "indentation_level",
'code', function (self, indentation_level)
return self.Text and string.format("%s%s: %s", string.rep("\t", indentation_level), self.Character, TDevModeGetEnglishText(self.Text, nil, false)) or ""
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "ConversationLineBase",
})
PlaceObj('ClassDef', {
DefParentClassList = {
"PropertyObject",
"Container",
},
group = "PresetDefs",
id = "ConversationPhrase",
PlaceObj('PropertyDefText', {
'category', "General",
'id', "id",
'name', "Id",
'read_only', true,
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Copy Id",
'FuncName', "CopyFullIdToClipboard",
}),
PlaceObj('PropertyDefPropButton', {
'Name', "Change",
'FuncName', "ChangeId",
}),
},
'translate', false,
}),
PlaceObj('ClassMethodDef', {
'name', "GetFullId",
'params', "root",
'code', function (self, root)
return ComposePhraseId(root:FindSubObjectParentList(self), self, 2)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "CopyFullIdToClipboard",
'params', "root, prop_id, ged",
'code', function (self, root, prop_id, ged)
local full_id = self:GetFullId(root)
CopyToClipboard(full_id)
ged:ShowMessage("Phrase ID Copied to Clipboard", full_id)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "ChangeId",
'params', "root, prop_id, ged",
'code', function (self, root, prop_id, ged)
local old_id = self.id
local new_id = ged:WaitUserInput("Enter new Id", self.id)
if not new_id then return end
-- this phrase and all children phrases have their ids changed
local id_changes = {} -- old_id => new_id
self:ForEachSubObject("ConversationPhrase", function(phrase)
local old_full_id = phrase:GetFullId(root)
self.id = new_id
id_changes[old_full_id] = phrase:GetFullId(root)
self.id = old_id
end)
self.id = new_id
-- enumerate all references, updating matching ids
local count = 0
ForEachPhraseReferenceInPresets(root, function(parents, obj, phrase_id_prop)
local new_id = id_changes[obj[phrase_id_prop]]
if new_id then
obj[phrase_id_prop] = new_id
count = count + 1
end
end)
ged:ShowMessage("Information", string.format("A total of %d references to this phrase (or children phrases) were updated to use the new ids.", count))
ObjModified(self)
end,
}),
PlaceObj('PropertyDefCombo', {
'category', "General",
'id', "Keyword",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Add to combo",
'FuncName', "AddKeywordToCombo",
}),
},
'default', "",
'items', function (self) return PresetsCombo("ConversationKeyword") end,
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "KeywordT",
'no_edit', true,
}),
PlaceObj('ClassMethodDef', {
'name', "AddKeywordToCombo",
'code', function (self)
if self.Keyword ~= "" and not table.find(Presets.ConversationKeyword.Default, "id", self.Keyword) then
local keyword = ConversationKeyword:new()
keyword:SetGroup("Default")
keyword:SetId(self.Keyword)
ConversationKeyword:SaveAll("force")
end
end,
}),
PlaceObj('PropertyDefCombo', {
'category', "General",
'id', "Tag",
'help', "Tags are used to automatically aggregate several keywords in a sub-menu (named after the Tag) if there are too many keywords. Keywords with tags are by default aligned left.",
'default', "",
'items', function (self) return PresetsPropCombo("Conversation", "Tag", "", "recursive") end,
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "TagT",
'no_edit', true,
}),
PlaceObj('PropertyDefChoice', {
'category', "General",
'id', "Align",
'default', "left",
'items', function (self) return { "left", "right" } end,
}),
PlaceObj('PropertyDefPresetId', {
'category', "General",
'id', "StoryBranchIcon",
'preset_class', "ConversationStoryBranchIcons",
'default', "conversation_chat",
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "Comment",
'translate', false,
'lines', 1,
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "Enabled",
'help', "Is this keyword initially enabled.",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "AutoRemove",
'name', "Auto remove",
'help', "Is this phrase auto-removed once it is displayed to the player.",
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "VariantPhrase",
'name', "Variant phrase",
'help', "A random phrase from the active variant phrases is picked. Variant phrases have lower priority than non-variant phrases that have not yet been seen, so they can be activated only after all the non-variant phrases have been seen by the player.",
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "ShowDisabled",
'name', "Show disabled",
'help', "Displays the phrase dimmed if the conditions are not met, and there are no other enabled phrases with the same Keyword.",
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "ShowPhraseRollover",
'name', "Show Phrase Rollover",
'help', "Shows phrase rollover - autogenerated or overwritten if available. If false is set no rollover is displaed even if there is atogenerated.",
'default', true,
}),
PlaceObj('PropertyDefText', {
'category', "Activation",
'id', "PhraseRolloverText",
'name', "Phrase rollover text",
'help', "Show that text when rollover the phrase. That text will override the automatically generated one from conditions.",
'lines', 2,
'max_lines', 4,
}),
PlaceObj('PropertyDefText', {
'category', "Activation",
'id', "PhraseRolloverTextAuto",
'name', "Phrase rollover text autogenerated",
'help', "Show that text when the phrase is rollovered. That text is auto-generated from conditions via GetUIText.",
'dont_save', true,
'read_only', true,
'translate', false,
'lines', 2,
'max_lines', 4,
}),
PlaceObj('PropertyDefText', {
'category', "Activation",
'id', "PhraseConditionRolloverText",
'name', "Current phrase rollover text for executed phrase",
'help', "Show that text when the phrase is displayed. That text will override the automatically generated one from conditions.",
'lines', 2,
'max_lines', 4,
}),
PlaceObj('PropertyDefText', {
'category', "Activation",
'id', "PhraseConditionRolloverTextAuto",
'name', "Current Phrase Rollover Text Autogenerated",
'help', "Show that text when the phrase is displayed. That text is auto-generated from conditions via GetConditionPhraseTopRolloverText.",
'dont_save', true,
'read_only', true,
'translate', false,
'lines', 2,
'max_lines', 4,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Activation",
'id', "Conditions",
'help', "All conditions must be true for the phrase to be available.",
'base_class', "Condition",
}),
PlaceObj('PropertyDefBool', {
'category', "Activation",
'id', "NoBackOption",
'name', "No Back option",
'help', "Do not add a 'Back' option to the list of child phrases.",
'extra_code', "no_edit = function(obj) return #obj == 0 end",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Execution",
'id', "Lines",
'help', "The list of conversation lines to display when this phrase is activated.",
'base_class', "ConversationLineBase",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Execution",
'id', "Effects",
'help', "Effects that are executed after the phrase is displayed.",
'base_class', "Effect",
}),
PlaceObj('PropertyDefPresetIdList', {
'category', "Execution",
'id', "CompleteQuests",
'name', "Complete quests",
'help', "Sets quests status to 'completed'",
'preset_class', "QuestsDef",
}),
PlaceObj('PropertyDefPresetIdList', {
'category', "Execution",
'id', "GiveQuests",
'name', "Give quests",
'help', "Sets quests status to 'given'",
'preset_class', "QuestsDef",
}),
PlaceObj('PropertyDefChoice', {
'category', "Execution",
'id', "GoTo",
'name', "Go to",
'help', "Next phrase tree to jump to after this one - by default stay in the same tree.",
'default', "",
'items', function (self) return GetPhraseIdsCombo(GetParentTableOfKindNoCheck(self, "Conversation"), "skip_greetings", { "", "<back>", "<root>", "<end conversation>" }) end,
}),
PlaceObj('PropertyDefBool', {
'category', "Execution",
'id', "PlayGoToPhrase",
'name', 'Play "Go to" phrase',
'help', 'If set, plays all lines from the phrase jumped to with the "Go to" property and executes its Effects.',
}),
PlaceObj('ClassConstDef', {
'name', "StoreAsTable",
'value', true,
}),
PlaceObj('ClassConstDef', {
'name', "ComboFormat",
'type', "text",
'value', "<Keyword>",
'untranslated', true,
}),
PlaceObj('ClassConstDef', {
'name', "ContainerClass",
'type', "text",
'value', "ConversationPhrase",
}),
PlaceObj('ClassConstDef', {
'name', "EditorName",
'type', "text",
'value', "Phrase",
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local texts = {}
texts[#texts+1] = Untranslated("<color 100 100 200><if(Enabled)>+</if><def(Keyword,'[new phrase]')></color>")
local condition = self.Conditions and self.Conditions[1]
local txt = condition and _InternalTranslate(condition:GetEditorView(), condition) or ""
if txt and txt~="" then
txt = utf8.len(txt) <= 30 and txt or (utf8.sub(txt, 1, 30) .. "...")
texts[#texts+1] = Untranslated(" <color 150 150 100>["..txt.."]</color> ")
end
local txt
local interjections, line_interjections = {}, {}
local default_actor = GetParentTableOfKind(self, "Conversation").DefaultActor
for _, line in ipairs(self.Lines) do
if line:IsKindOf("ConversationLine") then
txt = txt or line and line.Text
if line.Character ~= "<default>" and line.Character ~= default_actor then
table.insert(line_interjections, string.format("[%s]", line.Character))
end
elseif line:IsKindOf("ConversationInterjectionList") then
table.insert(interjections, "\t\t" .. line:GetEditorView())
end
end
if next(line_interjections) then
table.insert(interjections, 1, "\t\tLine interjections: " .. table.concat(line_interjections, " ") )
end
if txt and txt ~= "" then
txt = TDevModeGetEnglishText(txt)
txt = utf8.len(txt) <= 50 and txt or (utf8.sub(txt, 1, 50) .. "...")
texts[#texts+1] = Untranslated(" "..string.format("<literal %s>%s", #txt, txt).." ")
end
local comment = self.Comment
if #(comment or "") > 0 then
comment = comment:match("^([^\n]*)")
comment = utf8.len(comment) <= 20 and comment or (utf8.sub(comment, 1, 20) .. "...")
texts[#texts+1] = Untranslated("<color 0 128 0>-- ".. comment .."</color>")
end
local phrase_text = table.concat(texts, "")
if self.Effects or self.Conditions or next(interjections) then
local text_lines = {phrase_text}
if next(interjections) then
text_lines[#text_lines+1] = Untranslated("<color 160 64 160>" .. table.concat(interjections, "\n") .. "</color>")
end
GetEditorConditionsAndEffectsText(text_lines, self)
GetEditorStringListPropText(text_lines, self, "CompleteQuests")
GetEditorStringListPropText(text_lines, self, "GiveQuests")
phrase_text = table.concat(text_lines, "\n")
end
if self.GoTo ~= "" and self.Keyword ~= "Goodbye" then
local command = self.GoTo:starts_with("<end") and "" or "Go to "
phrase_text = phrase_text .. Untranslated(string.format("\n\t\t<color 191 124 28>%s%s</color>", command, self.GoTo))
end
return phrase_text
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateId",
'params', "conversation",
'code', function (self, conversation)
local id = self.Keyword:gsub("[^%w_+-]", "")
local parent_list = conversation:FindSubObjectParentList(self)
local parent = parent_list[#parent_list]
local orig_id, idx = id, 1
while table.find(parent, "id", id) or id == "" do
idx = idx + 1
id = orig_id .. tostring(idx)
end
self.id = id
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnAfterEditorNew",
'params', "root, ged, is_paste",
'code', function (self, root, ged, is_paste)
if is_paste then
self:GenerateId(root)
self.KeywordT = g_ConversationTs[self.Keyword] or T(RandomLocId(), self.Keyword)
else
self.Lines = { ConversationLine:new() }
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
local conversation = GetParentTableOfKind(self, "Conversation")
if prop_id == "Keyword" and self.Keyword ~= "" then
if not self.id then
self:GenerateId(conversation)
end
self.KeywordT = g_ConversationTs[self.Keyword] or T(RandomLocId(), self.Keyword)
elseif prop_id == "Tag" then
self.Align = self.Tag == "" and "right" or "left"
self.TagT = self.Tag == "" and "" or g_ConversationTs[self.Tag] or T(RandomLocId(), self.Tag)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if self.VariantPhrase and self.ShowDisabled then
return "Variant phrases can't have the 'Show disabled' property"
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPhraseRolloverTextAuto",
'params', "game",
'code', function (self, game)
local rollover_texts = {}
for _, cond in ipairs(self.Conditions or empty_table) do
local text = cond:HasMember("GetUIText") and not cond:GetError() and cond:GetUIText(self, false, game)
if text and text~="" then
table.insert(rollover_texts, 1, text)
end
end
for _, eff in ipairs(self.Effects or empty_table) do
local text = eff:HasMember("GetUIText") and not eff:GetError() and eff:GetUIText(self, false, game)
if text and text~="" then
table.insert(rollover_texts, 1, text)
end
end
if next(rollover_texts) then
if game then
return table.concat(rollover_texts, "\n")
else
return _InternalTranslate(table.concat(rollover_texts, "\n"))
end
else
return ""
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPhraseConditionRolloverTextAuto",
'params', "game",
'code', function (self, game)
local rollover_texts = {}
for _, cond in ipairs(self.Conditions or empty_table) do
local text = cond:HasMember("GetPhraseTopRolloverText") and not cond:GetError() and cond:GetPhraseTopRolloverText(self, false, game)
if text and text~="" then
table.insert(rollover_texts, 1, text)
end
end
for _, eff in ipairs(self.Effects or empty_table) do
local text = eff:HasMember("GetPhraseTopRolloverText") and not eff:GetError() and eff:GetPhraseTopRolloverText(self, false, game)
if text and text~="" then
table.insert(rollover_texts, 1, text)
end
end
if next(rollover_texts) then
if game then
return table.concat(rollover_texts, "\n")
else
return _InternalTranslate(table.concat(rollover_texts, "\n"))
end
else
return ""
end
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "a global allowing T ID reuse; see OnAfterEditorNew",
'code', function ()
if FirstLoad then
g_ConversationTs = {}
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "__fromluacode",
'params', "table, arr",
'code', function (self, table, arr)
local obj = PropertyObject.__fromluacode(self, table, arr)
if g_ConversationTs[obj.Keyword] then obj.KeywordT = g_ConversationTs[obj.Keyword] end
if g_ConversationTs[obj.Tag] then obj.TagT = g_ConversationTs[obj.Tag] end
if obj.Keyword ~= "" then g_ConversationTs[obj.Keyword] = obj.KeywordT end
if obj.Tag ~= "" then g_ConversationTs[obj.Tag] = obj.TagT end
return obj
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetReadableText",
'params', "indentation_level",
'code', function (self, indentation_level)
local diffText = { }
diffText[#diffText + 1] = string.format("%s[Keyword: %s]", string.rep("\t", indentation_level), TDevModeGetEnglishText(self.KeywordT))
if self.Lines then
for _,line in ipairs(self.Lines) do
diffText[#diffText + 1] = line:GetReadableText(indentation_level + 1)
end
end
for _,phrase in ipairs(self) do
diffText[#diffText + 1] = phrase:GetReadableText(indentation_level + 1)
end
return table.concat(diffText, "\n")
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "StoryBranchIcons",
DefParentClassList = {
"ListPreset",
},
id = "ConversationStoryBranchIcons",
PlaceObj('PropertyDefUIImage', {
'category', "Preset",
'id', "icon",
'image_preview_size', 20,
}),
})
PlaceObj('PresetDef', {
Comment = "stores combo items for craft operations ids",
DefGedEditor = "",
DefGlobalMap = "CraftOperationIds",
group = "PresetDefs",
id = "CraftOperationId",
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/auction court hammer judge justice law.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4061",
DefEditorName = "Craft Operations Recipes Editor",
DefEditorShortcut = "",
DefGlobalMap = "CraftOperationsRecipes",
DefHasParameters = true,
DefHasSortKey = true,
DefModItem = true,
DefModItemName = "Crafting operation recipe",
DefModItemSubmenu = "Satellite",
group = "PresetDefs",
id = "CraftOperationsRecipeDef",
PlaceObj('PropertyDefCombo', {
'id', "CraftOperationId",
'help', "which craft operation displays that recipe",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Add to combo",
'FuncName', "AddCraftOperationIdToCombo",
}),
},
'items', function (self) return PresetsCombo("CraftOperationId") end,
'show_recent_items', 5,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Ingredients",
'name', "Ingredients",
'base_class', "RecipeIngredient",
}),
PlaceObj('PropertyDefNestedObj', {
'id', "ResultItem",
'name', "Result Item",
'base_class', "RecipeIngredient",
}),
PlaceObj('PropertyDefNumber', {
'id', "CraftTime",
'name', "Craft Time",
'help', "The time in hours needed to craft the item from a crafter with skill 50",
'slider', true,
'min', 0,
'max', 360000,
}),
PlaceObj('PropertyDefPresetId', {
'category', "Conditions",
'id', "RequiredCrafter",
'name', "RequiredCrafter",
'help', "Required Crafter",
'preset_class', "UnitDataCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
return IsMerc(gv_UnitData[preset.id])
end,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditions",
'id', "QuestConditions",
'base_class', "QuestConditionBase",
}),
PlaceObj('PropertyDefButtons', {
'category', "General",
'id', "btnAddItem",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Add Ingredients To Current Unit",
'FuncName', "UIPlaceIngredientsInInventory",
}),
},
'template', true,
}),
PlaceObj('ClassMethodDef', {
'name', "AddCraftOperationIdToCombo",
'code', function (self)
if self.CraftOperationId ~= "" and not table.find(CraftOperationIds, "id", self.CraftOperationId) then
local id = CraftOperationId:new()
id:SetGroup("Default")
id:SetId(self.CraftOperationId)
CraftOperationId:SaveAll("force")
end
end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Creates a new Crafting Operation Recipe that is accessed through the sector operations menu.",
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "EliteEnemyNames",
id = "EliteEnemyName",
PlaceObj('PropertyDefText', {
'id', "name",
'name', "Name",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/email envelope mail message.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4000",
DefEditorName = "Emails",
DefGlobalMap = "Emails",
DefParentClassList = {
"MsgReactionsPreset",
"CampaignSpecific",
},
id = "Email",
PlaceObj('PropertyDefText', {
'category', "Email",
'id', "title",
'name', "Title",
}),
PlaceObj('PropertyDefText', {
'category', "Email",
'id', "sender",
'name', "Sender",
}),
PlaceObj('PropertyDefText', {
'category', "Email",
'id', "body",
'name', "Body",
'lines', 4,
'max_lines', 20,
}),
PlaceObj('PropertyDefCombo', {
'category', "Email",
'id', "label",
'name', "Label",
'items', function (self) return PresetGroupCombo("EmailLabel", "Default") end,
'translate', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Email",
'id', "attachments",
'name', "Attachments",
'base_class', "EmailAttachment",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Reactions",
'id', "sendConditions",
'name', "Send Conditions",
'help', "If these conditions exist they will be evaluated periodically for one time emails.",
'base_class', "Condition",
}),
PlaceObj('PropertyDefBool', {
'category', "Reactions",
'id', "repeatable",
'name', "Repeatable",
}),
PlaceObj('PropertyDefBool', {
'category', "Reactions",
'id', "delayAfterCombat",
'name', "Delay After Combat",
'help', "When an email should be send during combat. It is instead send after the combat ends.",
'default', true,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Allows creating new emails received in the Email tab.",
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "EmailLabels",
DefParentClassList = {
"ListPreset",
},
id = "EmailLabel",
PlaceObj('PropertyDefText', {
'id', "name",
'name', "Name",
}),
PlaceObj('PropertyDefBool', {
'id', "hiddenWhenEmpty",
'name', "Hidden when empty",
'help', "Hides the label if there are no received emails marked with it",
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "5010",
DefEditorName = "Employment History Line",
DefGlobalMap = "EmploymentHistoryLines",
DefParentClassList = {
"MsgReactionsPreset",
},
id = "EmploymentHistoryLine",
PlaceObj('PropertyDefHelp', {
'category', "Preset",
'id', "help",
'help', "Caution:\n1. Renaming Ids or deleting presets will invalidate the related history logs from older saves.\n2. Do NOT add Translations to the save(inside AddEmploymentHistoryLog) or else when switching langauages those words/phrases won't be translated.\n Instead add ids and other indicative vars to the context and then use them in the GetText function.",
}),
PlaceObj('PropertyDefText', {
'id', "text",
'name', "Text",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetText",
'name', "GetText",
'params', "self, context",
'default', function (self, context)
return T{self.text, context}
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "EnemyRole",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
'name', "DisplayName",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
'name', "Icon",
}),
PlaceObj('PropertyDefUIImage', {
'id', "BadgeIcon",
'name', "BadgeIcon",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/group",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4010",
DefGlobalMap = "EnemySquadDefs",
id = "EnemySquads",
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if #(self.Units or "") == 0 then
return "Add units in squad"
end
end,
}),
PlaceObj('PropertyDefText', {
'id', "displayName",
'name', "Squad Display Name",
}),
PlaceObj('PropertyDefText', {
'id', "SquadPowerRange",
'name', "Squad Power Range",
'help', "Shows min squad power: lowestPowerUnits * lowestAmountSpawned. And max squad power: highestPowerUnits * higestAmountSpawned",
'dont_save', true,
'read_only', true,
'translate', false,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Units",
'base_class', "EnemySquadUnit",
'auto_expand', true,
}),
PlaceObj('PropertyDefBool', {
'category', "Bombard",
'id', "Bombard",
}),
PlaceObj('PropertyDefBool', {
'category', "Diamond Briefcase",
'id', "DiamondBriefcase",
'name', "Has Diamond Shipment",
}),
PlaceObj('PropertyDefChoice', {
'category', "Diamond Briefcase",
'id', "DiamondBriefcaseCarrier",
'name', "Carrier",
'help', "Valid carries are unit defs with only a single unit to be spawned from them. The chance to spawn should be set to 100%",
'items', function (self) return self:GetValidCarriers() end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetValidCarriers",
'code', function (self)
local arr = { { } }
for i, u in ipairs(self.Units) do
if u.UnitCountMax == 1 and u.UnitCountMin == 1 then
local name = u:GetEditorView()
local item = { name = name, value = i }
arr[#arr + 1] = item
end
end
return arr
end,
}),
PlaceObj('PropertyDefPresetId', {
'category', "Bombard",
'id', "BombardOrdnance",
'name', "Ordnance",
'extra_code', "no_edit = function(self) return not self.Bombard end",
'preset_class', "InventoryItemCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
return preset.object_class == "Ordnance"
end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Bombard",
'id', "BombardShots",
'name', "Num Shells",
'extra_code', "no_edit = function(self) return not self.Bombard end",
'default', 1,
'min', 1,
}),
PlaceObj('PropertyDefNumber', {
'category', "Bombard",
'id', "BombardAreaRadius",
'name', "Area Radius",
'help', "in tiles",
'extra_code', "no_edit = function(self) return not self.Bombard end",
'default', 3,
'min', 1,
'max', 99,
}),
PlaceObj('PropertyDefNumber', {
'category', "Bombard",
'id', "BombardLaunchOffset",
'name', "Launch Offset",
'help', "defines the direction of the fall together with Launch Angle; if left as 0 the shells will fall directly down",
'extra_code', "no_edit = function(self) return not self.Bombard end",
'default', 5000,
'scale', "m",
}),
PlaceObj('PropertyDefNumber', {
'category', "Bombard",
'id', "BombardLaunchAngle",
'name', "Launch Angle",
'help', "defines the direction of the fall together with Launch Offset",
'extra_code', "no_edit = function(self) return not self.Bombard end",
'default', 1200,
'scale', "deg",
}),
PlaceObj('ClassConstDef', {
'name', "EditorPreview",
'type', "text",
'value', "<Preview>",
'untranslated', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPreview",
'code', function (self)
local texts = {}
for _, squad_unit_def in ipairs(self.Units) do
texts[#texts + 1] = squad_unit_def:GetEditorView()
end
return table.concat(texts, ", ")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetSquadPowerRange",
'code', function (self)
local minSquadPower = 0
local maxSquadPower = 0
for _, unitGroups in ipairs(self.Units) do
local lowestPower
local highestPower
local minCount = unitGroups.UnitCountMin
local maxCount = unitGroups.UnitCountMax
for _, unitData in ipairs(unitGroups.weightedList) do
local unitPreset = UnitDataDefs[unitData.unitType]
if unitPreset then
local power = GetPowerOfUnit(unitPreset, "noMods")
if not lowestPower or lowestPower > power then
lowestPower = power
end
if not highestPower or highestPower < power then
highestPower = power
end
end
end
minSquadPower = minSquadPower + (lowestPower and (lowestPower * minCount) or 0)
maxSquadPower = maxSquadPower + (highestPower and (highestPower * maxCount) or 0)
end
return tostring(minSquadPower) .. " - " .. tostring(maxSquadPower)
end,
}),
PlaceObj('PropertyDefBool', {
'category', "Patrol",
'id', "patrolling",
'name', "Patrolling",
'help', "The squad will be set to travel between the specified waypoints when spawned.",
}),
PlaceObj('PropertyDefStringList', {
'category', "Patrol",
'id', "waypoints",
'name', "Waypoints",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return not self.patrolling end,
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "AutoResolveTest",
'id', "playerSquadAutoTest",
'name', "Player Squad",
'help', "Leave as false to use current squad.",
'items', function (self) return EnemySquadsComboItems() end,
}),
PlaceObj('PropertyDefButtons', {
'category', "AutoResolveTest",
'id', "buttonTestInAutoResolve",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Test in AutoResolve",
'FuncName', "TestInAutoResolve",
}),
},
'template', true,
}),
PlaceObj('ClassMethodDef', {
'name', "TestInAutoResolve",
'params', "root, prop_id, ged",
'code', function (self, root, prop_id, ged)
if not gv_SatelliteView then
print("Must be in sat view")
return
end
RevealAllSectors()
local dlg = GetSatelliteDialog()
local selected_squad = dlg.selected_squad
if not self.playerSquadAutoTest then
NetEchoEvent("CheatSatelliteTeleportSquad", selected_squad.UniqueId, "B1")
end
local sector = gv_Sectors["A1"]
sector.Side = "player1"
local allySquads, enemySquads = GetSquadsInSector(sector.Id, nil, "includeMilitia")
for _, squad in ipairs(enemySquads) do
RemoveSquad(squad)
end
for _, squad in ipairs(allySquads) do
RemoveSquad(squad)
end
GenerateEnemySquad(self.id, sector.Id, "Effect", nil, "enemy1")
if self.playerSquadAutoTest then
local isMilitia = EnemySquadDefs[self.playerSquadAutoTest] and EnemySquadDefs[self.playerSquadAutoTest].group == "MilitiaAutoresolveTest"
GenerateEnemySquad(self.playerSquadAutoTest, sector.Id, "Effect", nil, isMilitia and "ally" or "player1", isMilitia)
else
NetEchoEvent("CheatSatelliteTeleportSquad", selected_squad.UniqueId, sector.Id)
end
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "EntityVariation",
PlaceObj('PropertyDefStringList', {
'id', "Entities",
'items', function (self) return table.keys(EntityData) end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "GameTerm",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('PropertyDefText', {
'id', "Description",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/appointment calendar date day event month schedule.png",
DefEditorMenubar = "Editors.Other",
DefEditorMenubarSortKey = "4130",
DefEditorName = "Game Updates Editor",
DefGlobalMap = "GameUpdates",
DefHasGroups = false,
DefHasSortKey = true,
DefStoreAsTable = "true",
group = "PresetDefs",
id = "GameUpdate",
PlaceObj('PropertyDefText', {
'category', "General",
'id', "Title",
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "Text",
'wordwrap', true,
'lines', 3,
}),
PlaceObj('PropertyDefBool', {
'category', "General",
'id', "open_as_read",
'name', "Mark as read on open",
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4040",
DefEditorName = "Guardpost Objectives",
DefGlobalMap = "GuardpostObjectives",
group = "PresetDefs",
id = "GuardpostObjective",
PlaceObj('PropertyDefCombo', {
'id', "Sector",
'name', "Sector",
'help', "The sector on which badges should be placed. (optional)",
'items', function (self) return GetGuardpostCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefText', {
'id', "Description",
'name', "Description",
'max_lines', 2,
}),
PlaceObj('PropertyDefText', {
'id', "DescriptionCompleted",
'name', "DescriptionCompleted",
'max_lines', 2,
}),
PlaceObj('PropertyDefText', {
'id', "DescriptionFailed",
'name', "DescriptionFailed",
'max_lines', 2,
}),
PlaceObj('PropertyDefNestedList', {
'id', "OnComplete",
'name', "OnComplete",
'base_class', "Effect",
}),
PlaceObj('PropertyDefNestedList', {
'id', "OnRegenerate",
'name', "OnRegenerate",
'base_class', "Effect",
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "5000",
DefEditorName = "History Occurence",
DefGlobalMap = "HistoryOccurences",
DefParentClassList = {
"MsgReactionsPreset",
"CampaignSpecific",
},
id = "HistoryOccurence",
PlaceObj('PropertyDefText', {
'id', "text",
'name', "Text",
}),
PlaceObj('PropertyDefBool', {
'id', "repeatable",
'name', "Repeatable",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetText",
'name', "GetText",
'params', "self, context",
'default', function (self, context)
return T{self.text, context}
end,
}),
PlaceObj('PropertyDefNestedList', {
'id', "conditions",
'name', "Conditions",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return self.repeatable end,
'base_class', "Condition",
}),
PlaceObj('PropertyDefCombo', {
'id', "sector",
'name', "Sector",
'items', function (self) return GetCampaignSectorsCombo() end,
'translate', true,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Setting up conditions for new history occurrences in the History tab.",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "IMPErrorNetClientTexts",
PlaceObj('PropertyDefText', {
'id', "text",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "IMPErrorPswdTexts",
PlaceObj('PropertyDefText', {
'id', "text",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"AnimationStyle",
},
DefPresetClass = "AnimationStyle",
id = "IdleStyle",
PlaceObj('PropertyDefNestedList', {
'category', "Animations",
'id', "Animations",
'base_class', "AnimationStyleAnim",
'format', "<Animation> <color 45 138 138>(Weight: <Weight>)",
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "Start",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "Stop",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetRandomAnim",
'params', "unit",
'code', function (self, unit)
return self:GetRandomAnimId("Animations", unit)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetMainAnim",
'code', function (self)
return self:GetMainAnimId("Animations")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'code', function (self)
self:GenerateTotalWeight("Animations")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "HasAnimation",
'params', "anim",
'code', function (self, anim)
return table.find(self.Animations, "Animation", anim) and true or false
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "GetIdleStyleCombo(set)",
'code', function ()
function GetIdleStyleCombo(set)
return GetAnimationStyleCombo(set, "IdleStyle")
end
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "ImpAnswer",
PlaceObj('PropertyDefText', {
'id', "answer",
'name', "Text",
'lines', 1,
'max_lines', 5,
}),
PlaceObj('PropertyDefBool', {
'id', "is_default",
'name', "Default answer",
}),
PlaceObj('PropertyDefNestedList', {
'id', "stats_changes",
'name', "Stat changes",
'base_class', "ImpStatChange",
}),
PlaceObj('PropertyDefNestedList', {
'id', "perk_changes",
'name', "Perk changes",
'base_class', "ImpPerkChange",
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local texts = {}
local txt = _InternalTranslate(self.answer or "")
if txt and txt~="" then
txt = utf8.len(txt) <= 30 and txt or (utf8.sub(txt, 1, 30) .. "...")
texts[#texts+1] = Untranslated(" <color 150 150 100>["..txt.."]</color> ")
end
for _, stat in ipairs(self.stats_changes) do
texts[#texts+1] = stat:GetEditorView()
end
for _, perk in ipairs(self.perks_changes) do
texts[#texts+1] = perk:GetEditorView()
end
return table.concat(texts, " ")
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "ImpPerkChange",
PlaceObj('PropertyDefPresetId', {
'id', "perk",
'name', "Perk",
'template', true,
'preset_class', "CharacterEffectCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
return preset.object_class and IsKindOf(g_Classes[preset.object_class], "Perk")
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "change",
'name', "Value change",
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return T{202072264314, "<perk>:<change>", self}
end,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/conversation discussion language.png",
DefEditorMenubar = "Characters",
DefEditorName = "IMP Questions Editor",
DefGlobalMap = "ImpQuestions",
DefHasSortKey = true,
id = "ImpQuestionDef",
PlaceObj('PropertyDefText', {
'id', "question",
'name', "Question",
'lines', 1,
'max_lines', 10,
}),
PlaceObj('PropertyDefNestedList', {
'id', "answers",
'name', "Answers",
'base_class', "ImpAnswer",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "ImpStatChange",
PlaceObj('PropertyDefCombo', {
'id', "stat",
'name', "Stat",
'items', function (self) return GetUnitStatsComboTranslated() end,
'translate', true,
}),
PlaceObj('PropertyDefNumber', {
'id', "change",
'name', "Value change",
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return T{818103125130, "<stat>:<change>", self}
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "IntelPOIPresets",
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "IntelPointOfInterestDef",
PlaceObj('PropertyDefText', {
'id', "Text",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
}),
})
PlaceObj('ClassAsGroupPresetDef', {
DefParentClassList = {
"SlabMaterials",
},
GroupPresetClass = "SlabPreset",
id = "LaddersMaterials",
})
PlaceObj('PresetDef', {
DefEditorName = "Lightmodel Selection Rules",
DefGlobalMap = "LightmodelSelectionRules",
DefModItem = true,
DefModItemName = "Lightmodel Selection Rule",
DefModItemSubmenu = "Campaign & Maps",
id = "LightmodelSelectionRule",
PlaceObj('PropertyDefChoice', {
'id', "region",
'name', "Region",
'default', "any",
'items', function (self) return PresetsCombo("GameStateDef", "region", "any") end,
}),
PlaceObj('PropertyDefChoice', {
'id', "weather",
'name', "Weather",
'default', "any",
'items', function (self) return PresetsCombo("GameStateDef", "weather", "any") end,
}),
PlaceObj('PropertyDefChoice', {
'id', "tod",
'name', "Time of Day",
'default', "any",
'items', function (self) return PresetsCombo("GameStateDef", "time of day", "any") end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "lightmodel",
'name', "Lightmodel",
'preset_class', "LightmodelPreset",
'default', "ArtPreview",
}),
PlaceObj('PropertyDefNumber', {
'id', "priority",
'name', "Priority",
'default', 100,
'step', 100,
'slider', true,
'min', 100,
'max', 500,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "SelectLightmodel",
'code', function ()
function SelectLightmodel(region, weather, tod)
local best_match, best_match_quality = false, 0
for id, rule in pairs(LightmodelSelectionRules) do
local match_quality = 0
if rule.region == region then
match_quality = match_quality + 100
elseif rule.region == "any" then
match_quality = match_quality + 10
else
match_quality = match_quality - 100
end
if rule.weather == weather then
match_quality = match_quality + 90
elseif rule.weather == "any" then
match_quality = match_quality + 9
else
match_quality = match_quality - 100
end
if rule.tod == tod then
match_quality = match_quality + 80
elseif rule.tod == "any" then
match_quality = match_quality + 8
else
match_quality = match_quality - 100
end
match_quality = match_quality * rule.priority / 100
if match_quality > best_match_quality then
best_match, best_match_quality = id, match_quality
end
end
assert(best_match)
return LightmodelSelectionRules[best_match].lightmodel
end
if FirstLoad then
LightmodelSelectionRuleGameState = false
LightmodelSelectionRuleThread = false
end
function ChangeGameStateExclusive(state_descr)
local state_types = {}
for state_name, set in pairs(state_descr) do
local map_state = GameStateDefs[state_name]
if not map_state then
assert(false, "Game state does not exist!")
return
end
if state_types[map_state.group] then
assert(false, "State type already encountered!")
end
state_types[map_state.group] = true
end
for id, state in pairs(GameStateDefs) do
if state_types[state.group] and not state_descr[id] and not state.AutoSet then
state_descr[id] = false
end
end
local old_values = {}
for id in pairs(GameStateDefs) do
old_values[id] = GameState[id]
end
return ChangeGameState(state_descr), old_values
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local tag = function(value, preset_table)
if value == "any" then
return "any"
end
local rgb = table.concat({GetRGB(preset_table[value].Color)}, " ")
return "<color " .. rgb .. ">" .. value .. "</color>"
end
return
tag(self.region, GameStateDefs) .. " - " ..
tag(self.weather, GameStateDefs) .. " - " ..
tag(self.tod, GameStateDefs) ..
(self.priority > 100 and string.format(" (priority: %s)", self.priority) or "") ..
"<tab 300>" .. self.lightmodel
end,
}),
PlaceObj('ClassMethodDef', {
'name', "SortPresets",
'code', function (self)
local presets = Presets[self.PresetClass or self.class] or empty_table
local function cmp(a, b)
if a == "any" and b == "any" then return false end
if a == "any" then return true end
if b == "any" then return false end
return tostring(a) < tostring(b)
end
for _, group in ipairs(presets) do
table.sort(group, function(a, b)
if a.priority == b.priority then
if a.region == b.region then
if a.weather == b.weather then
return cmp(a.tod, b.tod)
end
return cmp(a.weather, b.weather)
end
return cmp(a.region, b.region)
end
return cmp(a.priority, b.priority)
end)
end
ObjModified(presets)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSelect",
'params', "selected, ged",
'code', function (self, selected, ged)
local function RebuildAttaches()
SuspendPassEdits("rebuild autoattaches")
MapForEach("map", "AutoAttachObject", function(o)
o:SetAutoAttachMode(o.auto_attach_mode)
end)
ResumePassEdits("rebuild autoattaches")
end
if selected then
local state_descr = {}
if self.tod ~= "any" then
state_descr[self.tod] = true
end
if self.weather ~= "any" then
state_descr[self.weather] = true
end
if self.region ~= "any" then
state_descr[self.region] = true
end
local _, old_values = ChangeGameStateExclusive(state_descr)
if not LightmodelSelectionRuleGameState then
LightmodelSelectionRuleGameState = old_values
end
gv_ForceWeatherTodRegion = { tod = self.tod, weather = self.weather, region = self.region }
if LightmodelSelectionRuleThread then
DeleteThread(LightmodelSelectionRuleThread)
end
LightmodelSelectionRuleThread = CreateRealTimeThread(function()
Sleep(300)
SetLightmodelOverride(false, self.lightmodel)
RebuildAttaches()
LightmodelSelectionRuleThread = false
end)
else
if LightmodelSelectionRuleGameState then
ChangeGameState(LightmodelSelectionRuleGameState)
LightmodelSelectionRuleGameState = false
gv_ForceWeatherTodRegion = false
end
if LightmodelSelectionRuleThread then
DeleteThread(LightmodelSelectionRuleThread)
end
LightmodelSelectionRuleThread = CreateRealTimeThread(function()
Sleep(300)
SetLightmodelOverride(false, false)
RebuildAttaches()
LightmodelSelectionRuleThread = false
end)
end
end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Contains information on use of Light models and tweaking of properties like World Region, Weather Condition and Time Of Day.",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/friends group presentation.png",
DefEditorMenubar = "Scripting",
DefEditorName = "Loading Screen Hints",
DefGlobalMap = "LoadingScreenHints",
DefHasSortKey = true,
id = "LoadingScreenHint",
PlaceObj('PropertyDefText', {
'id', "text",
'lines', 4,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"LootDefEntry",
},
group = "PresetDefs",
id = "LootEntryInventoryItem",
PlaceObj('PropertyDefChoice', {
'category', "Loot",
'id', "item",
'name', "Item",
'default', "",
'items', function (self) return InventoryItemCombo end,
}),
PlaceObj('ClassMethodDef', {
'name', "Setitem",
'params', "value",
'code', function (self, value)
self.item = value
if #(value or "") > 0 and InventoryItemDefs[value].object_class == "QuestItem" then
self.guaranteed = true
end
end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Loot",
'id', "stack_min",
'name', "Stack (Min)",
'default', 0,
'min', 0,
'max', 1000000,
}),
PlaceObj('PropertyDefNumber', {
'category', "Loot",
'id', "stack_max",
'name', "Stack (Max)",
'default', 0,
'min', 0,
'max', 1000000,
}),
PlaceObj('PropertyDefNumber', {
'category', "Loot",
'id', "Condition",
'name', "Condition",
'help', "Item's condition in percents",
'default', 100,
'slider', true,
'min', 1,
'max', 100,
}),
PlaceObj('PropertyDefBool', {
'category', "Loot",
'id', "RandomizeCondition",
'name', "Randomize Condition",
'help', "Randomize item condition within +/- 30",
}),
PlaceObj('PropertyDefBool', {
'category', "Loot",
'id', "Double",
'name', "Double",
'help', "Double or halve the item depending on difficulty and chances (25% on easy to double, 50% on hard to halve)",
}),
PlaceObj('PropertyDefNumber', {
'category', "Conditions",
'id', "generate_chance",
'name', "Generate Chance",
'help', "Generate chance is used instead of creating new loot def entry with this item and empty table.",
'default', 100,
'min', 0,
'max', 100,
}),
PlaceObj('ClassConstDef', {
'name', "EntryView",
'type', "text",
'value', "<color 75 105 198><item><stack_suffix>",
'untranslated', true,
}),
PlaceObj('ClassConstDef', {
'name', "EditorName",
'type', "text",
'value', "Item",
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateLoot",
'params', "looter, looted, seed, items",
'code', function (self, looter, looted, seed, items)
-- exclude this item from generation
if self.generate_chance <= 0 then
return
elseif self.generate_chance < 100 then
local rand
rand, seed = BraidRandom(seed, 100)
if rand >= self.generate_chance then
return
end
end
-- stacks
local amount
local min, max = self:GetStackSize()
if min >= max then
amount = max
else
amount, seed = BraidRandom(seed, max - min + 1)
amount = min + amount
end
if self.Double then
local roll
roll, seed = BraidRandom(seed, 100)
local value = GameDifficulties[Game.game_difficulty]:ResolveValue("chanceToHalveDoubleLoot") or 0
if roll < value then
amount = amount / 2
end
end
local chance = self:GetDropChance()
local maxPossibleWeaponCondPenalty = Game and GameDifficulties[Game.game_difficulty]:ResolveValue("maxPossibleWeaponCondPenalty") or 0
local lootConditionRandomization = const.Weapons.LootConditionRandomization
while amount > 0 do
local item = PlaceInventoryItem(self.item)
item.drop_chance = chance
item.guaranteed_drop = self.guaranteed
if IsKindOf(item, "InventoryStack") then
item.Amount = Min(amount, item.MaxStacks)
amount = amount - item.Amount
else
amount = amount - 1
local condition = self.Condition
if self.RandomizeCondition then
local rnd
rnd, seed = BraidRandom(seed, 2*lootConditionRandomization)
local diffRnd = 0
diffRnd, seed = - (BraidRandom(seed, maxPossibleWeaponCondPenalty))
condition = Clamp(condition - lootConditionRandomization + rnd + diffRnd ,1, 100)
end
item.Condition = condition
NetUpdateHash("ItemGenerated", item.class, item.Condition)
end
items[#items + 1] = item
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "ListChances",
'params', "items, env, chance",
'code', function (self, items, env, chance)
local item
local min, max = self:GetStackSize()
if min > 1 or max > 1 then
item = string.format("Item: %s (%d-%d)", self.item, Max(1, self.stack_min), Max(self.stack_min, self.stack_max))
else
item = string.format("Item: %s", self.item)
end
items[item] = (items[item] or 0.0) + chance
end,
}),
PlaceObj('PropertyDefBool', {
'id', "guaranteed",
'name', "Guaranteed Drop",
}),
PlaceObj('PropertyDefNumber', {
'id', "drop_chance_mod",
'name', "Drop Chance Modifier",
'default', 100,
'min', 0,
}),
PlaceObj('PropertyDefNumber', {
'id', "BaseDropChance",
'name', "Base Drop Chance",
'dont_save', true,
'read_only', true,
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetBaseDropChance",
'code', function (self)
local template = InventoryItemDefs[self.item]
local class = template and g_Classes[template.object_class]
return class and class.base_drop_chance or 0
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "DropChance",
'read_only', true,
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetDropChance",
'code', function (self)
if self.guaranteed then
return 100
end
local base = self:GetBaseDropChance()
return MulDivRound(base, self.drop_chance_mod, 100)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "Getstack_suffix",
'code', function (self)
local min, max = self:GetStackSize()
if min > 1 or max > 1 then
return T{819375042261, "(<min>-<max>)", min = min, max = max}
end
return ""
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetStackSize",
'code', function (self)
local min = Max(1, self.stack_min)
local max = Max(min, self.stack_max)
return min, max
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"LootDefEntry",
},
group = "PresetDefs",
id = "LootEntryUpgradedWeapon",
PlaceObj('PropertyDefPresetId', {
'category', "Loot",
'id', "weapon",
'name', "Weapon",
'preset_class', "InventoryItemCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
return preset.group and preset.group:starts_with("Firearm")
end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Loot",
'id', "Condition",
'name', "Condition",
'help', "Item's condition in percents",
'default', 100,
'slider', true,
'min', 1,
'max', 100,
}),
PlaceObj('PropertyDefBool', {
'category', "Loot",
'id', "RandomizeCondition",
'name', "Randomize Condition",
'help', "Randomize item condition within +/- 30",
}),
PlaceObj('PropertyDefPresetIdList', {
'category', "Loot",
'id', "upgrades",
'name', "Upgrades",
'preset_class', "WeaponComponent",
}),
PlaceObj('ClassConstDef', {
'name', "EntryView",
'type', "text",
'value', "Upgraded <weapon>",
'untranslated', true,
}),
PlaceObj('ClassConstDef', {
'name', "EditorName",
'type', "text",
'value', "Upgraded Weapon",
}),
PlaceObj('ClassMethodDef', {
'name', "ListChances",
'params', "items, env, chance",
'code', function (self, items, env, chance)
local item = "Weapon " .. (self.weapon or "")
for i, upgrade in ipairs(self.upgrades) do
item = string.format("%s%s%s", item, i == 1 and " with upgrades " or ", ", upgrade)
end
items[item] = (items[item] or 0.0) + chance
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateLoot",
'params', "looter, looted, seed, items",
'code', function (self, looter, looted, seed, items)
local weapon_items, upgrades = {}, {}
local weapon = self.weapon
if not weapon then return end
local item = PlaceInventoryItem(self.weapon)
local condition = self.Condition
if self.RandomizeCondition then
local rnd
rnd, seed = BraidRandom(seed, 2*const.Weapons.LootConditionRandomization)
condition = Clamp(condition - const.Weapons.LootConditionRandomization + rnd ,1, 100)
local diffRnd = 0
diffRnd, seed = - (BraidRandom(seed, GameDifficulties[Game.game_difficulty]:ResolveValue("maxPossibleWeaponCondPenalty") or 0))
condition = Clamp(condition + diffRnd ,1, 100)
end
item.Condition = condition
NetUpdateHash("ItemGenerated", item.class, item.Condition)
item.drop_chance = self:GetDropChance()
item.guaranteed_drop = self.guaranteed
for _, id in ipairs(self.upgrades) do
item:SetWeaponComponent(false, id)
end
table.insert(items, item)
end,
}),
PlaceObj('PropertyDefBool', {
'id', "guaranteed",
'name', "Guaranteed Drop",
}),
PlaceObj('PropertyDefNumber', {
'id', "drop_chance_mod",
'name', "Drop Chance Modifier",
'default', 100,
'min', 0,
}),
PlaceObj('PropertyDefNumber', {
'id', "BaseDropChance",
'name', "Base Drop Chance",
'dont_save', true,
'read_only', true,
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetBaseDropChance",
'code', function (self)
local template = InventoryItemDefs[self.weapon]
local class = template and g_Classes[template.object_class]
return class and class.base_drop_chance or 0
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "DropChance",
'read_only', true,
'default', 0,
}),
PlaceObj('ClassMethodDef', {
'name', "GetDropChance",
'code', function (self)
if self.guaranteed then
return 100
end
local base = self:GetBaseDropChance()
return MulDivRound(base, self.drop_chance_mod, 100)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
local compatible
for _, slot in ipairs(g_Classes[self.weapon] and g_Classes[self.weapon].ComponentSlots) do
for _, component in ipairs(slot.AvailableComponents) do
compatible = compatible or {}
compatible[component] = slot
end
end
local slots
local errors
for _, component in ipairs(self.upgrades) do
if not WeaponComponents[component] then
errors = errors or {}
errors[#errors+1] = "Invalid component: " .. component
end
local slot = compatible[component]
if not slot then
errors = errors or {}
errors[#errors+1] = "Incompatible component: " .. component
else
slots = slots or {}
if slots[slot] then
errors = errors or {}
errors[#errors+1] = "More than one upgrade for slot " .. slot
end
slots[slot] = component
end
end
if next(errors) then
return table.concat(errors, "\n")
end
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"LootDefEntry",
},
group = "PresetDefs",
id = "LootEntryWeaponComponent",
PlaceObj('PropertyDefChoice', {
'category', "Loot",
'id', "item",
'name', "Item",
'default', "",
'items', function (self) return PresetGroupCombo("WeaponComponent", "Default") end,
}),
PlaceObj('ClassConstDef', {
'name', "EntryView",
'type', "text",
'value', "<color 75 105 198><item>",
'untranslated', true,
}),
PlaceObj('ClassConstDef', {
'name', "EditorName",
'type', "text",
'value', "Weapon Component",
}),
PlaceObj('ClassMethodDef', {
'name', "GenerateLoot",
'params', "looter, looted, seed, items",
'code', function (self, looter, looted, seed, items)
items[#items + 1] = self.item
end,
}),
PlaceObj('ClassMethodDef', {
'name', "ListChances",
'params', "items, env, chance",
'code', function (self, items, env, chance)
local item = string.format("Item: %s", self.item)
items[item] = (items[item] or 0.0) + chance
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "MercHireStatus",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('PropertyDefText', {
'id', "RolloverText",
}),
PlaceObj('PropertyDefUIImage', {
'id', "icon",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "MercNationalities",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
'name', "Display Name",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
'name', "Icon",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "MercSpecializations",
PlaceObj('PropertyDefUIImage', {
'id', "icon",
}),
PlaceObj('PropertyDefText', {
'id', "name",
}),
PlaceObj('PropertyDefText', {
'id', "rolloverText",
}),
})
PlaceObj('PresetDef', {
group = "PresetDefs",
id = "MercStat",
PlaceObj('PropertyDefText', {
'id', "ShortenedName",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "MercTiers",
PlaceObj('PropertyDefText', {
'id', "name",
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Scripting",
DefEditorName = "Merc Tracked Stats",
DefGlobalMap = "MercTrackedStats",
DefHasSortKey = true,
DefParentClassList = {
"MsgReactionsPreset",
},
id = "MercTrackedStat",
PlaceObj('PropertyDefText', {
'id', "name",
'name', "Name",
}),
PlaceObj('PropertyDefText', {
'id', "description",
'name', "Description",
}),
PlaceObj('PropertyDefBool', {
'id', "hide",
'name', "Hide",
'help', "Don't show in AIM Evaluation Page.",
}),
PlaceObj('PropertyDefFunc', {
'category', "Reactions",
'id', "DisplayValue",
'name', "Display Value",
'params', "self, merc",
'default', function (self, merc)
local value = GetTrackedStat(merc, self.id)
return value and T{227251647374, "<value>", value = value} or T(555613400236, "-")
end,
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Combat",
DefGlobalMap = "MoraleEffects",
id = "MoraleEffect",
PlaceObj('PropertyDefNumber', {
'id', "Weight",
'default', 100,
'min', 1,
}),
PlaceObj('PropertyDefNumber', {
'id', "Cooldown",
'help', "in turns",
'default', -1,
}),
PlaceObj('PropertyDefNumber', {
'id', "GlobalCooldown",
'help', "in turns",
'default', -1,
}),
PlaceObj('PropertyDefChoice', {
'id', "Activation",
'default', "positive",
'items', function (self) return { "positive", "negative" } end,
}),
PlaceObj('PropertyDefChoice', {
'id', "AppliedTo",
'default', "ally",
'items', function (self) return { "ally", "teammate", "enemy", "custom"} end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetTargetUnit",
'extra_code', 'no_edit = function(self) return self.AppliedTo ~= "custom" end',
'params', "self, team",
}),
PlaceObj('PropertyDefFunc', {
'id', "Activate",
'params', "self, unit",
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"AnimationStyle",
},
DefPresetClass = "AnimationStyle",
id = "MoveStyle",
PlaceObj('PropertyDefNestedList', {
'category', "Animations",
'id', "Move",
'base_class', "AnimationStyleAnim",
'format', "<Animation> <color 45 138 138>(Weight: <Weight>)",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Animations",
'id', "Idle",
'base_class', "AnimationStyleAnim",
'format', "<Animation> <color 45 138 138>(Weight: <Weight>)",
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "MoveStart",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "MoveStart_Left",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "MoveStart_Right",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "MoveStop_FootLeft",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "MoveStop_FootRight",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "TurnOnSpot_Left",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Animations",
'id', "TurnOnSpot_Right",
'items', function (self) return self:AnimationsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "StepFX",
'default', "",
'items', function (self) return {"", "StepWalk", "StepRun"} end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetRandomMoveAnim",
'params', "unit",
'code', function (self, unit)
return self:GetRandomAnimId("Move", unit)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetMainMoveAnim",
'code', function (self)
return self:GetMainAnimId("Move")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "HasMoveAnim",
'params', "anim",
'code', function (self, anim)
return table.find(self.Move, "Animation", anim) and true or false
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnPreSave",
'code', function (self)
self:GenerateTotalWeight("Move")
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "GetMoveStyleCombo(set)",
'code', function ()
function GetMoveStyleCombo(set)
return GetAnimationStyleCombo(set, "MoveStyle")
end
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "MultiplayerGameTypes",
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "MultiplayerGameType",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "PlayerColors",
DefParentClassList = {
"ListPreset",
},
id = "PlayerColor",
PlaceObj('PropertyDefColor', {
'id', "color",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/blog news newspaper page",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4020",
DefGlobalMap = "PopupNotifications",
DefModItem = true,
DefModItemName = "Popup notification",
DefModItemSubmenu = "Campaign & Maps",
DefParentClassList = {
"Preset",
"CampaignSpecific",
},
id = "PopupNotification",
PlaceObj('PropertyDefText', {
'id', "Title",
}),
PlaceObj('PropertyDefUIImage', {
'id', "Image",
'image_preview_size', 100,
}),
PlaceObj('PropertyDefText', {
'id', "Text",
'wordwrap', true,
'lines', 5,
}),
PlaceObj('PropertyDefText', {
'id', "GamepadText",
'wordwrap', true,
'lines', 5,
}),
PlaceObj('PropertyDefCombo', {
'id', "Actor",
'default', "narrator",
'items', function (self) return VoiceActors end,
}),
PlaceObj('PropertyDefBool', {
'id', "OnceOnly",
'help', "The popup will be shown only once no matter how many times it is called for in effects",
}),
PlaceObj('PropertyDefButtons', {
'id', "btn_test",
'help', "Shows the pop-up in game",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Test",
'FuncName', "Test",
}),
},
}),
PlaceObj('PropertyDefFunc', {
'id', "Test",
'no_edit', true,
'default', function (self)
ShowPopupNotification(self.id)
end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "Quest",
'help', "For which quest we store how many times the popup has been shown",
'preset_class', "QuestsDef",
}),
PlaceObj('PropertyDefCombo', {
'id', "QuestVariable",
'help', "In which quest variable we store how many times the popup has been shown",
'default', "",
'items', function (self) return GetQuestsVarsCombo(self.Quest, "Num") end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Allows adding of new presets with tile, text and image that are used mainly in tutorials and starting help.",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "QuestBadgePlacement",
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('PropertyDefCombo', {
'id', "BadgeUnit",
'name', "Badge on Unit",
'help', "The unit/group to place the badge on, if it exists on the current map.",
'items', function (self) return GridMarkerGroupsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "BadgePreset",
'name', "Badge Preset",
'default', "DefaultQuestBadge",
'items', function (self) return PresetsCombo("BadgePresetDef")() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "Sector",
'name', "Sector",
'help', "The sector on which badges should be placed. (optional)",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefBool', {
'id', "PlaceOnAllOfGroup",
'help', "By default the badge is only placed on the first match.",
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return (self.Sector and Untranslated("Sector: <u(Sector)>", self) or Untranslated("")) .. (self.BadgeUnit and Untranslated(" Unit: <u(BadgeUnit)>", self) or Untranslated(""))
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "QuestNote",
PlaceObj('PropertyDefText', {
'id', "Text",
'default', "",
'lines', 3,
'max_lines', 8,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return Untranslated("(<Idx>)")..Untranslated(_InternalTranslate(self.Text))
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
if not self.Scouting and not next(self.ShowConditions) and not self.ShowWhenCompleted then
return "Note without 'scouting' and 'show conditions'."
end
if not next(self.HideConditions) and not next(self.CompletionConditions) then
return "Note without 'hide' and 'complete' conditions."
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorNew",
'params', "parent, ged, is_paste",
'code', function (self, parent, ged, is_paste)
local maxidx = parent.LastNoteIdx or 0
self.Idx = maxidx +1
parent.LastNoteIdx = self.Idx
end,
}),
PlaceObj('PropertyDefNumber', {
'id', "Idx",
'read_only', true,
'default', 1,
}),
PlaceObj('PropertyDefBool', {
'id', "Scouting",
'help', "If set to true then this note can be uncovered by the scouting operation.",
}),
PlaceObj('PropertyDefBool', {
'id', "ShowWhenCompleted",
'help', "(NO EFFECT AT THE MOMENT)If set to true the note will become visible, once completed.",
}),
PlaceObj('PropertyDefBool', {
'id', "AddInHistory",
'help', "Adds the note in the History when completed.",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "ShowConditions",
'name', "Show Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "HideConditions",
'name', "Hide Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "CompletionConditions",
'name', "Completion Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Badges",
'name', "Badges",
'base_class', "QuestBadgePlacement",
'inclusive', true,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"QuestVarDeclaration",
},
group = "PresetDefs",
id = "QuestVarBool",
PlaceObj('PropertyDefText', {
'id', "Name",
'translate', false,
}),
PlaceObj('PropertyDefBool', {
'id', "Value",
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return Untranslated("bool <Name> = ")..Untranslated(tostring(self.Value))
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "QuestVarDeclaration",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
local quest_def = GetParentTableOfKind(self, "QuestsDef")
local id = quest_def.id
local variables = quest_def.Variables
local found_self_name = 0
for idx,var in ipairs(variables) do
if var.Name and var.Name == self.Name then
found_self_name = found_self_name + 1
end
end
if found_self_name>1 then
return "Duplicated variable name.Place choose another!"
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
if not LocalStorage.QuestEditorFilter or not LocalStorage.QuestEditorFilter.CheckVars then
return
end
if self.Name == "Completed" or self.Name == "Given" or self.Name == "Failed" or self.Name == "NotStarted" then
return
end
local quest_def = GetParentTableOfKind(self, "QuestsDef")
local id = quest_def.id
local res = QuestGatherGameDepending({}, id, self.Name)
if not res then
return "Variable not used (checked: conversation, maps, quests, sector events)"
end
end,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
local quest_def = GetParentTableOfKind(self, "QuestsDef")
local id = quest_def.id
local quest = QuestGetState(id)
if rawget(quest, self.Name) == nil then
SetQuestVar(quest,self.Name,self.Value)
ObjModified(quest)
end
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"QuestVarDeclaration",
},
group = "PresetDefs",
id = "QuestVarNum",
PlaceObj('PropertyDefText', {
'id', "Name",
'translate', false,
}),
PlaceObj('PropertyDefNumber', {
'id', "Value",
'name', "Value, min",
'default', 0,
}),
PlaceObj('PropertyDefNumber', {
'id', "RandomRangeMax",
'name', "Value, max (optional)",
'help', 'If set the starting value will be random number between "Value, min" and this number. Both values are inclusive. Leave blank to set value to exactly "Value, min".',
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return Untranslated("int <Name> = ")..Untranslated(tostring(self.Value))
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if self.RandomRangeMax and self.RandomRangeMax <= self.Value then
return "Value max must be greater than min"
end
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"QuestVarDeclaration",
},
group = "PresetDefs",
id = "QuestVarTCEState",
PlaceObj('PropertyDefText', {
'id', "Name",
'translate', false,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('PropertyDefChoice', {
'id', "Value",
'name', "Value",
'no_edit', true,
'items', function (self) return {true, false, "done"} end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return string.format("TCE %s = %s",self.Name,tostring(self.Value))
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
if not self.Name then return end
local quest_def = GetParentTableOfKind(self, "QuestsDef")
local tces = quest_def.TCEs
local used_tce = false
for _, tce in ipairs(tces) do
if tce.ParamId==self.Name then
used_tce = true
break
end
end
if not used_tce then
return "TCE var is declared but not used ("..self.Name..")"
end
end,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"QuestVarDeclaration",
},
group = "PresetDefs",
id = "QuestVarText",
PlaceObj('PropertyDefText', {
'id', "Name",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'id', "Value",
'default', "",
'translate', false,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return Untranslated("str <Name> = <Value>")
end,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/magnifier microbes research.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "3020",
DefEditorName = "Quests Editor",
DefEditorShortcut = "Ctrl-Alt-Q",
DefFilterClass = "QuestEditorFilter",
DefGedEditor = "QuestsEditor",
DefGlobalMap = "Quests",
DefParentClassList = {
"Preset",
"CampaignSpecific",
},
DefSingleFile = false,
id = "QuestsDef",
PlaceObj('PropertyDefCombo', {
'category', "Preset",
'id', "Chapter",
'extra_code', "sort_order = -1",
'default', "Landing",
'items', function (self) return PresetsPropCombo("QuestsDef", "Chapter", "Landing") end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Preset",
'id', "QuestGroup",
'items', function (self) return QuestGroups end,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Preset",
'id', "Variables",
'base_class', "QuestVarDeclaration",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Preset",
'id', "NoteDefs",
'name', "NoteDefs",
'extra_code', "no_edit = function(self) return self.Hidden end",
'base_class', "QuestNote",
'inclusive', true,
'no_descendants', true,
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "DevNotes",
'name', "Developer Notes",
'translate', false,
'wordwrap', true,
'lines', 5,
}),
PlaceObj('PropertyDefText', {
'category', "General",
'id', "DisplayName",
'name', "Display Name",
}),
PlaceObj('PropertyDefUIImage', {
'category', "General",
'id', "Image",
'name', "Image",
'extra_code', "no_edit = function(self) return not self.Main end",
'default', "UI/PDA/Quest/tasks_img_01",
'image_preview_size', 200,
}),
PlaceObj('PropertyDefBool', {
'category', "General",
'id', "Hidden",
'name', "Hidden",
'help', "If true the quest is never shown in the quest log.",
}),
PlaceObj('PropertyDefBool', {
'category', "General",
'id', "Main",
'name', "Main",
'help', "Whether this quest is part of the main quest line.",
}),
PlaceObj('PropertyDefPresetId', {
'id', "Author",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return config.ModdingToolsInUserMode end,
'preset_class', "HGMember",
}),
PlaceObj('PropertyDefChoice', {
'category', "Status",
'id', "LineVisibleOnGive",
'name', "Line visible on 'given'",
'help', 'Showing which log line is automatically set to visible when the quest enters "given"',
'default', 0,
'items', function (self) return GetQuestNoteLinesCombo(self.id) end,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Status",
'id', "EffectOnChangeVarValue",
'name', "Effect On rise bool var",
'base_class', "QuestEffectOnStatus",
'inclusive', true,
'format', "<Prop>",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Triggered Conditional Event",
'id', "TCEs",
'name', "Triggered Conditional Event",
'base_class', "TriggeredConditionalEvent",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Triggered Conditional Event",
'id', "KillTCEsConditions",
'name', "Kill TCEs Conditions",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('ClassMethodDef', {
'name', "OnChangeVarValue",
'params', "var_id, prev_val, new_val",
'code', function (self, var_id, prev_val, new_val)
local rise_flag = not prev_val and new_val
if rise_flag then
if var_id=="Given" and self.LineVisibleOnGive>0 then
local quest = QuestGetState(self.id or "")
local note_idx = quest.LineVisibleOnGive
if table.find(quest.NoteDefs or empty_table, "Idx", note_idx) then
quest.note_lines[note_idx] = GetQuestNoteCampaignTimestamp(quest.note_lines)
end
ObjModified(gv_Quests)
end
for _, status_effect in ipairs(self.EffectOnChangeVarValue or empty_table) do
if status_effect.Prop == var_id then
ExecuteEffectList(status_effect.Effects, QuestGetState(self.id), var_id)
end
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local quest = gv_Quests and QuestGetState(self.id)
local texts = { Untranslated(self.id) }
if GedQuestRefData then
local data = GedQuestRefData[self.id]
if data then
texts = { Untranslated("<color 212 180 64>"), Untranslated(self.id), Untranslated("</color>") }
if data.from then table.insert(texts, Untranslated("<color 0 128 0><literal 1><</color>")) end
if data.to then table.insert(texts, Untranslated("<color 196 64 64><literal 1>></color>")) end
end
end
local color
local status = "not_started"
local given = QuestIsBoolVar(quest,"Given", true)
local completed =QuestIsBoolVar(quest,"Completed", true)
local failed = QuestIsBoolVar(quest,"Failed", true)
if given and not completed and not failed then
color = RGB(75, 105, 198)
status = "given"
end
if completed and not failed then
color = RGB(0, 128, 0)
status = "completed"
end
if failed then
color =RGB( 250,10,10)
status = "failed"
end
local clr = color and string.format("<color %d %d %d>", GetRGB(color)) or ""
local uclr = color and "</color>" or ""
texts[#texts+1] = Untranslated(clr .. " ("..status..")" .. uclr)
if self.NoteDefs and #self.NoteDefs > 0 then
if self.Hidden then
texts[#texts+1] = Untranslated("<color 255 0 0> (Notes: " .. #self.NoteDefs .. " " .. " (hidden))</color> ")
else
texts[#texts+1] = Untranslated(" (Notes: " .. #self.NoteDefs .. ")")
end
end
if self.Comment ~= "" then
texts[#texts+1] = Untranslated("<color 0 128 0> -- " .. self.Comment)
end
return table.concat(texts, "")
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not gv_Quests then
return "Please start this editor on a map with gameplay"
end
local used = {}
if self.TCEs then
for _, tce in ipairs(self.TCEs) do
if not tce.ParamId then
return "Add unique Variable to store triggered conditions/effects state in"
end
if used[tce.ParamId] then
return "Variable "..(tce.ParamId).. " is already used choose another one"
end
used[tce.ParamId] = true
end
end
if self.PlaceBadge and not self.BadgeUnit then
return "Place Badge is true, but no target unit provided"
end
local duplicateIdx = {}
local idxSet = {}
for i, n in ipairs(self.NoteDefs) do
if idxSet[n.Idx] then
duplicateIdx[#duplicateIdx + 1] = n.Idx
end
idxSet[n.Idx] = true
end
if #duplicateIdx > 0 then
return "Duplicate note ids (merge conflict?) Indices: " .. table.concat(duplicateIdx, ", ")
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorNew",
'params', "parent, ged, is_paste, old_id",
'code', function (self, parent, ged, is_paste, old_id)
if not is_paste then
-- default kill tce condition
self.KillTCEsConditions = {QuestKillTCEsOnCompleted:new{}}
-- default status variables
self.Variables = {QuestVarBool:new{Name = "Completed"},
QuestVarBool:new{Name = "Given"},
QuestVarBool:new{Name = "Failed"},
QuestVarBool:new{Name = "NotStarted", Value = true},}
else -- is_paste
self:ChangeQuestId(old_id, self.id)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
if prop_id == "Id" then
self:ChangeQuestId(old_value, self.id)
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "ChangeQuestId",
'params', "old_id, new_id",
'code', function (self, old_id, new_id)
self:ForEachSubObject("PropertyObject", function(obj)
if obj:GetProperty("QuestId") == old_id then
obj:SetProperty("QuestId", new_id)
end
end)
end,
}),
PlaceObj('ClassGlobalCodeDef', {
'comment', "build parent table cache, used by QuestKillTCEsOnCompleted",
'code', function ()
function OnMsg.DataLoaded()
PopulateParentTableCache(Presets.QuestsDef)
end
end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Allows adding of new quests, as well as setting up variables in them. Each quest can be set up with its conditions as Given, Completed or Failed. See the New Quest sample mod in the Sample Mods section for an example on how to build a quest.",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/appliance electrical juicer kitchen mixer.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4060",
DefEditorName = "Recipes Editor",
DefGlobalMap = "Recipes",
DefHasParameters = true,
DefModItem = true,
DefModItemName = "Combine recipe",
DefModItemSubmenu = "Item",
id = "RecipeDef",
PlaceObj('PropertyDefNestedList', {
'id', "Ingredients",
'name', "Ingredients",
'base_class', "RecipeIngredient",
}),
PlaceObj('PropertyDefNestedList', {
'id', "ResultItems",
'name', "Result Items",
'base_class', "RecipeIngredient",
}),
PlaceObj('PropertyDefNumber', {
'id', "Difficulty",
'default', 45,
}),
PlaceObj('PropertyDefBool', {
'id', "MechanicalRoll",
'name', "Mechanical Roll",
}),
PlaceObj('PropertyDefBool', {
'id', "ExplosivesRoll",
'name', "Explosives Roll",
}),
PlaceObj('PropertyDefChoice', {
'id', "RevertCondition",
'name', "Revert Condition",
'default', "none",
'items', function (self) return {"none", "attacks", "damage"} end,
}),
PlaceObj('PropertyDefNumber', {
'id', "RevertConditionValue",
'name', "Revert Condition Value",
'extra_code', 'no_edit = function(obj) return obj.RevertCondition=="none" end',
'default', 5,
}),
PlaceObj('PropertyDefButtons', {
'category', "General",
'id', "btnAddItem",
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Add Ingredients To Current Unit",
'FuncName', "UIPlaceIngredientsInInventory",
}),
},
'template', true,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Defines a new recipe with ingredients and result items that can be performed in the inventory.",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "RecipeIngredient",
PlaceObj('PropertyDefPresetId', {
'id', "item",
'name', "Item ID",
'template', true,
'preset_class', "InventoryItemCompositeDef",
}),
PlaceObj('PropertyDefNumber', {
'id', "amount",
'name', "Amount",
'default', 1,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return T{422241156445, "<item> : <amount>", self}
end,
}),
})
PlaceObj('PresetDef', {
DefEditorCustomActions = {
PlaceObj('EditorCustomActionDef', {
'Name', "Run Singe Rule",
'FuncName', "RunSingleRule",
'Toolbar', "main",
'Menubar', "Process",
'Icon', "CommonAssets/UI/Ged/play",
}),
},
DefEditorMenubar = "Editors.Audio",
DefEditorName = "AutoRuledEmitters Editor",
id = "RuleAutoPlaceSoundSources",
PlaceObj('PropertyDefBool', {
'category', "Placement",
'id', "DeleteOld",
'name', "Delete Old Markers",
'help', "Requires EmitterType to be select so it knows which markers to delete",
'default', true,
}),
PlaceObj('PropertyDefCombo', {
'category', "Placement",
'id', "EmitterType",
'name', "Emitter Type",
'help', "Type of the emitter to place",
'default', "",
'items', function (self) return EmitterTypeCombo end,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Placement",
'id', "ClassPatterns",
'name', "Class Patterns",
'base_class', "ClassPattern",
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "MinDist",
'name', "Minimum Distance",
'help', "The minimum distance to keep among placed sound sources which are of the same EmitteryType or listed in EmittersAway or from objects of class OriginAwayClass",
'default', 10000,
'scale', "m",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Placement",
'id', "EmittersAway",
'name', "Emitters Away",
'help', "Types of the emitters to keep away from(using MinDist), e.g. Animals will not be placed close to Animals",
'base_class', "EmitterTypeClass",
}),
PlaceObj('PropertyDefText', {
'category', "Placement",
'id', "OriginAwayClass",
'name', "Origin Away from Class",
'help', "Type of objects to keep away from(using MinDist)",
'translate', false,
}),
PlaceObj('PropertyDefBool', {
'category', "Placement",
'id', "BeachPoints",
'name', "Beach Points",
'help', "In addition to class patterns below matches beach points too(using MinDist as grid tile step)",
'extra_code', "no_edit = function(self) return self.OnWater end",
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "BeachPointsWaterStep",
'name', "Beach Points Water Step",
'help', "Step used to check for water around point - if a point is on ground and at least one of its 4 neighbours is water it is considered as a Beach Point",
'extra_code', "no_edit = function(self) return not self.BeachPoints end",
'default', 10000,
'scale', "m",
}),
PlaceObj('PropertyDefCombo', {
'category', "Placement",
'id', "BorderRelation",
'default', "any",
'items', function (self) return {"any", "Inside Border Area", "Outside Border Area"} end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "BorderTolerance",
'name', "Border Tolerance",
'help', "Border area extension/shrinkage",
'extra_code', 'no_edit = function(self) return self.BorderRelation == "any" end',
'default', 0,
'scale', "voxelSizeX",
}),
PlaceObj('PropertyDefBool', {
'category', "Requirements",
'id', "OnWater",
'name', "On Water",
'help', "requires the sample position to be on water",
'extra_code', "no_edit = function(self) return self.BeachPoints or self.OnLand end",
}),
PlaceObj('PropertyDefBool', {
'category', "Requirements",
'id', "OnLand",
'name', "On Land",
'help', "requires the sample position to be on land",
'extra_code', "no_edit = function(self) return self.BeachPoints or self.OnWater end",
}),
PlaceObj('PropertyDefNumber', {
'category', "Requirements",
'id', "WaterNearBy",
'name', "Water Near By",
'help', "Water around required in this distance, 0 if not required",
'extra_code', "no_edit = function(self) return self.OnWater end",
'default', 0,
'scale', "m",
}),
PlaceObj('PropertyDefNumber', {
'category', "Requirements",
'id', "LandNearBy",
'name', "Land Near By",
'help', "Land around required in this distance, 0 if not required",
'extra_code', "no_edit = function(self) return self.BeachPoints or self.OnLand end",
'default', 0,
'scale', "m",
}),
PlaceObj('PropertyDefStringList', {
'category', "Requirements",
'id', "Regions",
'help', "Works only on maps from specific regions",
'items', function (self) return PresetsCombo("GameStateDef", "region") end,
}),
PlaceObj('PropertyDefTexturePicker', {
'category', "Requirements",
'id', "Terrain",
'items', function (self) return GetTerrainTexturesItems end,
'multiple', true,
'thumb_width', 128,
'thumb_height', 128,
'base_color_map', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Requirements",
'id', "ClassCountAround",
'name', "Class Count Around",
'base_class', "ClassCountAround",
}),
PlaceObj('PropertyDefFunc', {
'category', "Requirements",
'id', "Filter",
'help', "returns true whether this object should emit a sound source",
'params', "self, obj",
'default', function (self, obj)
return true
end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Emmiters",
'id', "SoundSamples",
'name', "Sound Banks",
'help', "How many sound samples to choose randomly(by weight) from sound candidates",
'default', 3,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Emmiters",
'id', "SoundCandidates",
'name', "Sound Bank Candidates",
'help', "Sound candidates each with its own weight used by randomization",
'base_class', "AutoPlacedSoundSourceWeight",
}),
PlaceObj('ClassMethodDef', {
'name', "OnEditorSetProperty",
'params', "prop_id, old_value, ged",
'code', function (self, prop_id, old_value, ged)
if prop_id == "EmitterType" then
self.EmittersAway = self.EmittersAway or {}
if self.EmitterType ~= "" and not table.find_value(self.EmittersAway, "EmitterType", self.EmitterType) then
table.insert(self.EmittersAway, PlaceObj("EmitterTypeClass",{'EmitterType',self.EmitterType}))
end
table.remove_value(self.EmittersAway, "EmitterType", old_value)
if #self.EmittersAway == 0 then
self.EmittersAway = false
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPlacePos",
'params', "rand, spot_pos, spot_radius",
'code', function (self, rand, spot_pos, spot_radius)
local rand_pos = point(rand(spot_radius), 0, 0)
rand_pos = RotateAxis(rand_pos, point(4096, 0, 0), rand(360 * 60))
rand_pos = RotateAxis(rand_pos, point(0, 4096, 0), rand(360 * 60))
rand_pos = RotateAxis(rand_pos, point(0, 0, 4096), rand(360 * 60))
local pos = spot_pos + rand_pos
local x, y, z = pos:xyz()
local w, h = terrain.GetMapSize()
x = Clamp(x, 0, w - 1)
y = Clamp(y, 0, h - 1)
local terrain_z = terrain.GetHeight(pos)
z = (z < terrain_z) and terrain_z or z
return point(x, y, z)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "MatchBorderRelation",
'params', "pos",
'code', function (self, pos)
if self.BorderRelation == "any" then
return true
end
local border_area = GetBorderAreaLimits():grow(self.BorderTolerance)
local pos_inside = pos:InBox2D(border_area)
if self.BorderRelation == "Inside Border Area" then
return pos_inside
else
return not pos_inside
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
local text, delim = "", ""
if #(self.ClassPatterns or empty_table) == 0 and not self.BeachPoints then
text = "Either 'Class Patterns' must be non-empty or 'Beach Points' must be checked"
delim = "\n"
end
if #(self.SoundCandidates or empty_table) == 0 and self.SoundSamples > 0 then
text = string.format("%s%sNo 'Sound Samples' specified but spawning %d of them is required!", text, delim, self.SoundSamples)
delim = "\n"
end
for idx, sample in ipairs(self.SoundCandidates or empty_table) do
if not sample.Sound or sample.Sound == "" then
text = string.format("%s%sNo Sound Bank specified for sound candidate %d.", text, delim, idx)
delim = "\n"
end
end
local class = self.OriginAwayClass
if class and class ~= "" then
local classes = ExpandRuleClasses(class)
if #classes == 0 then
text = string.format("%s%sNo classes expanded for OriginAwayClass='%s'!", text, delim, class)
delim = "\n"
end
end
if self.DeleteOld and self.id == "" then
text = string.format("%s%sDeleteOld requires id set!", text, delim)
delim = "\n"
end
return text ~= "" and text
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "SatelliteShortcuts",
id = "SatelliteShortcutPreset",
PlaceObj('PropertyDefCombo', {
'id', "start_sector",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "end_sector",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "shortcut_direction_entrance_sector",
'help', "The sector which denotes the direction in which the start sector is being entered from",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "shortcut_direction_exit_sector",
'help', "The sector which denotes the direction in which the exit sector is being entered from",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "speed_const",
'help', "The constant denoting the shortcut's speed",
'default', "RiverTravelTime",
'items', function (self) return ConstCategoryToCombo(const.SatelliteShortcut) end,
}),
PlaceObj('PropertyDefCombo', {
'id', "terrain",
'name', "Travel Breakdown Terrain Description",
'default', "Shortcut_River",
'items', function (self) return PresetsCombo("SectorTerrain") end,
}),
PlaceObj('PropertyDefCombo', {
'id', "entry_direction_start",
'name', "Deployment Entry At Start Sector",
'items', function (self) return { false, "North", "South", "East", "West" } end,
}),
PlaceObj('PropertyDefCombo', {
'id', "entry_direction_end",
'name', "Deployment Entry At End Sector",
'items', function (self) return { false, "North", "South", "East", "West" } end,
}),
PlaceObj('PropertyDefBool', {
'id', "one_way",
'name', "One way",
}),
PlaceObj('PropertyDefBool', {
'id', "disabled",
'name', "Disabled By Default",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetEditorView",
'no_edit', true,
'default', function (self)
return self.id .. " (" .. tostring(self.start_sector) .. " - " .. tostring(self.end_sector) .. ")"
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetPath",
'help', "The points to draw the shortcut curve",
'default', function (self)
return empty_table
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetShortcutVisibilitySectors",
'no_edit', true,
'default', function (self)
return self.VisibilitySectors
end,
}),
PlaceObj('PropertyDefStringList', {
'id', "VisibilitySectors",
'help', "Sectors which are visible while travelling on the shortcut",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefNumber', {
'id', "TravelTimeInSectors",
'help', "How many sectors this shortcut is long. This is multiplied by const.Satellite.RiverTravelTime",
}),
PlaceObj('PropertyDefBool', {
'id', "water_shortcut",
}),
PlaceObj('ClassMethodDef', {
'name', "GetShortcutEnabled",
'code', function (self)
gv_SatelliteShortcutState = gv_SatelliteShortcutState or {}
local runtimeState = gv_SatelliteShortcutState[self.id]
if runtimeState and runtimeState.enabled then
return runtimeState.enabled
end
return not self.disabled
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetTravelTime",
'code', function (self)
gv_SatelliteShortcutState = gv_SatelliteShortcutState or {}
local runtimeState = gv_SatelliteShortcutState[self.id]
local constName = runtimeState and runtimeState.speed_const or self.speed_const or "RiverTravelTime"
local timeConst = const.SatelliteShortcut[constName]
return self.TravelTimeInSectors * timeConst
end,
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "SatelliteTimelineEvents",
DefParentClassList = {
"ListPreset",
},
id = "SatelliteTimelineEventDef",
PlaceObj('PropertyDefText', {
'id', "Title",
}),
PlaceObj('PropertyDefText', {
'id', "Text",
}),
PlaceObj('PropertyDefText', {
'id', "Hint",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetIcon",
'name', "GetIcon",
'params', "self,eventCtx",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetTextContext",
'name', "GetTextContext",
'params', "self,eventCtx",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetDescriptionText",
'name', "GetDescriptionText",
'params', "self,eventCtx",
'default', function (self,eventCtx)
return self.Text, self.Title, self.Hint
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetMapLocation",
'name', "GetMapLocation",
'params', "self,eventCtx",
}),
PlaceObj('PropertyDefFunc', {
'id', "GetAssociatedMercs",
'name', "GetAssociatedMercs",
'params', "self,eventCtx",
}),
PlaceObj('PropertyDefFunc', {
'id', "OnClick",
'name', "OnClick",
'params', "self,eventCtx",
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "SatelliteWarnings",
DefParentClassList = {
"ListPreset",
},
id = "SatelliteWarning",
PlaceObj('PropertyDefText', {
'id', "Title",
'default', T(998836062590, --[[PresetDef SatelliteWarning default]] "Warning"),
}),
PlaceObj('PropertyDefText', {
'id', "Body",
}),
PlaceObj('PropertyDefText', {
'id', "OkText",
'default', T(357769680740, --[[PresetDef SatelliteWarning default]] "OK"),
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "SectorTerrainTypes",
DefParentClassList = {
"ListPreset",
},
id = "SectorTerrain",
PlaceObj('PropertyDefNumber', {
'id', "TravelMod",
'name', "Travel Modifier",
'help', "Modifies travel times through this sector",
'default', 100,
'scale', "%",
'slider', true,
'min', 0,
'max', 500,
}),
PlaceObj('PropertyDefText', {
'id', "DisplayName",
'template', true,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "SkinDecalData",
PlaceObj('PropertyDefChoice', {
'category', "Decal",
'id', "DecEntity",
'name', "Decal Entity",
'default', "",
'items', function (self) return ClassDescendantsCombo("SkinDecal") end,
}),
PlaceObj('PropertyDefPresetId', {
'category', "Decal",
'id', "DecType",
'preset_class', "SkinDecalType",
'default', "",
}),
PlaceObj('PropertyDefChoice', {
'category', "Placement",
'id', "Spot",
'name', "Attach Spot",
'no_validate', true,
'default', "",
'items', function (self) return EntitySpotsCombo end,
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "DecOffsetX",
'name', "Offset X (red axis)",
'default', 0,
'scale', "cm",
'slider', true,
'min', -5000,
'max', 5000,
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "DecOffsetY",
'name', "Offset Y (green axis)",
'default', 0,
'scale', "cm",
'slider', true,
'min', -5000,
'max', 5000,
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "DecOffsetZ",
'name', "Offset Z (blue axis)",
'default', 0,
'scale', "cm",
'slider', true,
'min', -5000,
'max', 5000,
}),
PlaceObj('PropertyDefBool', {
'category', "Placement",
'id', "InvertFacing",
'name', "Invert Facing (along red axis)",
}),
PlaceObj('PropertyDefChoice', {
'category', "Placement",
'id', "DecAttachAxis",
'name', "Rotation Axis",
'default', "+X",
'items', function (self) return table.keys(SkinDecalAttachAxis, "sorted") end,
}),
PlaceObj('PropertyDefRange', {
'category', "Placement",
'id', "DecAttachAngleRange",
'name', "Rotation Range",
'extra_code', "slider = true",
'default', range(0, 360),
'min', 0,
'max', 360,
}),
PlaceObj('PropertyDefNumber', {
'category', "Placement",
'id', "DecScale",
'name', "Scale",
'default', 100,
'slider', true,
'min', 1,
'max', 500,
}),
PlaceObj('PropertyDefColor', {
'category', "Placement",
'id', "ClrMod",
'name', "Color Modifier",
'default', RGBA(100, 100, 100, 255),
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Editors.Art",
DefEditorName = "Skin decal presets",
DefParentClassList = {
"Preset",
"SkinDecalData",
},
id = "SkinDecalMetadata",
})
PlaceObj('PresetDef', {
DefGlobalMap = "SkinDecalTypes",
DefParentClassList = {
"ListPreset",
},
id = "SkinDecalType",
PlaceObj('PropertyDefBool', {
'id', "ClearedByWater",
'name', "Cleared By Water",
'default', true,
}),
PlaceObj('PropertyDefChoice', {
'id', "DefaultEntity",
'name', "Default Entity",
'default', "",
'items', function (self) return ClassDescendantsCombo("Decal") end,
}),
PlaceObj('PropertyDefNumber', {
'id', "DefaultScale",
'name', "Default Scale",
'default', 100,
'scale', "%",
'min', 1,
'max', 1000,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not IsValidEntity(self.DefaultEntity) then
return "Invalid entity"
end
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "StanceToStanceAP",
PlaceObj('PropertyDefChoice', {
'id', "start_stance",
'name', "Starting Stance",
'items', function (self) return PresetGroupCombo("CombatStance", "Default") end,
}),
PlaceObj('PropertyDefChoice', {
'id', "end_stance",
'name', "End Stance",
'items', function (self) return PresetGroupCombo("CombatStance", "Default") end,
}),
PlaceObj('PropertyDefNumber', {
'id', "ap_cost",
'name', "AP Cost",
'default', 0,
'scale', "AP",
}),
})
PlaceObj('PresetDef', {
DefEditorMenubar = "Scripting",
DefEditorName = "Stat Gaining Prerequisites",
DefGlobalMap = "StatGainingPrerequisites",
DefParentClassList = {
"MsgReactionsPreset",
},
id = "StatGainingPrerequisite",
PlaceObj('PropertyDefNestedList', {
'category', "StatGaining",
'id', "parameters",
'name', "Parameters",
'base_class', "PresetParam",
}),
PlaceObj('PropertyDefCombo', {
'category', "StatGaining",
'id', "relatedStat",
'name', "Related Stat",
'items', function (self) return UnitPropertiesStats:GetProperties() end,
}),
PlaceObj('PropertyDefNumber', {
'category', "StatGaining",
'id', "failChance",
'name', "Fail Chance",
'help', "Chance to fail on top of all other checks.",
'default', 0,
'scale', "%",
'min', 0,
'max', 100,
}),
PlaceObj('PropertyDefBool', {
'category', "StatGaining",
'id', "oncePerMapVisit",
'name', "Once Per Map Visit",
}),
PlaceObj('ClassMethodDef', {
'name', "ResolveValue",
'params', "key",
'code', function (self, key)
local value = self:GetProperty(key)
if value then return value end
if self.parameters then
local found = table.find_value(self.parameters, "Name", key)
if found then
return found.Value
end
end
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "TacticalNotification",
PlaceObj('PropertyDefText', {
'id', "text",
'name', "Text",
}),
PlaceObj('PropertyDefText', {
'id', "secondaryText",
'name', "SecondaryText",
}),
PlaceObj('PropertyDefText', {
'id', "removalGroup",
'name', "Group",
'translate', false,
}),
PlaceObj('PropertyDefNumber', {
'id', "duration",
'name', "Duration",
'default', 1500,
}),
PlaceObj('PropertyDefCombo', {
'id', "style",
'name', "Style",
'default', "red",
'items', function (self) return { "red", "yellow", "blue" } end,
}),
PlaceObj('PropertyDefBool', {
'id', "combatLog",
'name', "Log in Combat Log",
}),
PlaceObj('PropertyDefCombo', {
'id', "combatLogType",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return not self.combatLog end,
'default', "short",
'items', function (self) return { "short", "important", "debug" } end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "TargetBodyPart",
PlaceObj('PropertyDefText', {
'id', "display_name",
'name', "Display Name",
}),
PlaceObj('PropertyDefText', {
'id', "description",
'name', "Description",
}),
PlaceObj('PropertyDefText', {
'id', "display_name_caps",
'name', "Display Name Caps",
}),
PlaceObj('PropertyDefNumber', {
'id', "damage_mod",
'name', "Damage Modifier",
'default', 0,
'scale', "%",
}),
PlaceObj('PropertyDefNumber', {
'id', "tohit_mod",
'name', "Chance To Hit Modifier",
'default', 0,
'scale', "%",
}),
PlaceObj('PropertyDefCombo', {
'id', "applied_effect",
'name', "Applied Effect",
'default', "",
'items', function (self) return PresetGroupCombo("CharacterEffectCompositeDef", "Default") end,
}),
PlaceObj('PropertyDefBool', {
'id', "default",
'name', "Default target",
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
local duplicated_default
if self.default then
--check to see if a second one is set as default
ForEachPresetInGroup("TargetBodyPart", "Default", function(preset)
if preset.id ~= self.id and preset.default then
duplicated_default = true
end
end)
end
if duplicated_default then return "More than one body part is set as default target" end
end,
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
}),
PlaceObj('PropertyDefText', {
'id', "armorPart",
'name', "ArmorPart",
'help', "The inventory slot which serves as armor for this body part.",
'translate', false,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/outline starburst.png",
DefEditorMenubar = "Combat",
DefEditorMenubarSortKey = "-10",
DefFilterClass = "TestCombatFilter",
DefHasSortKey = true,
id = "TestCombat",
PlaceObj('PropertyDefBool', {
'id', "show_in_cheats",
'name', "Show in Cheats",
'help', "Can be tested from main menu cheats",
}),
PlaceObj('PropertyDefNumber', {
'id', "SortKey",
'name', "SortKey",
'help', "The lower the number, the earlier it occurs in the list",
'default', 0,
}),
PlaceObj('PropertyDefBool', {
'id', "skip_deployment",
'name', "Skip Deployment",
'help', "Directly in combat mode",
}),
PlaceObj('PropertyDefCombo', {
'id', "sector_id",
'name', "Sector Id",
'help', "Sector id",
'extra_code', "no_edit = function(self) return self.map end",
'default', "A1",
'items', function (self) return GetCampaignSectorsCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "map",
'name', "Map",
'help', "Use this property if you want to test combat in a test map (which is not defined as a sector map)",
'items', function (self) return ListMaps() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "TimeOfDay",
'name', "Time of Day",
'default', "Day",
'items', function (self) return PresetsCombo("GameStateDef", "time of day", "Any") end,
}),
PlaceObj('PropertyDefCombo', {
'id', "Weather",
'name', "Weather",
'default', "Default",
'items', function (self) return PresetsCombo("GameStateDef", "weather", "Default") end,
}),
PlaceObj('PropertyDefBool', {
'id', "real_gameplay",
'name', "Real Gameplay",
'help', "Attack or defend the sector, using real gameplay spawning logic (Entrance and Defender markers)",
'default', true,
}),
PlaceObj('PropertyDefText', {
'id', "DisplayText",
'name', "DisplayText",
}),
PlaceObj('PropertyDefNumber', {
'id', "Alt_Shortcut",
'help', "Alt + [shortcut] will quickstart this test",
'min', 1,
'max', 5,
}),
PlaceObj('PropertyDefBool', {
'id', "reveal_intel",
'name', "Reveal Intel",
'default', true,
}),
PlaceObj('PropertyDefNestedList', {
'id', "squads",
'base_class', "TestCombatSquad",
'inclusive', true,
}),
PlaceObj('PropertyDefCombo', {
'id', "player_role",
'name', "Player Role",
'help', "The player attacks or defends the sector",
'extra_code', "no_edit = function(self) return not self.real_gameplay end",
'default', "attack",
'items', function (self) return {"attack", "defend"} end,
}),
PlaceObj('PropertyDefCombo', {
'id', "attacker_dir",
'name', "Attacker Dir",
'help', "Direction from which the attacker (player or enemy - determined by Player Role prop) enters the sector",
'extra_code', "no_edit = function(self) return not self.real_gameplay end",
'default', "North",
'items', function (self) return const.WorldDirections end,
}),
PlaceObj('PropertyDefStringList', {
'id', "trigger_enemy_spawners",
'name', "Trigger Enemy Spawners",
'help', "Spawn all units from there spawner markers, ignoring their conditions",
'items', function (self) return TriggerEnemySpawnersCombo(self:GetCombatMap()) end,
}),
PlaceObj('PropertyDefStringList', {
'id', "disable_enemy_spawners",
'name', "Disable Enemy Spawners",
'help', "Do not spawn units from these markers",
'items', function (self) return TriggerEnemySpawnersCombo(self:GetCombatMap()) end,
}),
PlaceObj('PropertyDefFunc', {
'id', "OnMapLoaded",
'help', 'Use this to customize conditions in the test combat. \nCalled in a real time thread OnMsg("PostNewMapLoaded")',
}),
PlaceObj('PropertyDefFunc', {
'id', "OnCombatStart",
'help', 'Use this to customize conditions in the test combat. \nCalled in a real time thread OnMsg("CombatStart")',
}),
PlaceObj('PropertyDefPresetId', {
'id', "combatTask",
'name', "Combat Task",
'help', "Preselect a Combat Task for the combat.",
'preset_class', "CombatTask",
}),
PlaceObj('PropertyDefButtons', {
'id', "enter_sector_btn",
'dont_save', true,
'read_only', true,
'buttons', {
PlaceObj('PropertyDefPropButton', {
'Name', "Test",
'FuncName', "TestCombatTest",
}),
},
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
local err = self:VerifyPlayerSquad()
if err then
return err
end
local map = GetMapName()
local combat_map = self:GetCombatMap()
if not combat_map or map ~= combat_map or GameState.loading then
return
end
if self.real_gameplay then
if not next(MapGetMarkers("ExitZoneInteractable", self.attacker_dir)) then
return string.format("No %s Entrance markers on the map", self.attacker_dir)
end
if not next(MapGetMarkers("Defender", false, function(m) return m:IsMarkerEnabled() end)) and not next(MapGetMarkers("DefenderPriority", false, function(m) return m:IsMarkerEnabled() end)) then
return "No Enabled Defender markers on the map"
end
end
for _, squad in ipairs(self.squads) do
if squad.spawn_location == "On Marker" then
if not next(MapGetMarkers(squad.spawn_marker_type, squad.spawn_marker_group)) then
return string.format("No %s %s markers on the map", squad.spawn_marker_type, squad.spawn_marker_group)
end
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "VerifyPlayerSquad",
'code', function (self)
local player_squads = 0
for _, squad in ipairs(self.squads) do
if squad.squad_type ~= "NPC" then
player_squads = player_squads + 1
end
end
if player_squads == 0 then
return "No Player squad defined"
elseif player_squads > 1 then
return "More than one Player squad defined"
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetCombatMap",
'code', function (self)
local sector = table.find_value(CampaignPresets[DefaultCampaign].Sectors, "Id", self.sector_id)
local map = self.map or sector and sector.Map
return map
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return self.id .. " <color 0 128 0>" .. (self.map or self.sector_id)
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "TestCombatSquad",
PlaceObj('PropertyDefChoice', {
'id', "squad_type",
'default', "CurrentPlayerSquad",
'items', function (self) return {"CurrentPlayerSquad", "Custom", "NPC"} end,
}),
PlaceObj('PropertyDefPresetIdList', {
'id', "Mercs",
'name', "Mercs",
'help', "List of your team to deploy",
'extra_code', 'no_edit = function(self) return self.squad_type ~= "Custom" end',
'preset_class', "UnitDataCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
if IsMerc(preset) then
return true
end
end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "npc_squad_id",
'extra_code', 'no_edit = function(self) return self.squad_type ~= "NPC" end',
'preset_class', "EnemySquads",
'preset_filter', function (preset, obj, prop_meta)
if preset.group ~= "Test Encounters" then return obj end
end,
}),
PlaceObj('PropertyDefChoice', {
'id', "side",
'extra_code', 'read_only = function(self) return self.squad_type ~= "NPC" end',
'default', "player1",
'items', function (self) return Sides end,
}),
PlaceObj('PropertyDefChoice', {
'id', "spawn_location",
'default', "Standard",
'items', function (self) return {"Standard", "On Marker"} end,
}),
PlaceObj('PropertyDefChoice', {
'id', "tier",
'name', "Tier",
'help', "Level up, give more perks and more expensive weapons for higher tiers.",
'default', 1,
'items', function (self) return {1,2,3} end,
}),
PlaceObj('PropertyDefCombo', {
'id', "spawn_marker_type",
'name', "Marker Type",
'help', "For enemies: Defender marker type and no marker group places enemies using defender priority logic",
'extra_code', 'no_edit = function(self) return self.spawn_location == "Standard" end',
'default', "Defender",
'items', function (self) return GetGridMarkerTypesCombo() end,
}),
PlaceObj('PropertyDefCombo', {
'id', "spawn_marker_group",
'name', "Marker Group",
'help', "Where to spawn squad",
'extra_code', 'no_edit = function(self) return self.spawn_location == "Standard" end',
'items', function (self) return GridMarkerGroupsCombo() end,
}),
PlaceObj('ClassMethodDef', {
'name', "SetProperty",
'params', "id, value",
'code', function (self, id, value)
local prev = self[id]
PropertyObject.SetProperty(self, id,value)
if id == "squad_type" then
if value == "NPC" then
if prev ~= "NPC" then
self:SetProperty("side", "enemy1")
end
else
self:SetProperty("side", "player1")
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
if self.squad_type == "CurrentPlayerSquad" then
return "Current Player Squad"
elseif self.squad_type == "Custom" then
return "Custom Player Squad"
end
local def = EnemySquadDefs[self.npc_squad_id]
return string.format("[%s] %s\n%s", self.side, tostring(self.npc_squad_id), def and def:GetPreview() or "")
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "TriggeredConditionalEvent",
PlaceObj('PropertyDefPresetId', {
'id', "QuestId",
'name', "QuestId",
'read_only', true,
'no_edit', true,
}),
PlaceObj('PropertyDefChoice', {
'id', "ParamId",
'name', "Param id",
'help', "The name of the param in the quest table which will be used to store the state of the TriggeredConditionalEvent",
'items', function (self) return GetQuestsVarsCombo(self.QuestId, "TCEState") end,
}),
PlaceObj('PropertyDefChoice', {
'id', "Trigger",
'name', "Trigger",
'default', "activation",
'items', function (self) return {"always", "activation", "deactivation", "change"} end,
}),
PlaceObj('PropertyDefBool', {
'id', "Once",
'name', "Once",
}),
PlaceObj('PropertyDefNestedList', {
'id', "Conditions",
'name', "Conditions",
'base_class', "Condition",
}),
PlaceObj('PropertyDefBool', {
'id', "SequentialEffects",
'name', "Execute Effects Sequentially",
'help', "Whether effects should wait for each other when executing in order.",
'default', true,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Effects",
'name', "Effects",
'base_class', "Effect",
}),
PlaceObj('ClassMethodDef', {
'name', "Update",
'code', function (self)
if not self.Effects then
return
end
local questId = self.QuestId
local paramId = self.ParamId
local quest = QuestGetState(questId)
if not quest then
return
end
local state = quest[paramId]
if self.Once and state == "done" then
return
end
-- evaluate
local evaluation
if next(self.requiredSectors) then
local weAreHere = not gv_SatelliteView
weAreHere = weAreHere and table.find(self.requiredSectors, gv_CurrentSectorId)
evaluation = weAreHere and EvalConditionList(self.Conditions) or false
else
evaluation = EvalConditionList(self.Conditions)
end
-- trigger
local exec = false
local trigger = self.Trigger
if trigger == "always" then
exec = evaluation
elseif (trigger == "activation" or trigger == "change") and not state then
exec = evaluation
elseif (trigger == "deactivation" or trigger == "change") and state == true and not evaluation then
exec = true
end
local done = false
if exec then
if self.Once then
rawset(quest, paramId, "done")
done = true
end
if self.SequentialEffects then
ExecuteSequentialEffects(self.Effects, "QuestAndState", questId, paramId)
else
ExecuteEffectList(self.Effects, quest, state)
end
end
if not done then
rawset(quest, paramId, evaluation)
end
return exec
end,
}),
PlaceObj('ClassConstDef', {
'name', "EditorView",
'type', "text",
'value', "<u(ParamId)>",
'untranslated', true,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not self.ParamId then
return "Add unique Variable to store triggered conditions/effects state in"
end
if not self.Effects then
return "Add at least one effect to execute"
end
for _, eff in ipairs(self.Effects) do
if next(eff.RequiredObjClasses) then
if table.find(eff.RequiredObjClasses, "Unit") then
return "Can't use effects that require a unit ("..eff.class..")"
end
return "Can't use effects that require an object ("..eff.class..")"
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "OnAfterEditorNew",
'params', "parent, ged, is_paste",
'code', function (self, parent, ged, is_paste)
local quest_def = GetParentTableOfKind(self, "QuestsDef")
self.QuestId = quest_def.id
end,
}),
PlaceObj('PropertyDefStringList', {
'id', "requiredSectors",
'read_only', true,
'items', function (self) return GetCampaignSectorsCombo() end,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/alert attention danger error warning.png",
DefEditorMenubar = "Scripting",
DefEditorMenubarSortKey = "4030",
DefEditorName = "Tutorial Hints Editor",
DefGlobalMap = "TutorialHints",
DefHasSortKey = true,
DefParentClassList = {
"Preset",
"CampaignSpecific",
},
group = "PresetDefs",
id = "TutorialHint",
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
}),
PlaceObj('PropertyDefPresetId', {
'id', "PopupId",
'help', "Popup notification preset id.",
'preset_class', "PopupNotification",
}),
PlaceObj('PropertyDefText', {
'category', "Popup Preview",
'id', "PopupTitle",
'dont_save', true,
'read_only', true,
}),
PlaceObj('PropertyDefText', {
'category', "Popup Preview",
'id', "PopupText",
'dont_save', true,
'read_only', true,
'wordwrap', true,
'lines', 5,
}),
PlaceObj('PropertyDefText', {
'id', "TutorialPopupTitle",
'no_edit', "expression",
'no_edit_expression', function (self, prop_meta) return self.group ~= "TutorialPopups" end,
'default', T(767566189526, --[[PresetDef TutorialHint default]] "Tutorial"),
}),
PlaceObj('PropertyDefText', {
'id', "Text",
'default', "",
'lines', 3,
'max_lines', 8,
}),
PlaceObj('PropertyDefText', {
'id', "GamepadText",
'lines', 3,
'max_lines', 8,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPopupTitle",
'params', "id",
'code', function (self, id)
local id = self.PopupId
local preset = PopupNotifications[id]
return preset and preset.Title
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetPopupText",
'params', "id",
'code', function (self, id)
local id = self.PopupId
local preset = PopupNotifications[id]
return preset and preset.Text
end,
}),
PlaceObj('PropertyDefBool', {
'id', "StoreAsTable",
'read_only', true,
'no_edit', true,
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "StaticPopup",
'help', "Static popups show in the left corner under snype.",
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "ShowConditions",
'name', "Show Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "HideConditions",
'name', "Hide Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Conditionals",
'id', "CompletionConditions",
'name', "Completion Condition",
'base_class', "Condition",
'inclusive', true,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Allows adding new tutorial hint pop-up in the HUD or setting up a pop-up window preset created in the Popup Notification mod item.",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "UnitBodyPartCollider",
PlaceObj('PropertyDefChoice', {
'id', "id",
'items', function (self) return {"Head","Arms","Torso","Groin","Legs"} end,
}),
PlaceObj('PropertyDefStringList', {
'id', "TargetSpots",
'no_validate', true,
'items', function (self) return {"Head","Neck","Torso","Groin","Shoulderl","Shoulderr","Elbowl","Elbowr","Wristl","Wristr","Pelvisl","Pelvisr","Kneel","Kneer","Ribsupperl","Ribsupperr","Ribslowerl","Ribslowerr","Tail"} end,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Colliders",
'base_class', "UnitColliderBase",
'format', "<Text>",
}),
})
PlaceObj('PresetDef', {
DefGlobalMap = "UnitColliders",
DefHasParameters = true,
DefHasSortKey = true,
id = "UnitCollider",
PlaceObj('PropertyDefNestedList', {
'id', "BodyParts",
'base_class', "UnitBodyPartCollider",
'format', "<id>",
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "UnitColliderBase",
PlaceObj('PropertyDefCombo', {
'id', "TargetSpot",
'help', "Associate every collider with a target spot",
'no_validate', true,
'default', "",
'items', function (self) return {"Head","Neck","Torso","Groin","Shoulderl","Shoulderr","Elbowl","Elbowr","Wristl","Wristr","Pelvisl","Pelvisr","Kneel","Kneer","Ribsupperl","Ribsupperr","Ribslowerl","Ribslowerr","Tail"} end,
}),
PlaceObj('ClassMethodDef', {
'name', "Text",
'code', function (self)
return ""
end,
}),
PlaceObj('PropertyDefText', {
'id', "Type",
'read_only', true,
'translate', false,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"UnitColliderBase",
},
group = "PresetDefs",
id = "UnitColliderCapsule",
PlaceObj('PropertyDefCombo', {
'id', "Spot1",
'help', "Capsule segment point 1",
'no_validate', true,
'default', "",
'items', function (self) return {"Head","Neck","Torso","Groin","Shoulderl","Shoulderr","Elbowl","Elbowr","Wristl","Wristr","Pelvisl","Pelvisr","Kneel","Kneer","Ribsupperl","Ribsupperr","Ribslowerl","Ribslowerr","Tail"} end,
}),
PlaceObj('PropertyDefCombo', {
'id', "Spot2",
'help', "Capsule segment point 2",
'no_validate', true,
'default', "",
'items', function (self) return {"Head","Neck","Torso","Groin","Shoulderl","Shoulderr","Elbowl","Elbowr","Wristl","Wristr","Pelvisl","Pelvisr","Kneel","Kneer","Ribsupperl","Ribsupperr","Ribslowerl","Ribslowerr","Tail"} end,
}),
PlaceObj('PropertyDefNumber', {
'id', "Radius",
'help', "Capsule radius",
'default', 0,
'scale', "cm",
}),
PlaceObj('ClassMethodDef', {
'name', "Text",
'code', function (self)
return string.format("Capsule, Spot1=%s, Spot2=%s, Radius=%d, TargetSpot=%s", self.Spot1, self.Spot2, self.Radius, self.TargetSpot)
end,
}),
PlaceObj('PropertyDefText', {
'id', "Type",
'read_only', true,
'default', "Capsule",
'translate', false,
}),
})
PlaceObj('ClassDef', {
DefParentClassList = {
"UnitColliderBase",
},
group = "PresetDefs",
id = "UnitColliderSphere",
PlaceObj('PropertyDefCombo', {
'id', "Spot",
'help', "Sphere center",
'no_validate', true,
'default', "",
'items', function (self) return {"Head","Neck","Torso","Groin","Shoulderl","Shoulderr","Elbowl","Elbowr","Wristl","Wristr","Pelvisl","Pelvisr","Kneel","Kneer","Ribsupperl","Ribsupperr","Ribslowerl","Ribslowerr","Tail"} end,
}),
PlaceObj('PropertyDefNumber', {
'id', "Radius",
'help', "Sphere radius",
'default', 0,
'scale', "cm",
}),
PlaceObj('ClassMethodDef', {
'name', "Text",
'code', function (self)
return string.format("Sphere, Spot=%s, Radius=%d, TargetSpot=%s", self.Spot, self.Radius, self.TargetSpot)
end,
}),
PlaceObj('PropertyDefText', {
'id', "Type",
'read_only', true,
'default', "Sphere",
'translate', false,
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/cog outline.png",
DefEditorMenubar = "Combat",
DefGlobalMap = "WeaponComponents",
DefHasParameters = true,
DefModItem = true,
DefModItemName = "Weapon component",
DefModItemSubmenu = "Item",
DefParentClassList = {
"WeaponComponentSharedClass",
},
id = "WeaponComponent",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
}),
PlaceObj('PropertyDefUIImage', {
'category', "General",
'id', "Icon",
'template', true,
'default', "",
'image_preview_size', 400,
}),
PlaceObj('PropertyDefCombo', {
'id', "Slot",
'items', function (self) return PresetGroupCombo("WeaponUpgradeSlot", "Default") end,
}),
PlaceObj('PropertyDefNestedList', {
'id', "Visuals",
'base_class', "WeaponComponentVisual",
'inclusive', true,
}),
PlaceObj('PropertyDefCombo', {
'id', "EnableWeapon",
'items', function (self) return InventoryItemCombo end,
}),
PlaceObj('PropertyDefPresetIdList', {
'id', "ModificationEffects",
'preset_class', "WeaponComponentEffect",
}),
PlaceObj('PropertyDefNumber', {
'category', "Costs",
'id', "Cost",
'name', "Cost (Parts)",
'help', "The cost of the upgrade in parts",
'template', true,
'default', 0,
}),
PlaceObj('PropertyDefNestedList', {
'category', "Costs",
'id', "AdditionalCosts",
'template', true,
'base_class', "WeaponComponentCost",
}),
PlaceObj('PropertyDefCombo', {
'category', "Costs",
'id', "ModificationDifficulty",
'default', 46,
'items', function (self) return const.WeaponModDifficultyPresets end,
}),
PlaceObj('ClassConstDef', {
'name', "FilterClass",
'type', "text",
'value', "WeaponComponentFilter",
}),
PlaceObj('PropertyDefButtons', {
'category', "Can Be Attached To",
'id', "CanBeAttachedTo",
'name', "Can Be Attached To",
'dont_save', true,
'read_only', true,
'template', true,
'extra_code', "buttons = function(obj) return WeaponComponentExtraButtons(obj) end",
}),
PlaceObj('PropertyDefStringList', {
'category', "Misc",
'id', "BlockSlots",
'name', "Block Slots",
'items', function (self) return PresetGroupCombo("WeaponUpgradeSlot", "Default") end,
}),
PlaceObj('PropertyDefBool', {
'category', "Misc",
'id', "ModifyRightHandGrip",
'name', "Modify the right hand grip",
}),
PlaceObj('PropertyDefBool', {
'category', "Misc",
'id', "EnableAimFX",
'name', "Enable Aim FX",
}),
PlaceObj('ClassConstDef', {
'name', "GetWarning",
}),
PlaceObj('ClassMethodDef', {
'name', "GetWarning",
'code', function (self)
local myParams = self.Parameters or empty_table
for i, effId in ipairs(self.ModificationEffects) do
local effect = WeaponComponentEffects[effId]
if effect and effect.RequiredParams then
local requiredParams = effect.RequiredParams
for i, param in ipairs(requiredParams) do
if not table.find(myParams, "Name", param) then
return "Missing param " .. param .. " for effect " .. effId
end
end
end
end
end,
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Creates a new weapon component that could be used in a weapon as a base component or through the Modify UI screen of a weapon. The Z_Blockings group is used to make certain components incompatible with others at the same time.",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/cog outline.png",
DefEditorMenubar = "Combat",
DefGlobalMap = "WeaponComponentBlockPairs",
DefParentClassList = {
"WeaponComponentSharedClass",
},
group = "PresetDefs",
id = "WeaponComponentBlockPair",
PlaceObj('PropertyDefPresetId', {
'id', "Weapon",
'preset_class', "InventoryItemCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
local classdef = g_Classes[preset.object_class]
return IsKindOf(classdef, "Firearm")
end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "ComponentBlockOne",
'preset_class', "WeaponComponent",
}),
PlaceObj('PropertyDefPresetId', {
'id', "ComponentBlockTwo",
'preset_class', "WeaponComponent",
}),
})
PlaceObj('PresetDef', {
DefEditorIcon = "CommonAssets/UI/Icons/cog outline.png",
DefEditorMenubar = "Combat",
DefGlobalMap = "WeaponComponentEffects",
DefHasParameters = true,
DefHasSortKey = true,
DefParentClassList = {
"MsgActorReactionsPreset",
},
group = "PresetDefs",
id = "WeaponComponentEffect",
PlaceObj('PropertyDefText', {
'category', "Display Data",
'id', "Description",
'lines', 1,
'max_lines', 5,
}),
PlaceObj('PropertyDefStringList', {
'category', "Params",
'id', "RequiredParams",
'arbitrary_value', true,
}),
PlaceObj('PropertyDefCombo', {
'category', "Stat Modifier",
'id', "StatToModify",
'name', "StatToModify",
'items', function (self) return ClassModifiablePropsNonTranslatableCombo(g_Classes.Firearm) end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Stat Modifier",
'id', "ModificationType",
'default', "Add",
'items', function (self) return { "Add", "Multiply", "Subtract" } end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Stat Modifier",
'id', "CaliberChange",
'items', function (self) return PresetGroupCombo("Caliber", "Default") end,
}),
PlaceObj('PropertyDefCombo', {
'category', "Stat Modifier",
'id', "Scale",
'items', function (self) return table.keys(const.Scale) end,
}),
PlaceObj('PropertyDefButtons', {
'category', "Used In",
'id', "UsedIn",
'name', "Used In",
'dont_save', true,
'read_only', true,
'template', true,
'extra_code', "buttons = function(obj) return WeaponComponentEffectUsedIn(obj) end",
}),
PlaceObj('ClassMethodDef', {
'name', "VerifyReaction",
'params', "event, reaction_def, reaction_actor, ...",
'code', function (self, event, reaction_def, reaction_actor, ...)
if IsKindOf(reaction_actor, "BaseWeapon") then
return reaction_actor:HasComponent(self.id)
end
if IsKindOf(reaction_actor, "UnitInventory") then
if reaction_actor:FindItemInSlot(reaction_actor.current_weapon, function(weapon, id) return IsKindOf(weapon, "FirearmBase") and weapon:HasComponent(id) end, self.id) then
return true
end
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetReactionActors",
'params', "event, reaction_def, ...",
'code', function (self, event, reaction_def, ...)
return ZuluReactionGetReactionActors_Light(event, reaction, ...)
end,
}),
PlaceObj('ClassConstDef', {
'name', "EditorMenubarName",
'type', "text",
'value', "WeaponComponentEffect",
}),
})
PlaceObj('PresetDef', {
DefEditorName = "WeaponComponent Editor",
DefPresetClass = "WeaponComponentSharedClass",
id = "WeaponComponentSharedClass",
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "WeaponComponentSlot",
PlaceObj('PropertyDefCombo', {
'id', "SlotType",
'items', function (self) return PresetGroupCombo("WeaponUpgradeSlot", "Default") end,
}),
PlaceObj('PropertyDefBool', {
'id', "Modifiable",
'default', true,
}),
PlaceObj('PropertyDefBool', {
'id', "CanBeEmpty",
}),
PlaceObj('PropertyDefStringList', {
'id', "AvailableComponents",
'items', function (self) return WeaponSlotComponentComboItems end,
}),
PlaceObj('PropertyDefCombo', {
'id', "DefaultComponent",
'name', "",
'default', "",
'items', function (self) return WeaponSlotDefaultComponentComboItems end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
local mod_text = self.Modifiable and "" or "(non-modifiable)"
local text = self.SlotType and Presets.WeaponUpgradeSlot.Default[self.SlotType].DisplayName or "Component"
return Untranslated(text) .. " " .. Untranslated(mod_text)
end,
}),
})
PlaceObj('ClassDef', {
group = "PresetDefs",
id = "WeaponComponentVisual",
PlaceObj('PropertyDefCombo', {
'id', "Entity",
'items', function (self) return GetWeaponComponentEntities end,
}),
PlaceObj('PropertyDefCombo', {
'id', "Slot",
'items', function (self) return PresetGroupCombo("WeaponUpgradeSlot", "Default") end,
}),
PlaceObj('PropertyDefPresetId', {
'id', "ApplyTo",
'preset_class', "InventoryItemCompositeDef",
'preset_filter', function (preset, obj, prop_meta)
local classdef = g_Classes[preset.object_class]
return IsKindOf(classdef, "Firearm")
end,
}),
PlaceObj('PropertyDefCombo', {
'id', "OverrideHolsterSlot",
'default', "",
'items', function (self) return { "", "Shoulder", "Leg" } end,
}),
PlaceObj('PropertyDefBool', {
'id', "ModifyRightHandGrip",
'template', true,
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
'name', "Custom Icon",
'help', "icon used for this particular component; leave empty to uae component default",
'template', true,
'default', "",
'image_preview_size', 400,
}),
PlaceObj('ClassConstDef', {
'name', "StoreAsTable",
'value', true,
}),
PlaceObj('ClassMethodDef', {
'name', "GetError",
'code', function (self)
if not self.Slot then
return "No slot"
end
if not self.Entity then
return "No entity"
end
end,
}),
PlaceObj('ClassMethodDef', {
'name', "GetEditorView",
'code', function (self)
return string.format("%s component (%s)", self.Slot or "unspecified", self:IsGeneric() and "any weapon" or self.ApplyTo)
end,
}),
PlaceObj('ClassMethodDef', {
'name', "Match",
'params', "id",
'code', function (self, id)
return self:IsGeneric() or self.ApplyTo == id
end,
}),
PlaceObj('ClassMethodDef', {
'name', "IsGeneric",
'code', function (self)
return (self.ApplyTo or "") == ""
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
id = "WeaponPropertyDef",
PlaceObj('PropertyDefText', {
'id', "bind_to",
'name', "Property",
'help', "The name of the property to bind to.",
'translate', false,
}),
PlaceObj('PropertyDefText', {
'id', "display_name",
'name', "Display Name",
}),
PlaceObj('PropertyDefText', {
'id', "short_display_name",
'name', "Short Display Name",
}),
PlaceObj('PropertyDefText', {
'id', "description",
'name', "Description",
}),
PlaceObj('PropertyDefNumber', {
'id', "max_progress",
'name', "Max Progress Bar Value",
'help', "The max value of the bar",
'default', 100,
}),
PlaceObj('PropertyDefBool', {
'id', "reverse_bar",
'name', "Reverse Bar",
}),
PlaceObj('PropertyDefBool', {
'id', "show_in_inventory",
'name', "Show in inventory rollover",
}),
PlaceObj('PropertyDefFunc', {
'id', "DisplayForContext",
'params', "self, context",
'default', function (self, context)
return context:IsWeapon()
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "GetProp",
'params', "self, item, unit_id",
'default', function (self, item, unit_id)
return item:GetProperty(self.bind_to)
end,
}),
PlaceObj('PropertyDefFunc', {
'id', "Getbase_Prop",
'params', "self, item, unit_id",
'default', function (self, item, unit_id)
return item:GetProperty("base_"..self.bind_to)
end,
}),
})
PlaceObj('PresetDef', {
DefParentClassList = {
"ListPreset",
},
group = "PresetDefs",
id = "WeaponType",
PlaceObj('PropertyDefText', {
'id', "Name",
}),
PlaceObj('PropertyDefText', {
'id', "Description",
'lines', 2,
'max_lines', 100,
}),
PlaceObj('PropertyDefUIImage', {
'id', "Icon",
'default', "UI/Icons/Weapons/M16A2",
'image_preview_size', 100,
}),
})
PlaceObj('PresetDef', {
DefModItem = true,
DefModItemName = "Weapon slot",
DefModItemSubmenu = "Item",
DefParentClassList = {
"ListPreset",
},
id = "WeaponUpgradeSlot",
PlaceObj('PropertyDefText', {
'id', "DisplayName",
}),
PlaceObj('ClassConstDef', {
'name', "Documentation",
'type', "text",
'value', "Creates a new possible weapon slot that could be defined for a weapon preset and referenced in a Weapon Component preset.",
}),
})