InGameChat.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: InGameChat.cpp ///////////////////////////////////////////////////////////////////////
  24. // Author: Matthew D. Campbell - June 2002
  25. // Desc: GUI callbacks for the in-game chat entry
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/Player.h"
  30. #include "Common/PlayerList.h"
  31. #include "GameClient/DisconnectMenu.h"
  32. #include "GameClient/GameWindow.h"
  33. #include "GameClient/Gadget.h"
  34. #include "GameClient/GadgetTextEntry.h"
  35. #include "GameClient/GadgetStaticText.h"
  36. #include "GameClient/GameClient.h"
  37. #include "GameClient/GameText.h"
  38. #include "GameClient/GUICallbacks.h"
  39. #include "GameClient/InGameUI.h"
  40. #include "GameClient/LanguageFilter.h"
  41. #include "GameLogic/GameLogic.h"
  42. #include "GameNetwork/GameInfo.h"
  43. #include "GameNetwork/NetworkInterface.h"
  44. static GameWindow *chatWindow = NULL;
  45. static GameWindow *chatTextEntry = NULL;
  46. static GameWindow *chatTypeStaticText = NULL;
  47. static UnicodeString s_savedChat;
  48. static InGameChatType inGameChatType;
  49. // ------------------------------------------------------------------------------------------------
  50. // ------------------------------------------------------------------------------------------------
  51. void ShowInGameChat( Bool immediate )
  52. {
  53. #if !defined(_PLAYTEST)
  54. if (TheGameLogic->isInReplayGame())
  55. return;
  56. #endif
  57. if (TheInGameUI->isQuitMenuVisible())
  58. return;
  59. if (TheDisconnectMenu && TheDisconnectMenu->isScreenVisible())
  60. return;
  61. if (chatWindow)
  62. {
  63. chatWindow->winHide(FALSE);
  64. chatWindow->winEnable(TRUE);
  65. chatTextEntry->winHide(FALSE);
  66. chatTextEntry->winEnable(TRUE);
  67. GadgetTextEntrySetText( chatTextEntry, s_savedChat );
  68. s_savedChat.clear();
  69. }
  70. else
  71. {
  72. chatWindow = TheWindowManager->winCreateFromScript( AsciiString("InGameChat.wnd") );
  73. static NameKeyType textEntryChatID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:TextEntryChat" );
  74. chatTextEntry = TheWindowManager->winGetWindowFromId( NULL, textEntryChatID );
  75. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  76. static NameKeyType chatTypeStaticTextID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:StaticTextChatType" );
  77. chatTypeStaticText = TheWindowManager->winGetWindowFromId( NULL, chatTypeStaticTextID );
  78. }
  79. TheWindowManager->winSetFocus( chatTextEntry );
  80. SetInGameChatType( INGAME_CHAT_EVERYONE );
  81. }
  82. // ------------------------------------------------------------------------------------------------
  83. // ------------------------------------------------------------------------------------------------
  84. void ResetInGameChat( void )
  85. {
  86. if(chatWindow)
  87. TheWindowManager->winDestroy( chatWindow );
  88. chatWindow = NULL;
  89. chatTextEntry = NULL;
  90. chatTypeStaticText = NULL;
  91. s_savedChat.clear();
  92. }
  93. // ------------------------------------------------------------------------------------------------
  94. // ------------------------------------------------------------------------------------------------
  95. void HideInGameChat( Bool immediate )
  96. {
  97. if (chatWindow)
  98. {
  99. s_savedChat = GadgetTextEntryGetText( chatTextEntry );
  100. chatWindow->winHide(TRUE);
  101. chatWindow->winEnable(FALSE);
  102. chatTextEntry->winHide(TRUE);
  103. chatTextEntry->winEnable(FALSE);
  104. TheWindowManager->winSetFocus( NULL );
  105. }
  106. TheWindowManager->winSetFocus( NULL );
  107. }
  108. // ------------------------------------------------------------------------------------------------
  109. // ------------------------------------------------------------------------------------------------
  110. void SetInGameChatType( InGameChatType chatType )
  111. {
  112. inGameChatType = chatType;
  113. if (chatTypeStaticText)
  114. {
  115. switch (inGameChatType)
  116. {
  117. case INGAME_CHAT_EVERYONE:
  118. if (ThePlayerList->getLocalPlayer()->isPlayerActive())
  119. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Everyone") );
  120. else
  121. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Observers") );
  122. break;
  123. case INGAME_CHAT_ALLIES:
  124. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Allies") );
  125. break;
  126. case INGAME_CHAT_PLAYERS:
  127. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Players") );
  128. break;
  129. }
  130. }
  131. }
  132. // ------------------------------------------------------------------------------------------------
  133. // ------------------------------------------------------------------------------------------------
  134. Bool IsInGameChatActive() {
  135. if (chatWindow != NULL) {
  136. if (chatWindow->winIsHidden() == FALSE) {
  137. return TRUE;
  138. }
  139. }
  140. return FALSE;
  141. }
  142. // Slash commands -------------------------------------------------------------------------
  143. extern "C" {
  144. int getQR2HostingStatus(void);
  145. }
  146. extern int isThreadHosting;
  147. Bool handleInGameSlashCommands(UnicodeString uText)
  148. {
  149. AsciiString message;
  150. message.translate(uText);
  151. if (message.getCharAt(0) != '/')
  152. {
  153. return FALSE; // not a slash command
  154. }
  155. AsciiString remainder = message.str() + 1;
  156. AsciiString token;
  157. remainder.nextToken(&token);
  158. token.toLower();
  159. if (token == "host")
  160. {
  161. UnicodeString s;
  162. s.format(L"Hosting qr2:%d thread:%d", getQR2HostingStatus(), isThreadHosting);
  163. TheInGameUI->message(s);
  164. return TRUE; // was a slash command
  165. }
  166. return FALSE; // not a slash command
  167. }
  168. // ------------------------------------------------------------------------------------------------
  169. // ------------------------------------------------------------------------------------------------
  170. void ToggleInGameChat( Bool immediate )
  171. {
  172. static Bool justHid = false;
  173. if (justHid)
  174. {
  175. justHid = false;
  176. return;
  177. }
  178. #if !defined(_PLAYTEST)
  179. if (TheGameLogic->isInReplayGame())
  180. return;
  181. #endif
  182. if (!TheGameInfo->isMultiPlayer() && TheGlobalData->m_netMinPlayers)
  183. return;
  184. if (chatWindow)
  185. {
  186. Bool show = chatWindow->winIsHidden();
  187. if (show)
  188. ShowInGameChat( immediate );
  189. else
  190. {
  191. if (chatTextEntry)
  192. {
  193. // Send what is there, clear it out, and hide the window
  194. UnicodeString msg = GadgetTextEntryGetText( chatTextEntry );
  195. msg.trim();
  196. if (!msg.isEmpty() && !handleInGameSlashCommands(msg))
  197. {
  198. const Player *localPlayer = ThePlayerList->getLocalPlayer();
  199. AsciiString playerName;
  200. Int playerMask = 0;
  201. for (Int i=0; i<MAX_SLOTS; ++i)
  202. {
  203. playerName.format("player%d", i);
  204. const Player *player = ThePlayerList->findPlayerWithNameKey( TheNameKeyGenerator->nameToKey( playerName ) );
  205. if (player && localPlayer)
  206. {
  207. switch (inGameChatType)
  208. {
  209. case INGAME_CHAT_EVERYONE:
  210. if (!TheGameInfo->getConstSlot(i)->isMuted())
  211. playerMask |= (1<<i);
  212. break;
  213. case INGAME_CHAT_ALLIES:
  214. if ( (player->getRelationship(localPlayer->getDefaultTeam()) == ALLIES &&
  215. localPlayer->getRelationship(player->getDefaultTeam()) == ALLIES) || player==localPlayer )
  216. playerMask |= (1<<i);
  217. break;
  218. case INGAME_CHAT_PLAYERS:
  219. if ( player == localPlayer )
  220. playerMask |= (1<<i);
  221. break;
  222. }
  223. }
  224. }
  225. TheLanguageFilter->filterLine(msg);
  226. TheNetwork->sendChat(msg, playerMask);
  227. }
  228. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  229. HideInGameChat( immediate );
  230. justHid = true;
  231. }
  232. }
  233. }
  234. else
  235. {
  236. ShowInGameChat( immediate );
  237. }
  238. }
  239. //-------------------------------------------------------------------------------------------------
  240. //-------------------------------------------------------------------------------------------------
  241. WindowMsgHandledType InGameChatInput( GameWindow *window, UnsignedInt msg,
  242. WindowMsgData mData1, WindowMsgData mData2 )
  243. {
  244. switch( msg )
  245. {
  246. // --------------------------------------------------------------------------------------------
  247. case GWM_CHAR:
  248. {
  249. UnsignedByte key = mData1;
  250. // UnsignedByte state = mData2;
  251. switch( key )
  252. {
  253. // ----------------------------------------------------------------------------------------
  254. case KEY_ESC:
  255. {
  256. HideInGameChat();
  257. return MSG_HANDLED;
  258. //return MSG_IGNORED;
  259. } // end escape
  260. } // end switch( key )
  261. return MSG_HANDLED;
  262. } // end char
  263. }
  264. return MSG_IGNORED;
  265. } // end InGameChatInput
  266. //-------------------------------------------------------------------------------------------------
  267. //-------------------------------------------------------------------------------------------------
  268. WindowMsgHandledType InGameChatSystem( GameWindow *window, UnsignedInt msg,
  269. WindowMsgData mData1, WindowMsgData mData2 )
  270. {
  271. switch( msg )
  272. {
  273. //---------------------------------------------------------------------------------------------
  274. case GGM_FOCUS_CHANGE:
  275. {
  276. // Bool focus = (Bool) mData1;
  277. //if (focus)
  278. //TheWindowManager->winSetGrabWindow( chatTextEntry );
  279. break;
  280. } // end focus change
  281. //---------------------------------------------------------------------------------------------
  282. case GWM_INPUT_FOCUS:
  283. {
  284. // if we're givin the opportunity to take the keyboard focus we must say we want it
  285. if( mData1 == TRUE )
  286. *(Bool *)mData2 = TRUE;
  287. return MSG_HANDLED;
  288. }//case GWM_INPUT_FOCUS:
  289. //---------------------------------------------------------------------------------------------
  290. case GEM_EDIT_DONE:
  291. {
  292. ToggleInGameChat();
  293. //HideInGameChat();
  294. break;
  295. } // end button selected
  296. //---------------------------------------------------------------------------------------------
  297. case GBM_SELECTED:
  298. {
  299. GameWindow *control = (GameWindow *)mData1;
  300. static NameKeyType buttonClearID = TheNameKeyGenerator->nameToKey( AsciiString( "InGameChat.wnd:ButtonClear" ) );
  301. if (control && control->winGetWindowId() == buttonClearID)
  302. {
  303. if (chatTextEntry)
  304. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  305. s_savedChat.clear();
  306. }
  307. break;
  308. } // end button selected
  309. //---------------------------------------------------------------------------------------------
  310. default:
  311. return MSG_IGNORED;
  312. } // end switch( msg )
  313. return MSG_HANDLED;
  314. } // end InGameChatSystem