Skip to content

Commit a8a5138

Browse files
committed
refactor(chat): use FETCH_OR_SUBSTITUTE_FORMAT localized chat formats for team/global messages in ConnectionManager::processChat - Use CHAT:TeamFormat and CHAT:GlobalFormat via FETCH_OR_SUBSTITUTE_FORMAT - Keep team detection with isTeamChat helper - Applied to both GeneralsMD and Generals versions
1 parent 5626ae0 commit a8a5138

File tree

2 files changed

+154
-110
lines changed

2 files changed

+154
-110
lines changed

Generals/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp

Lines changed: 82 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -631,76 +631,89 @@ void ConnectionManager::processChat(NetChatCommandMsg *msg)
631631
}
632632

633633
// =============================================================
634-
// ConnectionManager::processChat()
635-
// Refactored by TheSuperHackers @feature - 31/10/2025
636-
// Simplified team chat detection, clean formatting logic.
637-
// =============================================================
634+
// ConnectionManager::processChat()
635+
// Refactored by TheSuperHackers @feature - 31/10/2025
636+
// Simplified team chat detection + localizable format via FETCH_OR_SUBSTITUTE_FORMAT()
637+
// =============================================================
638638

639-
static Bool isTeamChat(const Player* sender, UInt32 mask)
640-
{
641-
Int allies = 0;
642-
Int recipients = 0;
643-
644-
for (Int i = 0; i < MAX_SLOTS; ++i)
645-
{
646-
if ((1 << i) & mask)
647-
{
648-
const Player* receiver = ThePlayerList->getConstSlot(i);
649-
if (receiver && receiver->isPlayerActive())
650-
{
651-
recipients++;
652-
if (sender->getRelationship(receiver->getDefaultTeam()) == ALLIES)
653-
allies++;
654-
}
655-
}
656-
}
657-
658-
// Team message if all recipients are allies and at least one exists
659-
return (recipients > 0 && recipients == allies);
660-
}
661-
662-
void ConnectionManager::processChat(Int playerID, ChatMessage* msg)
663-
{
664-
const Player* player = ThePlayerList->getConstSlot(playerID);
665-
if (!player) return;
666-
667-
const Player* localPlayer = ThePlayerList->getLocalPlayer();
668-
Bool fromObserver = !player->isPlayerActive();
669-
670-
UnicodeString name(player->getDisplayName());
671-
UnicodeString unitext;
672-
673-
// Determine whether this is a team message
674-
Bool isTeamMessage = FALSE;
675-
if (player->isPlayerActive())
676-
{
677-
isTeamMessage = isTeamChat(player, msg->getPlayerMask());
678-
}
679-
680-
// Format the message string
681-
if (isTeamMessage)
682-
{
683-
// Format: (TEAM) [Player Name] Message
684-
UnicodeString teamPrefix = TheGameText->FETCH_OR_SUBSTITUTE("GUI:Team", L"TEAM");
685-
unitext.format(L"(%ls) [%ls] %ls", teamPrefix.str(), name.str(), msg->getText().str());
686-
}
687-
else
688-
{
689-
// Format: [Player Name] Message (no prefix for global/observer chat)
690-
unitext.format(L"[%ls] %ls", name.str(), msg->getText().str());
691-
}
692-
693-
// DEBUG_LOG(("ConnectionManager::processChat - got message from player %d (mask %8.8X), message is %ls",
694-
// playerID, msg->getPlayerMask(), unitext.str()));
695-
696-
Bool amIObserver = !localPlayer->isPlayerActive();
697-
Bool canSeeChat = (amIObserver || !fromObserver) && !TheGameInfo->getConstSlot(playerID)->isMuted();
698-
699-
if (((1 << m_localSlot) & msg->getPlayerMask()) && canSeeChat)
700-
{
701-
TheInGameUI->message(UnicodeString(L"%ls"), unitext.str());
702-
}
703-
}
639+
static Bool isTeamChat(const Player* sender, UInt32 mask)
640+
{
641+
Int allies = 0;
642+
Int recipients = 0;
643+
644+
for (Int i = 0; i < MAX_SLOTS; ++i)
645+
{
646+
if ((1 << i) & mask)
647+
{
648+
const Player* receiver = ThePlayerList->getConstSlot(i);
649+
if (receiver && receiver->isPlayerActive())
650+
{
651+
recipients++;
652+
if (sender->getRelationship(receiver->getDefaultTeam()) == ALLIES)
653+
allies++;
654+
}
655+
}
656+
}
657+
658+
// Team message if all recipients are allies and at least one exists
659+
return (recipients > 0 && recipients == allies);
660+
}
661+
662+
void ConnectionManager::processChat(Int playerID, ChatMessage* msg)
663+
{
664+
const Player* player = ThePlayerList->getConstSlot(playerID);
665+
if (!player) return;
666+
667+
const Player* localPlayer = ThePlayerList->getLocalPlayer();
668+
Bool fromObserver = !player->isPlayerActive();
669+
670+
UnicodeString name(player->getDisplayName());
671+
UnicodeString unitext;
672+
673+
// Determine whether this is a team message
674+
Bool isTeamMessage = FALSE;
675+
if (player->isPlayerActive())
676+
{
677+
isTeamMessage = isTeamChat(player, msg->getPlayerMask());
678+
}
679+
680+
// Use localized formatted strings (via FETCH_OR_SUBSTITUTE_FORMAT)
681+
if (isTeamMessage)
682+
{
683+
// In your .csf file, define:
684+
// CHAT:TeamFormat = (%s) [%s] %s
685+
UnicodeString teamPrefix = TheGameText->FETCH_OR_SUBSTITUTE("GUI:Team", L"TEAM");
686+
unitext = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT(
687+
"CHAT:TeamFormat",
688+
L"(%ls) [%ls] %ls",
689+
teamPrefix.str(),
690+
name.str(),
691+
msg->getText().str()
692+
);
693+
}
694+
else
695+
{
696+
// In your .csf file, define:
697+
// CHAT:GlobalFormat = [%s] %s
698+
unitext = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT(
699+
"CHAT:GlobalFormat",
700+
L"[%ls] %ls",
701+
name.str(),
702+
msg->getText().str()
703+
);
704+
}
705+
706+
// DEBUG_LOG(("ConnectionManager::processChat - got message from player %d (mask %8.8X), message is %ls",
707+
// playerID, msg->getPlayerMask(), unitext.str()));
708+
709+
Bool amIObserver = !localPlayer->isPlayerActive();
710+
Bool canSeeChat = (amIObserver || !fromObserver) && !TheGameInfo->getConstSlot(playerID)->isMuted();
711+
712+
if (((1 << m_localSlot) & msg->getPlayerMask()) && canSeeChat)
713+
{
714+
TheInGameUI->message(UnicodeString(L"%ls"), unitext.str());
715+
}
716+
}
704717
;
705718

