Home › Documentation › Custom · origen_phone
Custom · origen_phone text Copy
custom/
├── shared/
│ └── custom.lua
├── client/
│ └── notifications.lua
├── server/
│ ├── money.lua
│ └── permissions.lua
└── bridge/
├── banking/server.lua
├── business/server.lua
├── dispatch/server.lua
├── framework/client.lua
├── framework/server.lua
├── fuel/client.lua
├── garage/server.lua
├── housing/server.lua
├── inventory/client.lua
├── inventory/server.lua
├── notify/client.lua
├── uploader/server.lua
├── vehiclekeys/client.lua
├── voice/client.lua
├── voice/server.lua
└── weather/server.lua
Everything in custom/ is listed in escrow_ignore, so it stays open when the resource is encrypted, and it is separate from the core, so phone updates do not overwrite it. The provider files in bridge/ are also open: you can read them or copy one as a starting point.
Every Custom hook returns nil by default, which means "do the default thing". Return anything else and your code takes over.
custom/client/notifications.lua
Custom.ShowNotification(data) → boolean|nil
How a notification looks while the phone is put away. By default the phone peeks up from the bottom of the screen. With the phone open, notifications always show inside it.
Parameter Type Description datatable{ app, title, content, avatar, thumbnail }
Return Behaviour nilThe phone peeks up as usual trueYou already showed it; the phone does nothing
Use origen_notify instead of the phone:
lua Copy
function Custom . ShowNotification (data)
exports. origen_notify : ShowNotification (data. content , 'info' , 5000 )
return true
end
Only calls and messages use the phone, the rest your notify:
lua Copy
function Custom . ShowNotification (data)
if data. app == 'phone' or data. app == 'messages' then
return nil
end
exports. origen_notify : ShowNotification (data. content , 'info' , 5000 )
return true
end
The hook runs inside pcall. If it errors, the error is printed and the phone shows the notification as usual.
custom/server/money.lua
Every charge and payout the phone makes goes through here: ads, taxi fares, bills, transfers, dating subscriptions, line recovery. By default the phone uses the Banking bridge.
Custom.Charge(source, amount, reason, account) → boolean|nil, string|nil
Parameter Type Description sourcenumberPlayer server ID amountnumberAlways positive reasonstringAlready translated to the player's language accountstring|nilAccount the player picked, if the app lets them
Return Behaviour nilCharge through the banking bridge trueCharged, continue false, 'reason'Failed; the text is shown to the player
Charge cash instead of bank (Qbox):
lua Copy
function Custom . Charge (source, amount, reason)
local player = exports. qbx_core : GetPlayer (source)
if not player then return false , 'Player not found' end
if player. Functions . RemoveMoney ( 'cash' , amount, reason) then
return true
end
return false , 'You do not have enough cash'
end
Free ads for reporters:
lua Copy
function Custom . Charge (source, amount, reason)
local job = Framework. GetJob (source)
if reason : find ( 'Ad' ) and job and job. name == 'reporter' then
return true
end
return nil
end
Custom.Deposit(source, amount, reason) → boolean|nil, string|nil
Pays a player: driver and courier earnings, marketplace sales and refunds. Same return rules as Custom.Charge.
Parameter Type Description sourcenumberPlayer server ID amountnumberAmount to pay reasonstringAlready translated to the player's language
custom/server/permissions.lua
Custom.CanUseApp(source, appId) → boolean|nil
Your own veto on an app, for conditions that do not fit a panel rule. It runs after the panel rules and can only take access away, never grant it.
Parameter Type Description sourcenumberPlayer server ID appIdstring'bank', 'darkchat', 'blackmarket'...
Return Behaviour nilWhatever the panel says falseDenied, no matter what
lua Copy
function Custom . CanUseApp (source, appId)
if appId == 'bank' and MyResource. IsJailed (source) then
return false
end
return nil
end
This runs every time a phone opens, once per app (over thirty times in a row). Do not query the database here: keep what you need in memory.
custom/bridge
Every category has a template with the exact functions it needs. Fill it in and set the category to 'custom' in config/bridge.lua:
lua Copy
BridgeConfig. Banking = 'custom'
Each template registers itself with Bridge.Register(category, 'custom', { ... }) and is only used when its category is set to 'custom'.
custom/bridge/framework
Server
lua Copy
Bridge. Register ( 'Framework' , 'custom' , {
RegisterUsableItem = function (name, cb) end ,
GetPlayer = function (source) return nil end ,
Identifier = function (player) return nil end ,
Name = function (player) return nil end ,
Job = function (player) return nil end ,
Gang = function (player) return nil end ,
})
Method Returns Description RegisterUsableItem(name, cb)Registers the phone item as usable. cb(source, item) GetPlayer(source)table|nilYour framework's player object Identifier(player)string|nilStable character identifier (phone owner) Name(player)string|nil'Firstname Lastname'Job(player)table|nil{ name, label, type, grade, gradeLabel, onduty }Gang(player)table|nil{ name, label, grade, gradeLabel, isBoss }
Client
lua Copy
Bridge. Register ( 'Framework' , 'custom' , {
PlayerLoadedEvent = nil ,
IsDead = function () return false end ,
IsCuffed = function () return false end ,
})
Field Returns Description PlayerLoadedEventstring|nilClient event your framework fires once the character is loaded IsDead()booleanDead or downed: the phone cannot be used IsCuffed()booleanCuffed: the phone cannot be used
custom/bridge/inventory
Server
Method Returns Description Items(source, name)table[]|nil{ { slot, metadata } } for that item. nil when the inventory is not loaded yetSetMetadata(source, slot, meta)Writes metadata to the item in that slot All(source)table[]Every item: { name, label, count, slot, metadata } Remove(source, name, count)booleanRemoves items Add(target, name, count, meta)booleanAdds items to a player source or a stash id CanCarry(source, name, count)booleanWhether the player can carry the items
Client
Method Returns Description Items()table[]|nilThe local player's items, each with name and metadata
custom/bridge/banking/server.lua
Method Returns Description Accounts(citizenid)table[]{ { id, name, type, balance } }Charge(source, amount, reason)boolean, string|nilSuccess, and the error shown to the player Deposit(source, amount, reason)booleanPays the player Transactions(accountId)table[]{ { id, amount (negative = outgoing), description, type, createdAt (ms) } }AddToSociety(account, amount, reason)booleanDeposits a paid bill into the society or business account that issued it
lua Copy
Bridge. Register ( 'Banking' , 'custom' , {
Charge = function (source, amount, reason)
return exports. my_bank : RemoveMoney (source, amount, reason) == true
end ,
-- ...
})
custom/bridge/business/server.lua
Every method is optional: leave out what your business resource does not support.
Method Returns Description BusinessesOf(citizenid)table[]{ { id, name, label, type, onDuty } } businesses this character works forJobList()table[]{ { name, label } } business job names, for the admin panelDeliverOrder(businessId, orderId)booleanDelivers a supply order. false when the order no longer exists AddIncome(businessId, amount, kind, source, meta)booleanAdds income to the business till AddExpense(businessId, amount, kind, source, meta)Registers an expense
custom/bridge/dispatch/server.lua
Method Returns Description SendAlert(alert)booleanalert: { coords (vector3), title, message, job, source, number }. number is nil when anonymousCentralPlayers(job)number[]|nilSources answering that job's central. nil counts on-duty players instead
custom/bridge/garage/server.lua
Method Returns Description List(citizenid)table[]{ { plate, model, garage, state, fuel, engine, body, depotPrice } }. state: 0 out, 1 stored, 2 impounded. engine and body are 0 to 100Find(citizenid, plate)table|nil{ plate, model, mods (vehicle properties JSON), label, garage, stored (boolean) }Locate(garage)table|nil{ label, coords = { x, y } }TakeOut(plate)booleanMarks the vehicle as out of the garage (valet)
custom/bridge/housing/server.lua
Method Returns Description List(citizenid)table[]{ { id, name, mine (boolean), price, kind, keys (count), where = { x, y, z } } }Get(id, citizenid)table|nilSame shape as each List entry HasKey(citizenid, id)booleanWhether the character has a key to that property
custom/bridge/uploader/server.lua
Method Returns Description Upload(name, base64)string|nil url, string|nil errorUploads a file. name includes the extension Capture(source, options)string|nil url, string|nil errorCaptures the player's screen. options: { maxWidth, maxHeight }
custom/bridge/voice
Server
Method Returns Description SetCall(source, channel)Puts the player in a call channel. 0 leaves every call GetCall(source)numberCurrent call channel, 0 when in none
Client
Method Returns Description SetCallVolume(volume)Call volume, 5 to 100 RestoreCallEffect(serverId)Restores the call voice effect for that player
custom/bridge/weather/server.lua
Method Returns Description Get()table|nil{ weather (GTA weather type, e.g. 'CLEAR'), remaining (ms, optional), blackout, hour, minute }
custom/bridge/notify/client.lua
lua Copy
Bridge. Register ( 'Notify' , 'custom' , {
Send = function (message, kind)
lib. notify ({ description = message, type = kind == 'info' and 'inform' or kind })
end ,
})
Parameter Type Description messagestringNotification text kindstring'info', 'success', 'error' or 'warning'
custom/bridge/vehiclekeys/client.lua
lua Copy
Bridge. Register ( 'VehicleKeys' , 'custom' , {
GiveKeys = function (vehicle, plate)
end ,
})
Called by the valet when it delivers a vehicle. vehicle is the entity handle.
custom/bridge/fuel/client.lua
lua Copy
Bridge. Register ( 'Fuel' , 'custom' , {
SetFuel = function (vehicle, level)
SetVehicleFuelLevel (vehicle, level + 0.0 )
end ,
})
Called by the valet to restore the stored fuel level (0 to 100).