OPX//77
opx_infinitycalls

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.

Sideboth
Requirescharacter (hard)
Optionaltarget, menu
Contractcalls v1 — server (no client contract)
Configconfig/calls.lua (shared)
Datacharacter 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_RANGE the only answer is tooFar, 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 with contactsFull (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) or contact (swap contact rows; no call).
  • invite, accept, decline and hangup are each limited to one per REQUEST_MS per 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_MS and 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 idDefaultLabel keyAction
opx.calls.holoHcalls.key.holoOpen or close the hologram.
opx.calls.answerYcalls.key.answerAnswer the waiting invite; nothing when nothing rings.
opx.calls.declineXcalls.key.declineIn 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.

KeyDefaultEffect
enabledtruefalse switches the module off.
MAX_PARTICIPANTS3People on one call, 2–3 (3 is a hard ceiling).
INVITE_TTL_S30Seconds an unanswered invite rings, 5–300. Holds both players' invite slots meanwhile.
REQUEST_MS1500Minimum ms between two requests of one kind from one player, 0–60000.
CONTACT_RANGE6.0Metres between the two players for a contact swap, same bucket, 0.5–50. Calls have no range.
MAX_CONTACTS64Contact rows per character, 1–512. A full list refuses new contacts (contactsFull); nothing is dropped.
EYES{ LEASE_MS = 30000, RENEW_MS = 10000 }Eye-glow lease in ms (1000–600000), renewed every RENEW_MS (clamped 250..LEASE_MS/2), not on every SCAN_MS pass.
SCAN_MS2000Ms between sweeps: expire invites, drop unreachable participants, renew due leases (250–30000).
SOUNDgame ui_phone_* eventsINCOMING, INCOMING_STOP, ACCEPTED, DECLINED, OUTGOING, OUTGOING_STOP, HANG_UP: Wwise events played with Open77.sfx.play2d. '' switches one off.
RING_EVERY_MS3500Ms between two plays of the ring, 1000–60000.
KEY{ ID = 'opx.calls.holo', NAME = 'calls.key.holo', DEFAULT = 'H' }The hologram key. false (or no DEFAULT) binds none.
ANCHOR'bottom-center'Hologram position: top-left, top-center, top-right, left, center, right, bottom-left, bottom-center, bottom-right. Unknown: logged, falls back to bottom-center.
ANSWER_KEY{ ID = 'opx.calls.answer', NAME = 'calls.key.answer', DEFAULT = 'Y' }The answer key.
DECLINE_KEY{ ID = 'opx.calls.decline', NAME = 'calls.key.decline', DEFAULT = 'X' }The refuse / hang-up key.

Refusal codes

Shown to the player as calls.error.<code>.

CodeMeaning
badRequestMalformed request.
tooFastWithin REQUEST_MS of the last one.
selfCalling yourself.
notContactThe target is not in your contacts.
contactTooSoonYou offered them your contact less than 30 s ago.
noSuchPlayerThe target is not connected.
notReady / targetNotReadyYou / they are not in the world with a character.
notAlive / targetNotAliveYou / they are down or dead.
alreadyInCall / targetInCallYou / they are already on a call.
alreadyPending / targetPendingYou already have an invite out / they already have one waiting.
notInCallHang up or add with no call.
callFullThe call has MAX_PARTICIPANTS.
alreadyParticipantThey are already on this call.
noSuchInviteNo such invite waiting (or nothing to withdraw).
expiredThe invite rang out.
tooFarContact swap outside CONTACT_RANGE. Checked first for a contact offer.
contactsFullYour contact list is at MAX_CONTACTS: delete one first.
offlineShown on a contact row: that person is not connected.
unreadableA host read failed.

On this page