Repository navigation
[CPLUS plus ex] Skill Selection
Functions for selecting skills for pilots.
Modders generally are not expected to use these but they may be helpful for testing changes and your skills. None of these need to be called manually.
- applySkillsToPilot
- applySkillIdsToPilot
- applySkillsToAllPilots
- selectRandomSkill
- selectRandomSkills
- getAssignableSkillIds
- markPerRunSkillAsUsed
- unmarkPerRunSkill
- canBeVirtualSkill
- registerVirtualSkillSource
- addVirtualSkillToPilot
- addVirtualSkillsToPilot
- addRandomVirtualSkillsToPilot
- removeVirtualSkillFromPilot
- clearVirtualSkillsFromPilot
-
voidcplus_plus_ex:applySkillsToPilot(pilot, fireHooks)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
fireHooks |
bool | If true, fires skillsSelected hook before applying skills (Default: false) |
Applies level up skills to a pilot. If the pilot already has assigned skills, those are loaded and applied. Otherwise, random skills are selected based on configuration and constraints, then applied.
Example:
-- Apply skills to pod reward pilot
local podPilot = Game:GetPodRewardPilot()
if podPilot then
cplus_plus_ex:applySkillsToPilot(podPilot, true)
end-
voidcplus_plus_ex:applySkillIdsToPilot(pilot, skillIds, fireHooks)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
skillIds |
table | Table with two skill IDs: {skill1Id, skill2Id}
|
fireHooks |
bool | If true, fires skillsSelected hook before applying skills (Default: false) |
Applies specific skills to a pilot by ID. Use this to manually assign skills instead of random selection.
Example:
local pilot = Game:GetSquadPilots()[1]
-- Force override pilot skills
cplus_plus_ex:applySkillIdsToPilot(pilot, {"Move", "Grid"})-
voidcplus_plus_ex:applySkillsToAllPilots()
Applies skills to all available pilots (squad + storage). Pilots that already have skills assigned will be skipped. New pilots will have skills applied/assigned.
Fires preAssigningLvlUpSkills and postAssigningLvlUpSkills hooks if any new pilots are found. Also fires skillsSelected hooks for each new pilot.
Example:
-- Manually trigger skill application
cplus_plus_ex:applySkillsToAllPilots()-
string|falsecplus_plus_ex:selectRandomSkill(availableSkills, pilot, idx, selectedSkills)
| Argument name | Type | Description |
|---|---|---|
availableSkills |
table |
Array of skill ID strings (mutated: invalid candidates are removed). Prefer getAssignableSkillIds(). Do not pass getEnabledSkillsSet() (set has no array length for ipairs). |
pilot |
Pilot | memhack Pilot struct |
idx |
int | Index of skill to assign (1-2 normal, 3+ virtual) |
selectedSkills |
table | Array-like table of already selected skill IDs; written at idx on success |
Selects a weighted random skill ID that passes constraints for idx. On success, sets selectedSkills[idx] and returns the skill id string. Returns false if none available.
Example:
local pool = cplus_plus_ex:getAssignableSkillIds()
local pilot = Game:GetSquadPilots()[1]
local skills = {"Reactor"}
local chosen = cplus_plus_ex:selectRandomSkill(pool, pilot, 2, skills)
if chosen then
LOG("Selected second skill: " .. skills[2])
end-
tablecplus_plus_ex:selectRandomSkills(availableSkills, pilot, count)
| Argument name | Type | Description |
|---|---|---|
availableSkills |
table | Array like table of skills that can be chosen |
pilot |
Pilot | memhack Pilot struct |
count |
int | Number of skills to assign to the pilot. Can exceed 2 for virtual skills |
Selects random level up skills based on count and configured constraints.
The count parameter can exceed 2 to select virtual skills. Slots 1-2 are regular skills, slots 3+ are virtual skills.
Returns an array like table of the skill IDs selected.
Example:
local pool = cplus_plus_ex:getAssignableSkillIds()
local pilot = Game:GetSquadPilots()[1]
local skills = cplus_plus_ex:selectRandomSkills(pool, pilot, 2)
LOG("Selected skill " .. skills[1] .. " and skill " .. skills[2])-
tablecplus_plus_ex:getAssignableSkillIds()
Returns an array of enabled skill IDs eligible for random assignment. Internal skills (internalSkill = true) are omitted; they can still be set via applySkillIdsToPilot.
Example:
local pool = cplus_plus_ex:getAssignableSkillIds()
for _, skillId in ipairs(pool) do
LOG("Assignable: " .. skillId)
end-
voidcplus_plus_ex:markPerRunSkillAsUsed(skillId)
| Argument name | Type | Description |
|---|---|---|
skillId |
string | Skill ID |
Records a PER_RUN skill as assigned this run so it will not be selected again. No op for non per run skills. Call after a skill is applied, not during pool selection. CPLUS+ calls this automatically during normal assignment.
-
voidcplus_plus_ex:unmarkPerRunSkill(skillId)
| Argument name | Type | Description |
|---|---|---|
skillId |
string | Skill ID |
Releases a per run claim so a pilot can keep or replace their own stored skill during revalidation. Used internally when validating existing skills. Rarely needed by mods.
-
boolcplus_plus_ex:canBeVirtualSkill(skillId)
| Argument name | Type | Description |
|---|---|---|
skillId |
string | Skill ID to check |
Checks if a skill is allowed to be assigned as a virtual skill. Returns false for skills with hardcoded vanilla behavior that doesn't work correctly in virtual slots, or for skills that don't exist.
Returns true if the skill can be assigned as a virtual skill (slot 3+)
Vanilla skills that cannot be virtual:
- Opener, Closer, Popular, Thick, Invulnerable, Adrenaline, Pain, Regen, Conservative
Example:
if cplus_plus_ex:canBeVirtualSkill("Reactor") then
LOG("Reactor can be a virtual skill")
end
if not cplus_plus_ex:canBeVirtualSkill("Opener") then
LOG("Opener has hardcoded behavior and cannot be virtual")
end-
boolcplus_plus_ex:registerVirtualSkillSource(sourceId, callback)
| Argument name | Type | Description |
|---|---|---|
sourceId |
string | Source id of the source granting virtual skills (e.g. "warbot") |
callback |
fn | function to call when a skill is no longer allowed |
Registers a skill source for virtual skills and allows defining behavior when the skill not longer is valid.
This is OPTIONAL and not required for skill sources. If not specified, it will default to re-rolling the skill. Sources MUST register with this to implement different behavior
callback function signature: onSkillInvalidated(pilot, skillData, alreadyAssigned)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
skillData |
table | Virtual skill entry: { id = string, source = string }
|
alreadyAssigned |
table | Skills already assigned to the pilot |
The callback returns the same skill id to keep it, nil to remove it, or a different skill id to replace it.
Returns true if successfully registered
Example:
-- Forces nimble regardless
local function onSkillInvalidated(pilot, skillData, alreadyAssigned)
return "RrNimble"
end
cplus_plus_ex:registerVirtualSkillSource("ForcedNimble", onSkillInvalidated)-
boolcplus_plus_ex:addVirtualSkillToPilot(pilot, skillId, source)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
skillId |
string | Skill ID to add as a virtual skill |
source |
string | Optional. Source of the virtual skill for tracking/invalidation behavior |
Adds a single virtual skill to the pilot in the first available virtual slot (slot 3+). Validates constraints including:
- Skill must be virtual-capable (
canBeVirtualSkill) - Skill must be enabled in configuration
- Must satisfy reusability constraints (PER_PILOT, PER_RUN)
- Must satisfy slot restrictions and exclusions
Source is optional and can be used to track where it came from and define behavior if the skill no longer becomes valid for the run. See registerVirtualSkillSource for more info on source and behavior.
Returns true if the skill was successfully added
Example:
local pilot = Game:GetSquadPilots()[1]
-- Add a third skill
if cplus_plus_ex:addVirtualSkillToPilot(pilot, "Grid") then
LOG("Successfully added Grid as slot 3")
else
LOG("Failed - constraint violation or skill not virtual-capable")
end-
intcplus_plus_ex:addVirtualSkillsToPilot(pilot, skillIds, source)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
skillIds |
table | Array of skill IDs to add: {"skill1", "skill2", ...}
|
source |
string | Optional. Source of the virtual skill for tracking/invalidation behavior |
Adds multiple virtual skills to the pilot in the order provided. Each skill is validated before adding. Returns the total count of skills that were successfully added.
Source is optional and can be used to track where it came from and define behavior if the skill no longer becomes valid for the run. See registerVirtualSkillSource for more info on source and behavior.
Returns count of skills successfully added
Example:
local pilot = Game:GetSquadPilots()[1]
-- Try to add 3 virtual skills
local skills = {"Move", "Grid", "Reactor"}
local count = cplus_plus_ex:addVirtualSkillsToPilot(pilot, skills)
LOG(string.format("Successfully added %d out of %d virtual skills", count, #skills))-
intcplus_plus_ex:addRandomVirtualSkillsToPilot(pilot, count, source)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
count |
number | Number of random virtual skills to add |
source |
string | Optional. Source of the virtual skill for tracking/invalidation behavior |
Randomly selects and adds virtual skills to the pilot based on:
- Configuration weights
- Skill constraints (exclusions, reusability, slot restrictions)
- Available enabled skills that can be virtual
Source is optional and can be used to track where it came from and define behavior if the skill no longer becomes valid for the run. See registerVirtualSkillSource for more info on source and behavior.
Returns the count of skills successfully added (may be less than requested if constraints are violated).
Example:
local pilot = Game:GetSquadPilots()[1]
-- Add 2 random virtual skills
local count = cplus_plus_ex:addRandomVirtualSkillsToPilot(pilot, 2)
if count > 0 then
LOG(string.format("Added %d random virtual skills", count))
else
LOG("Could not add any virtual skills (no valid options)")
end-
boolcplus_plus_ex:removeVirtualSkillFromPilot(pilot, skillId)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
skillId |
string | Skill ID to remove |
Removes the first occurrence of the specified virtual skill from the pilot. If the pilot has the same skill multiple times as virtual skills, only one instance is removed. This only affects virtual skills (slot 3+) - It will NOT remove skills from slots 1-2
Returns true if a virtual skill was removed
Example:
local pilot = Game:GetSquadPilots()[1]
if cplus_plus_ex:removeVirtualSkillFromPilot(pilot, "Reactor") then
LOG("Removed Reactor from virtual skills")
else
LOG("Pilot doesn't have Reactor as a virtual skill")
end-
boolcplus_plus_ex:clearVirtualSkillsFromPilot(pilot)
| Argument name | Type | Description |
|---|---|---|
pilot |
Pilot | memhack Pilot struct |
Removes all virtual skills from the pilot. This only affects virtual skills (slot 3+) - It will NOT remove skills from slots 1-2
Returns true if any virtual skills were cleared
Example:
local pilot = Game:GetSquadPilots()[1]
if cplus_plus_ex:clearVirtualSkillsFromPilot(pilot) then
LOG("Cleared all virtual skills from " .. pilot:getNameStr())
else
LOG(pilot:getNameStr() .. " had no virtual skills to clear")
end