EndCore Framework

en-properties

Player-built bases with territory flags, walls, gates, storage, upkeep and decay, plus raiding with crowbars and breach charges.

en-properties lets survivors build their own bases. Use a building plan item to open the build menu and plant a Base Flag. The flag claims the ground within 35 m for you, or for your group if you're a group officer or leader. Inside that territory, only members can build walls, gates, storage crates and utility props such as a workbench, campfire, generator or work light. Placement uses a ghost preview with rotation and wall snapping.

Building costs materials, and so does upkeep. You pay upkeep in days at the flag, scaled by the size of the base, and an unpaid base decays every day.

Other players can raid a base. They can pry walls and doors apart with a crowbar (loud, and it draws zombies), force storage crates open, or plant breach charges that explode after a fuse. Destroying the flag abandons the base: its storage opens to anyone, and a new flag planted there takes it over.

Pieces are client-side local objects, so a base uses no networked entities.

At a glance

Depends on/onesync, oxmysql, en-core, en-ui, en-inventory
Start afterAll of the above
Works withen-crafting (workbench and campfire pieces), en-zombies (raid noise)
Database tablesencore_bases, encore_base_pieces
Config filesconfig/shared.lua
Itemsbuilding_plan, breach_charge, WEAPON_CROWBAR

How it works

Planting a flag

To plant a flag you need the plan item and must be placing within 9 m of yourself. The spot can't be in a no-build zone or inside claimed territory, and it must be at least 90 m from other flags. You must also be under the per-character or per-group base limit, and you pay the flag's cost.

A blank name defaults to "<Character name>'s Camp". New bases start with startingDays of upkeep. Planting inside an abandoned base's territory takes that base over.

Membership

The owner's character, or anyone in the owning group, is a member. Members can:

  • build pieces (each one awards 2 crafting XP)
  • repair pieces for 25% of their build cost
  • take pieces down for half the materials back (the flag must be the last piece, and removing it deletes the base)
  • set a numeric door code of up to 8 digits
  • open storage
  • pay upkeep at the flag, up to maxDays ahead
  • rename the base (3–40 characters)

Doors

Members open gates freely. So does anyone, once a base is abandoned. Outsiders need the door code, if one is set.

Storage

Storage pieces are en-inventory stashes with the id en-properties:<pieceId>. The piece's stash block sets the grid size and weight.

Upkeep and decay

Daily upkeep is the cost list multiplied by ceil(pieces / blockSize), with a minimum of one block. Decay is checked hourly. For each whole overdue day, every piece loses maxHealth * decay. A piece at 0 health is destroyed, and destroying the flag abandons the base.

Raiding

MethodToolEffect
Breach chargebreach_chargeExplodes after fuse seconds, damaging every piece within radius with falloff 1 - (distance / radius) * 0.6
TeardownCrowbarDeals damage to a wall or door per attempt (not flags or storage)
Force openCrowbarOpens a storage piece to anyone for openFor seconds

Teardown and forcing make noise that attracts zombies. A destroyed storage piece spills: its stash stays open to anyone for 10 minutes before it is removed. With offlineProtection on, a base can't be damaged while none of its members are online.

Streaming

The server sends bases to players within 260 m and removes them beyond 320 m. Clients spawn piece objects within 180 m.

Placement controls

ControlAction
Scroll wheelRotate
Hold ShiftFine rotation steps
Left mousePlace
Right mouse, Backspace or EscCancel

Configuration

KeyDefaultWhat it does
Config.planItem'building_plan'Usable item that opens the build menu
Config.territory.radius35.0Territory radius around the flag
Config.territory.minDistance90.0Minimum distance between flags
Config.territory.maxPerCharacter1Personal bases per character
Config.territory.maxPerGroup2Bases per group
Config.territory.maxPieces150Pieces per base, flag included
Config.territory.noBuild3 zones{ label, coords = vec3, radius } where nothing can be built
Config.placementmaxDistance = 9.0, rotateStep = 15.0, fineStep = 2.5, snap = true, snapDistance = 0.9Ghost placement
Config.upkeepenabled = true, dayHours = 24, blockSize = 10, cost = { { item = 'scrapmetal', count = 2 } }, startingDays = 3, maxDays = 14, decay = 0.2Upkeep and decay
Config.raiding.enabledtrueMaster switch for raiding
Config.raiding.offlineProtectionfalseProtect bases while no member is online
Config.raiding.breachitem = 'breach_charge', fuse = 12, damage = 900, radius = 4.0Breach charges
Config.raiding.teardowntools = { 'WEAPON_CROWBAR' }, duration = 8000, damage = 70, noise = 'crash'Prying walls and doors
Config.raiding.forceOpentools = { 'WEAPON_CROWBAR' }, duration = 25000, openFor = 300, noise = 'crash'Forcing storage
Config.repairCost0.25Repairs cost this fraction of the build cost, rounded up
Config.categoriescore, walls, doors, storage, utilityBuild menu tabs, in order
Config.pieces15 piecesBuildable pieces, keyed by kind

