EndCore Framework

Skills and party interfaces

Award skill XP and scale actions by skill bonuses and perks with encore.skills, and share rewards with nearby party members with encore.party.

Two optional systems that change how rewards work. With en-skills, players get better at what they do: skill XP comes from actions, and bonuses make those actions faster or stronger. With en-party, survivors team up and share XP with members nearby.

Both interfaces are written so your code never has to check whether the resource exists. Without en-skills, everyone is level 1 with no bonuses. Without en-party, everyone is a party of one.

Skills

API

SideFunctionReturnsWithout en-skills
bothencore.skills.isAvailable()booleanfalse
serverencore.skills.addXP(source, skill, amount)booleanfalse (nothing recorded)
serverencore.skills.getLevel(source, skill)number1
serverencore.skills.getBonus(source, key)number0
serverencore.skills.hasPerk(source, perk)booleanfalse
clientencore.skills.getLevel(skill)number1
clientencore.skills.getBonus(key)number0
clientencore.skills.hasPerk(perk)booleanfalse
  • A missing en-skills is silent. An en-skills export that errors returns the fallback and logs a warning once.
  • Levels and bonuses go through tonumber, so a bad value becomes the fallback.
  • addXP and hasPerk return true only if en-skills returns exactly true.

Bonuses

A bonus is a fraction: 0.12 means 12%. These are the bonus keys in use:

stamina, meleeDamage, weaponDamage, accuracy, carryWeight (in kilograms, not a fraction), searchSpeed, extraLoot, healing, lockpick, hotwire, craftSpeed, craftRefund, repair, infectionResist, foodRisk.

Pass lockpick and hotwire bonuses to minigames as bonus.

Security

  • Only the server can award XP. There is no client addXP.
  • Client-side bonuses are good for feel: shorter progress bars, easier minigames. For anything that changes items, money or damage, read the bonus again on the server.

Examples

lua
-- server: after a successful heal
encore.skills.addXP(source, 'medicine', 5)
local heal = 25 * (1 + encore.skills.getBonus(source, 'healing'))
lua
-- server: crafting refund and a perk
local refund = encore.skills.getBonus(source, 'craftRefund')
if math.random() < refund then
    encore.inventory.addItem(source, 'scrap', 1)
end

if encore.skills.hasPerk(source, 'quick_hands') then
    -- ...
end
lua
-- client: a faster search for skilled players
local speed = encore.skills.getBonus('searchSpeed')
local done = encore.progress({
    label = 'Searching',
    duration = math.floor(5000 * (1 - encore.math.clamp(speed, 0, 0.8))),
    disable = { move = true },
})

Contract

A resource named en-skills must export:

SideExportReturns
serverAddSkillXP(source, skill, amount)boolean
serverGetSkillLevel(source, skill)number
serverGetBonus(source, key)number
serverHasPerk(source, perk)boolean
clientGetSkillLevel(skill)number
clientGetBonus(key)number
clientHasPerk(perk)boolean

en-skills also exports GetSkills, OpenMenu and CloseMenu, but the library doesn't use them, so a replacement doesn't need them for the interface. See en-skills.

Party

API

SideFunctionReturnsWithout en-party
bothencore.party.isAvailable()booleanfalse
serverencore.party.getPartyId(source)number?nil
serverencore.party.getMembers(source)number[], including source{ source }
serverencore.party.getNearbyMembers(source, radius?)number[], source first{ source }
serverencore.party.inSameParty(a, b)booleana == b
serverencore.party.shareXP(source, amount, reason?)booleanThe full amount goes to source
clientencore.party.getMembers()server ids, including yoursYour own server id
clientencore.party.isMember(serverId)booleantrue only for yourself

Behaviour:

  • A missing en-party is silent, because parties are optional. An export that errors logs a warning once.
  • If en-party returns an empty list, the library treats it like the fallback and returns a list with just the player.
  • inSameParty(a, b) is always true when a == b.
  • getNearbyMembers uses en-party's configured share radius unless you pass radius in metres.
  • shareXP asks en-party to split the XP with nearby members. If en-party isn't running, or its export errors, the whole amount goes to the player through exports['en-core']:AddXP(source, amount, reason). See XP and levels.

Security

Reward on the server only. Client-side membership is for display, such as marking party members; it doesn't prove anything to the server.

Examples

lua
-- server: zombie kill reward
encore.party.shareXP(killer, 25, 'Zombie kill')

for _, member in ipairs(encore.party.getNearbyMembers(killer)) do
    encore.skills.addXP(member, 'survival', 2)
end
lua
-- server: only party members may open each other's stash
RegisterNetEvent('my-stash:openFor', function(ownerId)
    local src = source
    if type(ownerId) ~= 'number' then return end
    if not encore.party.inSameParty(src, ownerId) then return end
    -- ...
end)
lua
-- client: tag party members on nameplates
for _, entry in ipairs(encore.getNearbyPlayers(GetEntityCoords(PlayerPedId()), 30.0)) do
    if encore.party.isMember(entry.serverId) then
        encore.drawText3d(entry.coords + vec3(0.0, 0.0, 1.1), 'PARTY')
    end
end

Contract

A resource named en-party must export:

SideExportReturns
serverGetPartyId(source)number?
serverGetMembers(source)number[], including source
serverGetNearbyMembers(source, radius?)number[], including source, first
serverInSameParty(a, b)boolean
serverShareXP(source, amount, reason?)boolean
clientGetMembers()number[] of server ids, including yours
clientIsMember(serverId)boolean