InGameChat.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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 (TheGameLogic->isInReplayGame())
  54. return;
  55. if (TheInGameUI->isQuitMenuVisible())
  56. return;
  57. if (TheDisconnectMenu && TheDisconnectMenu->isScreenVisible())
  58. return;
  59. if (chatWindow)
  60. {
  61. chatWindow->winHide(FALSE);
  62. chatWindow->winEnable(TRUE);
  63. chatTextEntry->winHide(FALSE);
  64. chatTextEntry->winEnable(TRUE);
  65. GadgetTextEntrySetText( chatTextEntry, s_savedChat );
  66. s_savedChat.clear();
  67. }
  68. else
  69. {
  70. chatWindow = TheWindowManager->winCreateFromScript( AsciiString("InGameChat.wnd") );
  71. static NameKeyType textEntryChatID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:TextEntryChat" );
  72. chatTextEntry = TheWindowManager->winGetWindowFromId( NULL, textEntryChatID );
  73. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  74. static NameKeyType chatTypeStaticTextID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:StaticTextChatType" );
  75. chatTypeStaticText = TheWindowManager->winGetWindowFromId( NULL, chatTypeStaticTextID );
  76. }
  77. TheWindowManager->winSetFocus( chatTextEntry );
  78. SetInGameChatType( INGAME_CHAT_EVERYONE );
  79. }
  80. // ------------------------------------------------------------------------------------------------
  81. // ------------------------------------------------------------------------------------------------
  82. void ResetInGameChat( void )
  83. {
  84. if(chatWindow)
  85. TheWindowManager->winDestroy( chatWindow );
  86. chatWindow = NULL;
  87. chatTextEntry = NULL;
  88. chatTypeStaticText = NULL;
  89. s_savedChat.clear();
  90. }
  91. // ------------------------------------------------------------------------------------------------
  92. // ------------------------------------------------------------------------------------------------
  93. void HideInGameChat( Bool immediate )
  94. {
  95. if (chatWindow)
  96. {
  97. s_savedChat = GadgetTextEntryGetText( chatTextEntry );
  98. chatWindow->winHide(TRUE);
  99. chatWindow->winEnable(FALSE);
  100. chatTextEntry->winHide(TRUE);
  101. chatTextEntry->winEnable(FALSE);
  102. TheWindowManager->winSetFocus( NULL );
  103. }
  104. TheWindowManager->winSetFocus( NULL );
  105. }
  106. // ------------------------------------------------------------------------------------------------
  107. // ------------------------------------------------------------------------------------------------
  108. void SetInGameChatType( InGameChatType chatType )
  109. {
  110. inGameChatType = chatType;
  111. if (chatTypeStaticText)
  112. {
  113. switch (inGameChatType)
  114. {
  115. case INGAME_CHAT_EVERYONE:
  116. if (ThePlayerList->getLocalPlayer()->isPlayerActive())
  117. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Everyone") );
  118. else
  119. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Observers") );
  120. break;
  121. case INGAME_CHAT_ALLIES:
  122. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Allies") );
  123. break;
  124. case INGAME_CHAT_PLAYERS:
  125. GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Players") );
  126. break;
  127. }
  128. }
  129. }
  130. // ------------------------------------------------------------------------------------------------
  131. // ------------------------------------------------------------------------------------------------
  132. Bool IsInGameChatActive() {
  133. if (chatWindow != NULL) {
  134. if (chatWindow->winIsHidden() == FALSE) {
  135. return TRUE;
  136. }
  137. }
  138. return FALSE;
  139. }
  140. // Slash commands -------------------------------------------------------------------------
  141. extern "C" {
  142. int getQR2HostingStatus(void);
  143. }
  144. extern int isThreadHosting;
  145. Bool handleInGameSlashCommands(UnicodeString uText)
  146. {
  147. AsciiString message;
  148. message.translate(uText);
  149. if (message.getCharAt(0) != '/')
  150. {
  151. return FALSE; // not a slash command
  152. }
  153. AsciiString remainder = message.str() + 1;
  154. AsciiString token;
  155. remainder.nextToken(&token);
  156. token.toLower();
  157. if (token == "host")
  158. {
  159. UnicodeString s;
  160. s.format(L"Hosting qr2:%d thread:%d", getQR2HostingStatus(), isThreadHosting);
  161. TheInGameUI->message(s);
  162. return TRUE; // was a slash command
  163. }
  164. return FALSE; // not a slash command
  165. }
  166. // ------------------------------------------------------------------------------------------------
  167. // ------------------------------------------------------------------------------------------------
  168. void ToggleInGameChat( Bool immediate )
  169. {
  170. static Bool justHid = false;
  171. if (justHid)
  172. {
  173. justHid = false;
  174. return;
  175. }
  176. if (TheGameLogic->isInReplayGame())
  177. return;
  178. if (!TheGameInfo->isMultiPlayer() && TheGlobalData->m_netMinPlayers)
  179. return;
  180. if (chatWindow)
  181. {
  182. Bool show = chatWindow->winIsHidden();
  183. if (show)
  184. ShowInGameChat( immediate );
  185. else
  186. {
  187. if (chatTextEntry)
  188. {
  189. // Send what is there, clear it out, and hide the window
  190. UnicodeString msg = GadgetTextEntryGetText( chatTextEntry );
  191. msg.trim();
  192. if (!msg.isEmpty() && !handleInGameSlashCommands(msg))
  193. {
  194. const Player *localPlayer = ThePlayerList->getLocalPlayer();
  195. AsciiString playerName;
  196. Int playerMask = 0;
  197. for (Int i=0; i<MAX_SLOTS; ++i)
  198. {
  199. playerName.format("player%d", i);
  200. const Player *player = ThePlayerList->findPlayerWithNameKey( TheNameKeyGenerator->nameToKey( playerName ) );
  201. if (player && localPlayer)
  202. {
  203. switch (inGameChatType)
  204. {
  205. case INGAME_CHAT_EVERYONE:
  206. if (!TheGameInfo->getConstSlot(i)->isMuted())
  207. playerMask |= (1<<i);
  208. break;
  209. case INGAME_CHAT_ALLIES:
  210. if ( (player->getRelationship(localPlayer->getDefaultTeam()) == ALLIES &&
  211. localPlayer->getRelationship(player->getDefaultTeam()) == ALLIES) || player==localPlayer )
  212. playerMask |= (1<<i);
  213. break;
  214. case INGAME_CHAT_PLAYERS:
  215. if ( player == localPlayer )
  216. playerMask |= (1<<i);
  217. break;
  218. }
  219. }
  220. }
  221. TheLanguageFilter->filterLine(msg);
  222. TheNetwork->sendChat(msg, playerMask);
  223. }
  224. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  225. HideInGameChat( immediate );
  226. justHid = true;
  227. }
  228. }
  229. }
  230. else
  231. {
  232. ShowInGameChat( immediate );
  233. }
  234. }
  235. //-------------------------------------------------------------------------------------------------
  236. //-------------------------------------------------------------------------------------------------
  237. WindowMsgHandledType InGameChatInput( GameWindow *window, UnsignedInt msg,
  238. WindowMsgData mData1, WindowMsgData mData2 )
  239. {
  240. switch( msg )
  241. {
  242. // --------------------------------------------------------------------------------------------
  243. case GWM_CHAR:
  244. {
  245. UnsignedByte key = mData1;
  246. // UnsignedByte state = mData2;
  247. switch( key )
  248. {
  249. // ----------------------------------------------------------------------------------------
  250. case KEY_ESC:
  251. {
  252. HideInGameChat();
  253. return MSG_HANDLED;
  254. //return MSG_IGNORED;
  255. } // end escape
  256. } // end switch( key )
  257. return MSG_HANDLED;
  258. } // end char
  259. }
  260. return MSG_IGNORED;
  261. } // end InGameChatInput
  262. //-------------------------------------------------------------------------------------------------
  263. //-------------------------------------------------------------------------------------------------
  264. WindowMsgHandledType InGameChatSystem( GameWindow *window, UnsignedInt msg,
  265. WindowMsgData mData1, WindowMsgData mData2 )
  266. {
  267. switch( msg )
  268. {
  269. //---------------------------------------------------------------------------------------------
  270. case GGM_FOCUS_CHANGE:
  271. {
  272. // Bool focus = (Bool) mData1;
  273. //if (focus)
  274. //TheWindowManager->winSetGrabWindow( chatTextEntry );
  275. break;
  276. } // end focus change
  277. //---------------------------------------------------------------------------------------------
  278. case GWM_INPUT_FOCUS:
  279. {
  280. // if we're givin the opportunity to take the keyboard focus we must say we want it
  281. if( mData1 == TRUE )
  282. *(Bool *)mData2 = TRUE;
  283. return MSG_HANDLED;
  284. }//case GWM_INPUT_FOCUS:
  285. //---------------------------------------------------------------------------------------------
  286. case GEM_EDIT_DONE:
  287. {
  288. ToggleInGameChat();
  289. //HideInGameChat();
  290. break;
  291. } // end button selected
  292. //---------------------------------------------------------------------------------------------
  293. case GBM_SELECTED:
  294. {
  295. GameWindow *control = (GameWindow *)mData1;
  296. static NameKeyType buttonClearID = TheNameKeyGenerator->nameToKey( AsciiString( "InGameChat.wnd:ButtonClear" ) );
  297. if (control && control->winGetWindowId() == buttonClearID)
  298. {
  299. if (chatTextEntry)
  300. GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
  301. s_savedChat.clear();
  302. }
  303. break;
  304. } // end button selected
  305. //---------------------------------------------------------------------------------------------
  306. default:
  307. return MSG_IGNORED;
  308. } // end switch( msg )
  309. return MSG_HANDLED;
  310. } // end InGameChatSystem