Piece fields

FieldWhat it does
labelName in the build menu
categoryTab from Config.categories
modelProp model
healthMaximum health
descriptionBuild menu text
cost{ { item, count }, ... }
roleflag, door, storage or station; omit for a plain structure
snap'wall' to snap to the edges of other wall pieces
stash{ width, height, maxWeight }, storage only

Default pieces:

CategoryPieces
coreflag
wallswall_wood, wall_sheet, wall_sandbag, wall_barrier, container
doorsgate_farm, gate_chain
storagebox_wood (6x4, 60 kg), box_military (8x6, 150 kg), toolchest (10x6, 220 kg)
utilityworkbench, campfire, generator, worklight

Adding pieces

Any GTA prop can be a piece. This example adds a sturdier sandbag wall and a larger crate:

lua
Config.pieces.wall_sandbag_heavy = {
    label = 'Double Sandbag Wall', category = 'walls', model = 'prop_mb_sandblock_02', health = 2600, snap = 'wall',
    description = 'Two layers deep. Takes a lot of prying.',
    cost = { { item = 'cloth', count = 16 }, { item = 'scrapmetal', count = 6 } },
}

Config.pieces.supply_cache = {
    label = 'Supply Cache', category = 'storage', model = 'prop_mil_crate_01', health = 1400, role = 'storage',
    description = 'A reinforced crate for the good stuff.',
    cost = { { item = 'scrapmetal', count = 24 }, { item = 'duct_tape', count = 2 } },
    stash = { width = 10, height = 8, maxWeight = 250.0 },
}
Warning

Workbench and campfire pieces work as crafting stations because en-crafting targets props by model. If you change a station piece's model, make sure it's also listed in that station's models in en-crafting.

Exports

Server

ExportArgumentsReturns
GetBaseAtcoords (vector3){ id, name, citizenid, group_id, pieces } (piece count) or nil
GetBaseid{ id, name, x, y, z, citizenid, groupId, pieces } with a list of public pieces, or nil
IsBaseMembersource, idboolean
DamagePiecepieceId, amountboolean: whether the piece was destroyed (false if it doesn't exist). Ignores raid rules

A public piece is { id, baseId, kind, x, y, z, heading, health, maxHealth, open, coded, forced }.

Client

ExportArgumentsReturns
GetBaseAtcoordsThe base whose territory contains coords, from bases streamed to this client, or nil

Commands

CommandRestrictedWhat it does
/baseheregroup.adminShows the id, name, owner, piece count and upkeep days of the base you're standing in
/deletebase <id>group.adminDeletes a base with all its pieces and stashes

Events

Server-local events:

EventPayload
en-properties:server:builtsource, baseId, pieceId, kind
en-properties:server:pieceDamagedpieceId, baseId, amount, source?
en-properties:server:pieceRemovedpieceId, baseId, destroyed
en-properties:server:abandonedbaseId, reason?
en-properties:server:breachedsource, baseId, coords
en-properties:server:forcedsource, pieceId, baseId

Database

TableColumns
encore_basesid (primary key), citizenid, group_id, name VARCHAR(60), x, y, z, paid_until (unix time), decayed_at, created_at
encore_base_piecesid (primary key), base_id (foreign key to encore_bases.id, ON DELETE CASCADE), kind, x, y, z, heading, health, data (JSON, e.g. { code } for doors)

Storage contents are stored by en-inventory under stash id en-properties:<pieceId>.

Examples

Block a custom placeable item inside other players' bases:

lua
-- server
local base = exports['en-properties']:GetBaseAt(GetEntityCoords(GetPlayerPed(source)))

if base and not exports['en-properties']:IsBaseMember(source, base.id) then
    return false, 'You can\'t set that up in someone else\'s base.'
end

Let your own explosive damage base pieces:

lua
-- server
AddEventHandler('mymortar:server:impact', function(pieceIds)
    for _, pieceId in ipairs(pieceIds) do
        exports['en-properties']:DamagePiece(pieceId, 400)
    end
end)

Announce raids to the owning group:

lua
AddEventHandler('en-properties:server:breached', function(source, baseId, coords)
    local base = exports['en-properties']:GetBase(baseId)
    print(('%s is under attack at %.0f, %.0f'):format(base and base.name or baseId, coords.x, coords.y))
end)