-- AltSystem Data Definitions -- Contains skill data (fetched from TRP3 profile), item options, defense options, and modifier constants. AltSystem = AltSystem or {} AltSystem.Data = {} -- Skill levels and their modifiers AltSystem.Data.SkillLevels = { ["Inept"] = -4, ["Novice"] = -2, ["Adept"] = 0, ["Expert"] = 2, ["Master"] = 4, } -- The "Base roll" entry is always the first (default) skill local BASE_ROLL_ENTRY = { name = "Base roll", level = "Base", modifier = 0 } -- The "Unskilled" entry is always the last skill local UNSKILLED_ENTRY = { name = "Unskilled", level = "Unskilled", modifier = -4 } -- Default/fallback skill list used when no TRP3 profile skills are found local DEFAULT_SKILLS = { { name = "Base roll", level = "Base", modifier = 0 }, { name = "Novice Skill", level = "Novice", modifier = -2 }, { name = "Adept Skill", level = "Adept", modifier = 0 }, { name = "Expert Skill", level = "Expert", modifier = 2 }, { name = "Master Skill", level = "Master", modifier = 4 }, { name = "Unskilled", level = "Unskilled", modifier = -4 }, } -- Valid skill level keywords that must appear in the trait's right field (RT) local VALID_SKILL_KEYWORDS = { "Inept", "Novice", "Adept", "Expert", "Master" } -- Expected numeric value ranges for each skill keyword local SKILL_KEYWORD_RANGES = { ["Novice"] = { min = 1, max = 5 }, ["Adept"] = { min = 6, max = 10 }, ["Expert"] = { min = 11, max = 19 }, ["Master"] = { min = 20, max = 20 }, } -- Check if the trait's right text field contains a valid skill keyword. -- Returns the matched keyword if found, nil otherwise. local function FindSkillKeyword(rightText) if not rightText or rightText == "" then return nil end for _, keyword in ipairs(VALID_SKILL_KEYWORDS) do if rightText:find(keyword) then return keyword end end return nil end -- Check whether the numeric value matches the expected range for the given keyword. -- Returns a warning string if mismatched, or nil if everything is fine. local function CheckSkillMismatch(keyword, numericValue) if not keyword or keyword == "Inept" then return nil end local range = SKILL_KEYWORD_RANGES[keyword] if not range then return nil end if not numericValue or numericValue <= 0 then return nil end if numericValue < range.min or numericValue > range.max then return "Skill is marked as " .. keyword .. " (" .. range.min .. "-" .. range.max .. "), but the profile has a value of " .. numericValue .. "." end return nil end -- Determine the skill level from the trait's right text and numeric value (V2 field, 0-20 range). -- If the trait is marked as Inept, always returns "Inept" with -4 modifier regardless of numeric value. -- Otherwise returns the level string and modifier based on numeric value, or nil if the value is 0 or absent. local function ParseSkillLevel(rightText, numericValue) if rightText and rightText:find("Inept") then return "Inept", AltSystem.Data.SkillLevels["Inept"] end if not numericValue or numericValue <= 0 then return nil, nil end if numericValue >= 20 then return "Master", AltSystem.Data.SkillLevels["Master"] elseif numericValue >= 11 then return "Expert", AltSystem.Data.SkillLevels["Expert"] elseif numericValue >= 6 then return "Adept", AltSystem.Data.SkillLevels["Adept"] else return "Novice", AltSystem.Data.SkillLevels["Novice"] end end -- Fetch skills from the current TRP3 profile's personality traits. -- Returns an array of skill entries, always starting with "Base roll". -- Traits marked as Inept get a -4 modifier regardless of their numeric value. -- Falls back to the default list if no profile or no valid skills are found. function AltSystem.Data:RefreshSkills() local skills = {} -- Always add Base roll as the first entry table.insert(skills, { name = BASE_ROLL_ENTRY.name, level = BASE_ROLL_ENTRY.level, modifier = BASE_ROLL_ENTRY.modifier }) local foundAny = false -- Try to read personality traits from the active TRP3 profile if TRP3_API and TRP3_API.profile and TRP3_API.profile.getData then local ok, characteristics = pcall(TRP3_API.profile.getData, "player/characteristics") if ok and characteristics and characteristics.PS then for _, trait in ipairs(characteristics.PS) do local skillName = trait.LT local numericValue = trait.V2 local keyword = FindSkillKeyword(trait.RT) if skillName and skillName ~= "" and keyword then local level, modifier = ParseSkillLevel(trait.RT, numericValue) if level and modifier then foundAny = true table.insert(skills, { name = skillName, level = level, modifier = modifier, warning = CheckSkillMismatch(keyword, numericValue), }) end end end end end -- If no valid skills were found, use the default fallback list if not foundAny then skills = {} for _, skill in ipairs(DEFAULT_SKILLS) do table.insert(skills, { name = skill.name, level = skill.level, modifier = skill.modifier }) end end -- Always add Unskilled as the last entry table.insert(skills, { name = UNSKILLED_ENTRY.name, level = UNSKILLED_ENTRY.level, modifier = UNSKILLED_ENTRY.modifier }) AltSystem.Data.Skills = skills return skills end -- Initialize with the default skill list AltSystem.Data.Skills = {} for _, skill in ipairs(DEFAULT_SKILLS) do table.insert(AltSystem.Data.Skills, { name = skill.name, level = skill.level, modifier = skill.modifier }) end -- Item options: name and modifier (first entry = no item) AltSystem.Data.Items = { { name = "No item", modifier = 0 }, { name = "Rare item", modifier = 3 }, { name = "Epic item", modifier = 5 }, } -- Defense options: name and modifier AltSystem.Data.Defenses = { { name = "Base armor", modifier = 0 }, { name = "Extra small armor", modifier = 1 }, { name = "Extra large armor", modifier = 2 }, } -- Shield modifier AltSystem.Data.ShieldModifier = 1