|
|
|
|
|
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, "<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 |
|
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) |
|
|
|
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) |
|
|
|
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 {} |
|
|
|
|
|
local bbox = box( |
|
point(sector_unpack(self.sector_topleft)), |
|
point(sector_unpack(self.sector_bottomright)) + point(1, 1) |
|
) |
|
|
|
|
|
local parents, current = { self }, self |
|
local sector_by_id = {} |
|
repeat |
|
|
|
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 |
|
table.insert(parents, current) |
|
end |
|
until not current |
|
|
|
|
|
self.sector_rowsstart = bbox:minx() |
|
self.sector_rows = bbox:maxx() - 1 |
|
self.sector_columns = bbox:maxy() - 1 |
|
|
|
|
|
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 |
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
if not units[1] or self.RequireWeapon and not self:GetAttackWeapons(units[1]) then |
|
return "hidden" |
|
end |
|
|
|
|
|
local state, reason = self:GetUIState(units, { target = target }) |
|
if state == "enabled" or (state ~= "hidden" and not reason) then |
|
|
|
if self.RequireTargets and (not IsValid(target) and not IsPoint(target)) and not self:GetAnyTarget(units) then |
|
return "disabled", AttackDisableReasons.NoTarget |
|
end |
|
end |
|
|
|
|
|
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) |
|
|
|
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) |
|
|
|
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 |
|
|
|
|
|
local id_changes = {} |
|
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 |
|
|
|
|
|
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) |
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
self.KillTCEsConditions = {QuestKillTCEsOnCompleted:new{}} |
|
|
|
self.Variables = {QuestVarBool:new{Name = "Completed"}, |
|
QuestVarBool:new{Name = "Given"}, |
|
QuestVarBool:new{Name = "Failed"}, |
|
QuestVarBool:new{Name = "NotStarted", Value = true},} |
|
else |
|
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, "Warning"), |
|
}), |
|
PlaceObj('PropertyDefText', { |
|
'id', "Body", |
|
}), |
|
PlaceObj('PropertyDefText', { |
|
'id', "OkText", |
|
'default', T(357769680740, "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 |
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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, "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.", |
|
}), |
|
}) |
|
|
|
|