EndCore Framework

en-party

Short-lived teams of up to four survivors with map blips, a party HUD, and shared XP and loot for members nearby.

en-party lets survivors team up for a session. A party holds up to 4 players. Invite someone by looking at them (hold Alt, "Invite to party") or with /party invite <id>, or ask to join their party. An offer card pops up and they press Y to accept or X to decline.

Party members see each other as coloured map blips, even when far away and not streamed in, with a marker over their heads and a party HUD showing health, armour, downed and in-vehicle state. Members within 100 m of whoever earns a reward share XP and loot; en-zombies, for example, deals corpse finds out between nearby members. Parties are not saved: they end when broken up or when the server restarts. F6 opens the Survivors menu, with your party and your persistent en-core group side by side. Group invites use the same offer card.

At a glance

Depends on/onesync, en-core, en-ui
Optionalen-target (look-at invite options)
Start afteren-core, en-ui. Order does not matter for callers using encore.party.*
Database tablesNone (parties live in memory)
Config filesconfig/shared.lua
Key bindsen_party_menu (F6), en_party_accept (Y), en_party_decline (X)

How it works

  • Offers. Invites and join requests last Config.offerTimeout seconds, need the players within Config.offerDistance, and one player can only send an offer every Config.offerCooldown seconds.
  • Leadership. The creator leads. With Config.leaderInvitesOnly, only the leader can invite. Kicking and promoting are done from the menu.
  • Breaking up. With Config.disbandWhenAlone, a party ends when only one member remains.
  • Positions. Member positions are sent every Config.positionInterval ms for blips and the HUD.
  • Sharing XP. ShareXP gives XP to the earner and every member within Config.shareRadius. In 'split' mode the pot grows by bonusPerMember for each extra member and is divided: 4 members sharing 100 XP split 130, so 33 each (rounded, minimum 1). In 'full' mode everyone nearby gets the whole amount.
  • Without en-party. Every encore.party.* call behaves like a party of one, and XP goes straight to en-core's AddXP. Resources can call it without checking whether en-party is running.

en-party uses en-core's AddXP and GetCharacterName, and en-core's group callbacks and events for the Group tab. See Skills and party interface.

Configuration

config/shared.lua:

KeyDefaultWhat it does
Config.maxSize4Members, including the leader
Config.offerTimeout30 sHow long an invite or request lasts
Config.offerDistance25.0 mMax distance for /party invite and requests
Config.offerCooldown5 sTime between offers from one player
Config.leaderInvitesOnlyfalseOnly the leader may invite
Config.disbandWhenAlonetrueBreak up when one member remains
Config.shareRadius100.0 mReward sharing distance
Config.xp.mode'split''split' divides the pot (with bonus); 'full' gives everyone nearby the whole amount
Config.xp.bonusPerMember0.10Extra pot per additional member in split mode
Config.positionInterval1500 msBlip and HUD position updates
Config.keysmenu = 'F6', accept = 'Y', decline = 'X'Default keys
Config.blipsenabled true, sprite 1, scale 0.85, colours { 47, 3, 2, 27, 17, 8 }, downColour 40, showOffRadar trueMember blips (one colour per slot)
Config.overheadenabled true, distance 150.0Marker above members' heads

Squads of six where everyone gets full XP:

lua
-- config/shared.lua
Config.maxSize = 6
Config.xp = { mode = 'full', bonusPerMember = 0.0 }
Config.shareRadius = 150.0

Exports

Server

ExportArgumentsReturns
GetPartyIdsourceNumber or nil
GetPartysourceParty snapshot or nil
GetMemberssourcenumber[], including source; { source } with no party
GetNearbyMemberssource, radius?number[], source first, members within radius (default shareRadius)
InSamePartya, bboolean (true if a == b)
ShareXPsource, amount, reason?boolean. Other members see the reason as '<reason> (party)'
InviteToPartysource, targetok, message?
LeavePartysourceok, message?

Client

ExportArgumentsReturns
GetPartyParty table or nil
GetMembersServer ids
IsMemberserverIdboolean
OpenMenutab? ('party' or 'group')
CloseMenu

encore.party (preferred)

SideFunctions
Serverencore.party.getPartyId(src), getMembers(src), getNearbyMembers(src, radius?), inSameParty(a, b), shareXP(src, amount, reason?), isAvailable()
Clientencore.party.getMembers(), encore.party.isMember(serverId)

Commands

CommandWhat it does
/party invite <id>Invite a nearby player
/party acceptAccept your pending offer
/party declineDecline your pending offer
/party leaveLeave your party

/party is available to everyone. Requesting to join, kicking and promoting are only available from the menu and look options.

Look options

With en-target running, en-party adds three global player options, all at 3.0 m:

OptionShown when
en-party:invite "Invite to party"The target has no party state and you are allowed to invite
en-party:request "Ask to join their party"The target is in a party and you are not
en-party:groupInvite "Invite to group"The target has no group state and your group rank allows invites

Events

Server (local)

EventPayload
en-party:server:createdpartyId, leader
en-party:server:disbandedpartyId
en-party:server:joinedpartyId, source
en-party:server:leftpartyId, source

Client

EventTypePayload
en-party:client:changedLocalparty
en-party:client:showOfferLocaloffer
en-party:client:menuOpened / menuClosedLocal
en-party:client:updateNetParty snapshot or false
en-party:client:offerNet{ kind, from, size, timeout }
en-party:client:positionsNetMember position list

State bags

StateValue
Player(src).state.partyParty id (replicated) while in a party
Player(serverId).state.groupRead only; set by en-core groups

Examples

Reward a finished scavenging job to the whole team:

lua
-- server
RegisterNetEvent('my-scav:complete', function()
    local src = source
    encore.party.shareXP(src, 50, 'Cleared a pharmacy')

    for _, member in ipairs(encore.party.getNearbyMembers(src)) do
        encore.inventory.addItem(member, 'bandage', 1)
    end
end)

Stop friendly fire from counting in your own PvP script:

lua
-- server
AddEventHandler('my-pvp:server:playerKilled', function(killer, victim)
    if encore.party.inSameParty(killer, victim) then return end
    -- ... award the kill ...
end)