calls
Last updated on
Holocalls between players — ring, answer, decline, hang up, add a third participant, and swap contacts face to face.
A player presses H to open a centred hologram with their contacts and recent calls, and calls someone from it. The callee hears the game's incoming-call sound and the hologram pops up; they answer with Y or refuse with X (X also hangs up a live call or withdraws a call you placed). During a call both players' eyes carry the game's blue holocall glow and they share a voice channel. A third player can be added. Contacts are swapped face to face through a row on the target eye; only contacts appear in the hologram. The server owns every call; the client only asks.
| Side | both |
| Requires | character (hard) |
| Optional | target, menu |
| Contract | calls v1 — server (no client contract) |
| Config | config/calls.lua (shared) |
| Data | character metadata callContacts (≤ MAX_CONTACTS rows { citizenId, name }) and callRecent (last 20 outcomes) |
- Contacts only. A call or a join needs the target's citizen id in the caller's contacts; anyone else is refused
notContact, checked before anything about the target, so the refusal says nothing about who that id is or what they are doing. Strangers swap contacts face to face first. - Offering your contact to the same player again is refused for 30 s (
contactTooSoon); the floor is cleared when either player leaves. - Reach first for a contact offer. Out of
CONTACT_RANGEthe only answer istooFar, before anything is said about the target (down, loading, on a call), so an offer cannot probe a stranger from across the map. - Contacts can be deleted. Each contact row in the hologram has DELETE, which takes two presses (SURE?); Contact deleted. The row names a reference the server made for that list (
k1,k2…), never a citizen id. - A full list is refused, not trimmed. At
MAX_CONTACTS, sending a contact offer or accepting one is refused withcontactsFull(Your contact list is full. Delete a contact to make room.). The offer stays open, so the player can delete a contact and then accept. - Offline contacts are listed greyed as
offline, with no server id to call. - One player is in at most one call, with at most one invite out and one waiting.
- An invite has a
kind, decided by the server:call(start a call),join(the sender is in a call; accepting adds you) orcontact(swap contact rows; no call). invite,accept,declineandhangupare each limited to one perREQUEST_MSper player; a refusal is shown as a toast.- A call is dropped when a participant disconnects, leaves the world or is no longer alive (checked every
SCAN_MSand on life-state changes). When one of three leaves, the other two are told who hung up. A failed host read no longer ends live calls. - Names only for contacts. Every card, toast ("X joined / hung up / declined / did not answer") and recent-call row names a person only to a viewer who has them in their contacts; anyone else reads Unknown caller. A contact offer names its sender, never the person it was offered to. See Privacy.
- A contact offer tells its sender offered, declined or not answered, without the other person's name; the panel says Offering your contact....
- No toast repeats the hologram: X is calling you. and Calling X... are gone. The outcomes (answered, declined, no answer) are still toasts.
- An invite that rings out, or is answered just as it dies, updates the caller's screen and files a missed call on both sides. A disconnect while ringing: the callee gets a missed call, the caller reads "The call could not go through" and an unanswered row.
- Going down closes the hologram.
- Hanging up (and stopping the module) puts the voice route back to proximity.
- Audit entries:
calls.invite,calls.accept,calls.decline,calls.cancel,calls.hangUp,calls.contact,calls.forget,calls.unanswered,calls.eyes,calls.voice. - No commands.
Key bindings
| Mapping id | Default | Label key | Action |
|---|---|---|---|
opx.calls.holo | H | calls.key.holo | Open or close the hologram. |
opx.calls.answer | Y | calls.key.answer | Answer the waiting invite; nothing when nothing rings. |
opx.calls.decline | X | calls.key.decline | In order: refuse the invite ringing at you; else withdraw the invite you sent; else hang up the live call (M.DeclineOrHangUp). Label Decline or hang up a holocall. |
Y and X are shared, and a press goes to one owner (key contest, ranks in KEY_PRIORITY):
- X: a cancelable progress bar > a ringing call (decline) > your outgoing call (withdraw) > a carried crate > your emote > a call in progress (hang up). Cancelling an eat during a call no longer hangs up.
- Y: while a call rings, Y answers and the hotbar peek stays silent; otherwise Y peeks.
- H, Y and X do nothing while chat or a form holds the keyboard. Escape closes the hologram only when it is the top layer.
Configuration
config/calls.lua sets OPX.Config.MODULES.calls. Shared script. Numbers are clamped to the ranges shown.
Refusal codes
Shown to the player as calls.error.<code>.
| Code | Meaning |
|---|---|
badRequest | Malformed request. |
tooFast | Within REQUEST_MS of the last one. |
self | Calling yourself. |
notContact | The target is not in your contacts. |
contactTooSoon | You offered them your contact less than 30 s ago. |
noSuchPlayer | The target is not connected. |
notReady / targetNotReady | You / they are not in the world with a character. |
notAlive / targetNotAlive | You / they are down or dead. |
alreadyInCall / targetInCall | You / they are already on a call. |
alreadyPending / targetPending | You already have an invite out / they already have one waiting. |
notInCall | Hang up or add with no call. |
callFull | The call has MAX_PARTICIPANTS. |
alreadyParticipant | They are already on this call. |
noSuchInvite | No such invite waiting (or nothing to withdraw). |
expired | The invite rang out. |
tooFar | Contact swap outside CONTACT_RANGE. Checked first for a contact offer. |
contactsFull | Your contact list is at MAX_CONTACTS: delete one first. |
offline | Shown on a contact row: that person is not connected. |
unreadable | A host read failed. |