Messages
The inbox behind the ePADD's Messages app: crew-to-crew notes, mail from a story, and the replies a message can offer. See The ePADD for how a mission writes them.
Messages a crew can read and send: from each other, and from home.
Two things arrive in the same inbox, deliberately:
- Crew to crew. Helm texts Engineering. It is a bridge simulator with people sat at separate screens who cannot see each other, and passing a note is half of what they would do if they could.
-
From content. A mission, a quest beat or a map sends a letter from a character - family, a friend, a commanding officer.
message_sendis the same call either way, so a story never needs to know how the inbox works.message_send("Made it to the outer colonies. Mum sends her love.", to="helm", sender="Your brother") message_send("All hands: contact in ten minutes.", sender="The Captain")
ADDRESSED TO A CONSOLE, not to a person. A console is what ePADD knows, what a client
is sitting at, and what survives a player disconnecting and coming back - a crew name
does none of those. to="*" is everyone, and is the default, because the common case
from a story is an announcement.
READ STATE IS PER CONSOLE, and kept beside the messages rather than on the client: consoles get reassigned to different clients, and an inbox that forgot what it had read every time someone swapped seats would be worse than not tracking it at all.
Everything lives on Agent.SHARED, which clear_shared() rebuilds per mission, so an
inbox does not survive into the next mission.
message_answer(mid, index, console=None, seq=None)
Take one of a message's replies.
Returns the chosen dict, or None when the answer is refused - a stale seq, an already-answered message, an index that is not on offer for this console, or an outcome handler that says no (an unaffordable cost, say).
The seq moves BEFORE the outcomes run, so a second console pressing in the same frame is refused rather than applying the outcome twice. That is hail.py's discipline and the reason is the same: the outcomes are the part that cannot be undone.
message_answer_scene(scene_key, label, by=None, others=None)
Record what an away beat was answered with.
The beat's replies live in away.py, not on the message, so the message cannot
know on its own that it has been settled - and an answered beat that still showed
live buttons, or showed nothing at all, is the transcript losing the half that
matters. Called by away_answer once a pick has actually been applied.
message_answered(mid)
What was chosen, or None. A console that arrives late reads the decision.
message_ask(text, to='*', sender=None, subject=None, choices=None, kind='mail')
Send a message and wait for its reply.
answer = await message_ask("Do we hold?", to="helm",
sender="The Captain", choices=["Hold", "Break off"])
Resolves with the chosen dict. A message nobody answers keeps the task waiting -
compose it with a timeout when that matters:
promise_any(message_ask(...), delay_sim(60)).
message_bump()
Say that something the inbox draws has changed.
message_choices(mid, console=None)
The replies this console is offered on this message, guards applied.
Empty once the message is answered - a decision that has been taken is not still on offer, and leaving the buttons up invites a second press that can only be refused.
message_clear()
Drop every message and every read mark. For a mission that wants a clean inbox mid-game; the mission reset already does this on its own.
message_deliver_due(now=None)
Send every loaded message whose After: has passed, and forget it.
A mission ticks this (a do_interval, or its own loop). Mail that arrives while
the crew is flying is the point - a pile that all landed at t=0 would be a
document, not a message.
Returns:
| Name | Type | Description |
|---|---|---|
int |
how many were delivered this call. |
message_forwarded_from(msg, console=None, client_id=None)
The post this message was really addressed to, when the reader is covering.
None when it is their own mail - so a screen can label a forwarded letter without having to work out the addressing a second time.
message_forwarding(on=True)
Whether mail for an empty post is forwarded to somebody. On by default.
message_inbox(console=None)
Messages this console can see, newest first.
message_load_amd(doc, to=None)
Read messages out of a parsed AMD document into the pending pile.
A heading is a message when its fence has a From. The section heading, which
has none, is skipped - the same rule the recipe loader uses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
a parsed AMD document ( |
required | |
to
|
str
|
who they are for when a message does not say. Defaults to everyone. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
how many were loaded. |
message_mail(text, to='*', sender=None, subject=None)
A message from content - a letter from family, a friend, an admiral. Exactly
message_send(kind="mail"), named so a story reads as what it is.
message_mark_read(mid=None, console=None)
Mark one message read for a console, or the whole inbox when mid is None.
message_pending_count()
Reset-ledger probe for the undelivered pile.
message_promise_count()
Reset-ledger probe: a task waiting on a reply that a reload will never bring.
message_revision(console=None)
What the inbox screen watches to know it must repaint.
Combines the mail itself with THIS console's selection, because both change what
is on screen and neither wakes await gui() on its own. Two consoles reading
different messages therefore repaint independently.
message_select(mid, console=None)
Remember which message this console is reading, so it survives the repaint.
A rebuild makes a NEW listbox whose selection starts empty; without this the reading pane would snap back to the newest message every time anything arrived.
message_selected(console=None)
The message id this console is reading, or None.
message_send(text, to='*', sender=None, subject=None, kind='crew', choices=None, scene=None)
Put a message in an inbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
the body. Trimmed to MAX_TEXT. |
required |
to
|
str
|
console name, comma list, or "*" for everyone. |
'*'
|
sender
|
str
|
who it is from. A crew message defaults to the console that sent it; a story message should always say. |
None
|
subject
|
str
|
a short line for the list. |
None
|
kind
|
str
|
"crew" or "mail" - what a story sends. The inbox shows them differently; nothing else depends on it. |
'crew'
|
choices
|
list
|
replies to offer, as |
None
|
scene
|
str
|
an away scene key. Marks this message as that beat, so
the inbox asks |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
the stored message. |
message_unread(console=None)
How many this console has not read. This is what the app badge shows.
messages_count()
Reset-ledger probe.