706719
if ( ((1<<m_localSlot) & msg->getPlayerMask() ) && canSeeChat )

GeneralsMD/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -630,59 +630,90 @@ void ConnectionManager::processChat(NetChatCommandMsg *msg)
630630
return;
631631
}
632632

633-
// TheSuperHackers @feature TheSuperHackers 31/10/2025 Add team chat prefix to distinguish from global messages
634-
// Global chat has no prefix (default), team messages are prefixed with (TEAM)
635-
Bool isTeamMessage = FALSE;
636-
Bool fromObserver = !player->isPlayerActive();
637-
const Player *localPlayer = ThePlayerList->getLocalPlayer();
638-
639-
if (player->isPlayerActive())
633+
// =============================================================
634+
// ConnectionManager::processChat()
635+
// Refactored by TheSuperHackers @feature - 31/10/2025
636+
// Simplified team chat detection + localizable format via FETCH_OR_SUBSTITUTE_FORMAT()
637+
// =============================================================
638+
639+
static Bool isTeamChat(const Player* sender, UInt32 mask)
640640
{
641-
// Count how many active (non-observer) players receive this message
642-
Int activePlayers = 0;
643-
Int alliesCount = 0;
644-
641+
Int allies = 0;
642+
Int recipients = 0;
643+
645644
for (Int i = 0; i < MAX_SLOTS; ++i)
646645
{
647-
if ((1 << i) & msg->getPlayerMask())
646+
if ((1 << i) & mask)
648647
{
649-
AsciiString checkPlayerName;
650-
checkPlayerName.format("player%d", i);
651-
const Player *checkPlayer = ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(checkPlayerName));
652-
653-
if (checkPlayer && checkPlayer->isPlayerActive())
648+
const Player* receiver = ThePlayerList->getConstSlot(i);
649+
if (receiver && receiver->isPlayerActive())
654650
{
655-
activePlayers++;
656-
657-
// Check if this recipient is an ally of the sender
658-
if (player->getRelationship(checkPlayer->getDefaultTeam()) == ALLIES &&
659-
checkPlayer->getRelationship(player->getDefaultTeam()) == ALLIES)
660-
{
661-
alliesCount++;
662-
}
651+
recipients++;
652+
if (sender->getRelationship(receiver->getDefaultTeam()) == ALLIES)
653+
allies++;
663654
}
664655
}
665656
}
666-
667-
// Team message: sent to allies only (not to all active players)
668-
isTeamMessage = (activePlayers == alliesCount && alliesCount > 0);
669-
}
670657

