EndCore Framework

en-skills

Use-based skills with per-level bonuses, a perk tree paid for with character levels, and the bonus keys other resources read.

en-skills adds skills that improve as you use them:

SkillTrained by
EnduranceSprinting and swimming
StrengthMelee hits
ShootingLanding shots
ScavengingSearching bodies
MedicineUsing medical items
ThieveryLockpicking and hotwiring
CraftingCrafting
MechanicsRepairing vehicles

Each skill level adds small bonuses, such as more stamina, more carry weight, faster searches or better lockpicking, which other resources read.

Your character's en-core level also earns perk points, which you spend in a perk tree (press K). A perk can require a skill level, a character level or other perks, and gives a bigger bonus. You can reset your perks for cash, on a cooldown.

At a glance

Depends onen-core, en-ui
Start afterBoth of the above
Database tablesNone. Data lives in character metadata (metadata.skills)
Config filesconfig/shared.lua
Key bindsen_skills_menu (K)
Libraryencore.skills, safe to call even when en-skills isn't running

How it works

Levels

Skills go from level 1 to Config.maxLevel. Reaching level 2 takes curve.base XP, and each later level takes curve.growth times the XP of the previous level. With the defaults, the total XP needed is:

Level2345678910
Total XP10025047581313192078321749267489

To stop farming, the same skill can't gain XP for the same player more often than every Config.awardCooldown seconds. Hitting players never grants XP.

Bonuses

Each skill's bonuses are added once for every level above 1. The totals from skills and perks are summed and published to the player's skillBonuses state bag.

SkillBonus per level
endurancestamina 0.06
strengthmeleeDamage 0.03, carryWeight 1.0 kg
shootingweaponDamage 0.02, accuracy 0.04
scavengingsearchSpeed 0.04, extraLoot 0.015
medicinehealing 0.05
thieverylockpick 0.05, hotwire 0.03
craftingcraftSpeed 0.04
mechanicsrepair 0.05, hotwire 0.02

Who reads each bonus key:

KeyRead by
stamina, meleeDamage, weaponDamage, accuracyen-skills itself (GTA stats and damage modifiers)
carryWeight (kg)en-inventory, through the carryBonus state bag
searchSpeed, extraLoot, infectionResisten-zombies
healing, foodRisken-consumables
lockpick, hotwire, repairen-vehiclekeys, en-doorlock, en-garages
craftSpeed, craftRefunden-crafting

The client applies GTA stats (MP0_STAMINA, MP0_LUNG_CAPACITY, MP0_STRENGTH, MP0_SHOOTING_ABILITY) and weapon and melee damage modifiers whenever bonuses change, and again every 30 s.

XP en-skills awards itself

ActivityXP
firearmHitshooting +1 per hit on a non-player ped
meleeHitstrength +2 per hit on a non-player ped
enduranceMinuteendurance +4 per minute sprinting or swimming
corpseSearchedscavenging +4
medicalUsedmedicine +6, for items with category medical

Other XP comes from the resources that use the skill, such as crafting, lockpicking and repairs.

Perk points

Points are calculated, not stored:

lua
points = Config.startingPoints + (characterLevel - 1) * Config.pointsPerLevel - pointsSpent

If a character loses XP and drops a level, they can briefly have spent more points than they have. See XP and levels.

Default perks: marathon, second_wind, pack_mule, brawler, steady_hands, marksman, quick_hands, keen_eye, field_medic, iron_gut (character level 8), thick_skin, light_fingers, hot_start, tinkerer, thrifty, grease_monkey.

Configuration

KeyDefaultWhat it does
Config.keys.menu'K'Skills and perks menu
Config.maxLevel10Skill level cap
Config.curve{ base = 100, growth = 1.5 }XP curve
Config.pointsPerLevel1Perk points per character level after the first
Config.startingPoints1Starting perk points
Config.respeccost = 2500, moneyType = 'cash', cooldownHours = 24Perk reset price and cooldown
Config.awardCooldown1.0Minimum seconds between XP awards for the same skill and player
Config.skills8 skillslabel, icon, description, bonuses = { [key] = perLevel }
Config.orderlistDisplay order of skills
Config.activitysee aboveXP en-skills awards itself
Config.perks16 perksid, label, description, skill and level (optional), coreLevel (optional), requires = { perkIds }, cost, bonuses

