Chat & HUD Messaging Guide
This guide covers sending messages to players through chat, HUD announcements, console output, and world text.
HUD Announcements
Large on-screen announcements visible to targeted players:
var msg = new CCitadelUserMsg_HudGameAnnouncement
{
TitleLocstring = "ANNOUNCEMENT TITLE",
DescriptionLocstring = "Description text here"
};
// Send to all players
NetMessages.Send(msg, RecipientFilter.All);
// Send to one player
NetMessages.Send(msg, RecipientFilter.Single(playerSlot));
Console Messages
Print to a specific player's console:
controller.PrintToConsole("Hello, player!");
Print to all players' consoles:
CCitadelPlayerController.PrintToConsoleAll("Server message for everyone");
Or use Server.ClientCommand:
Server.ClientCommand(playerSlot, "echo Hello from server!");
Chat Messages
Intercepting Chat
Override OnChatMessage to intercept all chat:
public override HookResult OnChatMessage(ChatMessage msg)
{
Console.WriteLine($"[Chat] Slot {msg.SenderSlot}: {msg.Text}");
return HookResult.Handled;
}
Rebroadcasting Chat
Hook outgoing chat messages for custom formatting:
[NetMessageHandler]
public HookResult OnChatMsgOutgoing(OutgoingMessageContext<CCitadelUserMsg_ChatMsg> ctx)
{
var sender = Players.FromSlot(ctx.Message.SenderSlot);
if (sender == null) return HookResult.Handled;
// Send personalized chat to each recipient
foreach (var controller in Players.GetAll())
{
var personalMsg = new CCitadelUserMsg_ChatMsg
{
// Customize per-recipient
Text = $"[{sender.Name}]: {ctx.Message.Text}"
};
NetMessages.Send(personalMsg, RecipientFilter.Single(controller.EntityIndex));
}
// Block the original message
return HookResult.Stop;
}
Sounds
Play sound effects on entities:
// Basic sound
pawn.EmitSound("Mystical.Piano.AOE.Warning");
// With parameters
pawn.EmitSound("Damage.Send.Crit", pitch: 100, volume: 0.1f, soundLevel: 75f);
Delayed Sound
Timer.Once(1.Seconds(), () =>
{
pawn.EmitSound("Mystical.Piano.AOE.Explode");
});
World Text
3D text panels in the world:
var text = CPointWorldText.Create(
"GAME OVER",
position: new Vector3(0, 0, 500),
fontSize: 200f,
r: 255, g: 0, b: 0, a: 255 // Red text
);
// Update later
text.SetMessage("ROUND 2");
// Clean up
text.Remove();
See World Text API.
Targeting Players
All Players
NetMessages.Send(msg, RecipientFilter.All);
Single Player
NetMessages.Send(msg, RecipientFilter.Single(slot));
Custom Selection
var filter = new RecipientFilter();
foreach (var controller in Players.GetAll())
{
if (IsEligible(controller))
filter.Add(controller.EntityIndex);
}
NetMessages.Send(msg, filter);
By Team
var filter = new RecipientFilter();
foreach (var controller in Players.GetAll())
{
var pawn = controller.GetHeroPawn();
if (pawn?.TeamNum == 2) // Team 0
filter.Add(controller.EntityIndex);
}
NetMessages.Send(msg, filter);
See Also
- Networking API — Full message sending reference
- World Text API — 3D text panels
- Players API — Player enumeration
- Deathmatch Example — Chat rebroadcasting