671-
if (isTeamMessage)
672-
{
673-
// Format: (TEAM) [Player Name] Message
674-
UnicodeString teamPrefix = TheGameText->FETCH_OR_SUBSTITUTE("GUI:Team", L"TEAM");
675-
unitext.format(L"(%ls) [%ls] %ls", teamPrefix.str(), name.str(), msg->getText().str());
658+
// Team message if all recipients are allies and at least one exists
659+
return (recipients > 0 && recipients == allies);
676660
}
677-
else
661+
662+
void ConnectionManager::processChat(Int playerID, ChatMessage* msg)
678663
{
679-
// Format: [Player Name] Message (no prefix for global/observer chat)
680-
unitext.format(L"[%ls] %ls", name.str(), msg->getText().str());
681-
}
682-
// DEBUG_LOG(("ConnectionManager::processChat - got message from player %d (mask %8.8X), message is %ls", playerID, msg->getPlayerMask(), unitext.str()));
664+
const Player* player = ThePlayerList->getConstSlot(playerID);
665+
if (!player) return;
666+
667+
const Player* localPlayer = ThePlayerList->getLocalPlayer();
668+
Bool fromObserver = !player->isPlayerActive();
683669

684-
Bool amIObserver = !localPlayer->isPlayerActive();
685-
Bool canSeeChat = (amIObserver || !fromObserver) && !TheGameInfo->getConstSlot(playerID)->isMuted();
670+
UnicodeString name(player->getDisplayName());
671+
UnicodeString unitext;
672+
673+
// Determine whether this is a team message
674+
Bool isTeamMessage = FALSE;
675+
if (player->isPlayerActive())
676+
{
677+
isTeamMessage = isTeamChat(player, msg->getPlayerMask());
678+
}
679+
680+
// Use localized formatted strings (via FETCH_OR_SUBSTITUTE_FORMAT)
681+
if (isTeamMessage)
682+
{
683+
// In your .csf file, define:
684+
// CHAT:TeamFormat = (%s) [%s] %s
685+
UnicodeString teamPrefix = TheGameText->FETCH_OR_SUBSTITUTE("GUI:Team", L"TEAM");
686+
unitext = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT(
687+
"CHAT:TeamFormat",
688+
L"(%ls) [%ls] %ls",
689+
teamPrefix.str(),
690+
name.str(),
691+
msg->getText().str()
692+
);
693+
}
694+
else
695+
{
696+
// In your .csf file, define:
697+
// CHAT:GlobalFormat = [%s] %s
698+
unitext = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT(
699+
"CHAT:GlobalFormat",
700+
L"[%ls] %ls",
701+
name.str(),
702+
msg->getText().str()
703+
);
704+
}
705+
706+
// DEBUG_LOG(("ConnectionManager::processChat - got message from player %d (mask %8.8X), message is %ls",
707+
// playerID, msg->getPlayerMask(), unitext.str()));
708+
709+
Bool amIObserver = !localPlayer->isPlayerActive();
710+
Bool canSeeChat = (amIObserver || !fromObserver) && !TheGameInfo->getConstSlot(playerID)->isMuted();
711+
712+
if (((1 << m_localSlot) & msg->getPlayerMask()) && canSeeChat)
713+
{
714+
TheInGameUI->message(UnicodeString(L"%ls"), unitext.str());
715+
}
716+
}
686717

687718
if ( ((1<<m_localSlot) & msg->getPlayerMask() ) && canSeeChat )
688719
{

0 commit comments

Comments
 (0)