Adding a skill and a perk chain

lua
Config.skills.survival = {
    label = 'Survival', icon = 'temperature',
    description = 'Hardier in the cold and on bad food. Improves by surviving.',
    bonuses = { foodRisk = 0.03, infectionResist = 0.01 },
}
Config.order[#Config.order + 1] = 'survival'

Config.perks[#Config.perks + 1] = { id = 'forager', label = 'Forager', skill = 'survival', level = 3, cost = 1,
    description = 'Bad water rarely makes you sick.', bonuses = { foodRisk = 0.3 } }
Config.perks[#Config.perks + 1] = { id = 'deep_pockets', label = 'Deep Pockets', coreLevel = 10, cost = 2,
    requires = { 'pack_mule', 'forager' }, description = 'Carry 8 kg more.', bonuses = { carryWeight = 8 } }
Note

A new skill only gains XP when something awards it. Call encore.skills.addXP(source, 'survival', amount) from your own resource.

Skills or perks you remove from config are dropped from characters when they load.

Library

Other resources should use encore.skills from the EndCore library rather than the exports. It returns safe defaults if en-skills isn't running. See Skills and party.

SideFunctions
ServeraddXP(source, skill, amount), getLevel(source, skill), getBonus(source, key), hasPerk(source, perk)
ClientgetLevel(skill), getBonus(key), hasPerk(perk)
BothisAvailable()

Exports

Server

ExportArgumentsReturns
AddSkillXPsource, skill, amountboolean. False for an unknown skill, an amount of 0 or less, a maxed skill, or within awardCooldown
GetSkillLevelsource, skillnumber (1 if unknown or not loaded)
GetBonussource, keynumber (0 by default)
HasPerksource, idboolean
GetSkillssource{ xp, levels, perks, points } or nil

Client

ExportReturns
GetSkillLevel(skill)number
GetBonus(key)number, from LocalPlayer.state.skillBonuses
HasPerk(id)boolean
GetSkills(){ xp, levels, perks }
OpenMenu() / CloseMenu()Opens or closes the skills page

Commands

CommandRestrictedWhat it does
/skillxp <target> <skill> <amount>group.adminGrants skill XP, ignoring the cooldown
/resetperks <target>group.adminRefunds all perks for free and clears the respec cooldown

Events

Emitted, server-local:

EventPayload
en-skills:server:levelUpsource, skill, newLevel, previousLevel
en-skills:server:perkUnlockedsource, perkId
en-skills:server:respecsource

en-skills listens to weaponDamageEvent, en-zombies:server:corpseLooted, en-consumables:server:consumed, encore:server:onPlayerLoaded, encore:server:onPlayerUnload and encore:server:levelChanged.

State bags

KeyScopeMeaning
skillBonusesPlayer, replicatedTable of summed bonus keys
carryBonusPlayer, replicatedExtra carry weight in kg (the carryWeight bonus)

Character metadata holds skills = { xp = { [skill] = number }, perks = { [perkId] = true }, respecAt = unixTime }. See Player data.

Examples

Award Survival XP from a campfire-cooking script and scale a result by a bonus:

lua
-- server
AddEventHandler('mycooking:server:cooked', function(source)
    encore.skills.addXP(source, 'survival', 5)
end)

local function searchTime(source, base)
    local bonus = encore.skills.getBonus(source, 'searchSpeed')
    return math.floor(base * (1 - math.min(0.5, bonus)))
end

Lock an action behind a perk:

lua
if not encore.skills.hasPerk(source, 'field_medic') then
    return false, 'You need the Field Medic perk.'
end

Celebrate level-ups:

lua
AddEventHandler('en-skills:server:levelUp', function(source, skill, newLevel)
    if newLevel == 10 then
        print(('%s mastered %s'):format(GetPlayerName(source), skill))
    end
end)