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 after | All of the above |
| Works with | en-crafting (workbench and campfire pieces), en-zombies (raid noise) |
| Database tables | encore_bases, encore_base_pieces |
| Config files | config/shared.lua |
| Items | building_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
craftingXP) - 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
maxDaysahead - 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
| Method | Tool | Effect |
|---|---|---|
| Breach charge | breach_charge | Explodes after fuse seconds, damaging every piece within radius with falloff 1 - (distance / radius) * 0.6 |
| Teardown | Crowbar | Deals damage to a wall or door per attempt (not flags or storage) |
| Force open | Crowbar | Opens 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
| Control | Action |
|---|---|
| Scroll wheel | Rotate |
| Hold Shift | Fine rotation steps |
| Left mouse | Place |
| Right mouse, Backspace or Esc | Cancel |
Configuration
| Key | Default | What it does |
|---|---|---|
Config.planItem | 'building_plan' | Usable item that opens the build menu |
Config.territory.radius | 35.0 | Territory radius around the flag |
Config.territory.minDistance | 90.0 | Minimum distance between flags |
Config.territory.maxPerCharacter | 1 | Personal bases per character |
Config.territory.maxPerGroup | 2 | Bases per group |
Config.territory.maxPieces | 150 | Pieces per base, flag included |
Config.territory.noBuild | 3 zones | { label, coords = vec3, radius } where nothing can be built |
Config.placement | maxDistance = 9.0, rotateStep = 15.0, fineStep = 2.5, snap = true, snapDistance = 0.9 | Ghost placement |
Config.upkeep | enabled = true, dayHours = 24, blockSize = 10, cost = { { item = 'scrapmetal', count = 2 } }, startingDays = 3, maxDays = 14, decay = 0.2 | Upkeep and decay |
Config.raiding.enabled | true | Master switch for raiding |
Config.raiding.offlineProtection | false | Protect bases while no member is online |
Config.raiding.breach | item = 'breach_charge', fuse = 12, damage = 900, radius = 4.0 | Breach charges |
Config.raiding.teardown | tools = { 'WEAPON_CROWBAR' }, duration = 8000, damage = 70, noise = 'crash' | Prying walls and doors |
Config.raiding.forceOpen | tools = { 'WEAPON_CROWBAR' }, duration = 25000, openFor = 300, noise = 'crash' | Forcing storage |
Config.repairCost | 0.25 | Repairs cost this fraction of the build cost, rounded up |
Config.categories | core, walls, doors, storage, utility | Build menu tabs, in order |
Config.pieces | 15 pieces | Buildable pieces, keyed by kind |
Piece fields
| Field | What it does |
|---|---|
label | Name in the build menu |
category | Tab from Config.categories |
model | Prop model |
health | Maximum health |
description | Build menu text |
cost | { { item, count }, ... } |
role | flag, 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:
| Category | Pieces |
|---|---|
| core | flag |
| walls | wall_wood, wall_sheet, wall_sandbag, wall_barrier, container |
| doors | gate_farm, gate_chain |
| storage | box_wood (6x4, 60 kg), box_military (8x6, 150 kg), toolchest (10x6, 220 kg) |
| utility | workbench, campfire, generator, worklight |
Adding pieces
Any GTA prop can be a piece. This example adds a sturdier sandbag wall and a larger crate:
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 },
}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
| Export | Arguments | Returns |
|---|---|---|
GetBaseAt | coords (vector3) | { id, name, citizenid, group_id, pieces } (piece count) or nil |
GetBase | id | { id, name, x, y, z, citizenid, groupId, pieces } with a list of public pieces, or nil |
IsBaseMember | source, id | boolean |
DamagePiece | pieceId, amount | boolean: 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
| Export | Arguments | Returns |
|---|---|---|
GetBaseAt | coords | The base whose territory contains coords, from bases streamed to this client, or nil |
Commands
| Command | Restricted | What it does |
|---|---|---|
/basehere | group.admin | Shows the id, name, owner, piece count and upkeep days of the base you're standing in |
/deletebase <id> | group.admin | Deletes a base with all its pieces and stashes |
Events
Server-local events:
| Event | Payload |
|---|---|
en-properties:server:built | source, baseId, pieceId, kind |
en-properties:server:pieceDamaged | pieceId, baseId, amount, source? |
en-properties:server:pieceRemoved | pieceId, baseId, destroyed |
en-properties:server:abandoned | baseId, reason? |
en-properties:server:breached | source, baseId, coords |
en-properties:server:forced | source, pieceId, baseId |
Database
| Table | Columns |
|---|---|
encore_bases | id (primary key), citizenid, group_id, name VARCHAR(60), x, y, z, paid_until (unix time), decayed_at, created_at |
encore_base_pieces | id (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:
-- 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.'
endLet your own explosive damage base pieces:
-- 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:
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)