Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / people_interraction.cpp
blob0128791a28e8ce68d801280a971d0324702592db
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "stdpch.h"
24 // client
25 #include "../string_manager_client.h"
26 #include "people_interraction.h"
27 #include "nel/gui/interface_expr.h"
28 #include "interface_manager.h"
29 #include "nel/gui/action_handler.h"
30 #include "action_handler_misc.h"
31 #include "chat_window.h"
32 #include "../entity_animation_manager.h"
33 #include "nel/gui/group_editbox.h"
34 #include "nel/gui/group_menu.h"
35 #include "../client_chat_manager.h"
36 #include "../string_manager_client.h"
37 #include "nel/gui/interface_expr.h"
38 #include "nel/gui/ctrl_button.h"
39 #include "nel/gui/ctrl_text_button.h"
40 #include "filtered_chat_summary.h"
41 #include "input_handler_manager.h"
42 #include "../user_entity.h"
43 #include "../entities.h"
44 #include "../net_manager.h"
45 #include "../connection.h"
46 #include "nel/gui/group_tab.h"
47 #include "guild_manager.h"
48 // Game share
49 #include "game_share/entity_types.h"
50 // NeL
51 #include <nel/misc/command.h>
52 #include <nel/misc/rgba.h>
53 #include <nel/misc/i18n.h>
55 #include <string>
57 #include "../misc.h"
59 using namespace NLMISC;
60 using namespace std;
64 ////////////
65 // EXTERN //
66 ////////////
68 extern CEntityAnimationManager *EAM;
69 extern CClientChatManager ChatMngr;
70 extern NLMISC::CLog g_log;
72 /////////////
73 // GLOBALS //
74 /////////////
76 CPeopleInterraction PeopleInterraction;
79 static const string MAIN_CHAT_SOURCE_MENU = "ui:interface:main_chat_source_menu";
80 static const string USER_CHAT_SOURCE_MENU = "ui:interface:user_chat_source_menu";
81 static const string STD_CHAT_SOURCE_MENU = "ui:interface:std_chat_source_menu";
82 static const string NEW_PARTY_CHAT_WINDOW = "ui:interface:create_new_party_chat";
84 NLMISC::CRefPtr<CChatWindow> ChatWindowForFilter;
86 static const sint PARTY_CHAT_SPAWN_DELTA = 20; // to avoid that all party chat appear at the same position, a random value is added
88 //////////////////////////////////
89 // STATIC FUNCTIONs DECLARATION //
90 //////////////////////////////////
92 /** Display an error msg in the system info window, and also in the last window that triggered the command (so that the user is sure to see it)
94 static void displayVisibleSystemMsg(const std::string &msg, const string &cat = "CHK");
97 //////////////////////////////
98 // HANDLER FOR CHAT WINDOWS //
99 //////////////////////////////
101 // handler to manage user entry in party chat windows
103 struct CPartyChatEntryHandler : public IChatWindowListener
105 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
107 if (ClientCfg.Local)
109 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::player, 0);
111 else
113 // TODO GAMEDEV : manage entry in the party chat
120 // handler to manage user entry in 'around me' window
121 struct CAroundMeEntryHandler : public IChatWindowListener
123 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
125 if (ClientCfg.Local)
127 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::arround, 0);
129 else
131 // process msg as usual
132 ChatMngr.setChatMode(CChatGroup::arround);
133 ChatMngr.chat(msg);
138 // handler to manage user entry in 'region' window
139 struct CRegionEntryHandler : public IChatWindowListener
141 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
143 if (ClientCfg.Local)
145 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::region, 0);
147 else
149 // process msg as usual
150 ChatMngr.setChatMode(CChatGroup::region);
151 ChatMngr.chat(msg);
156 // handler to manage user entry in 'universe' window
157 struct CUniverseEntryHandler : public IChatWindowListener
159 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
161 if (ClientCfg.Local)
163 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::universe, 0);
165 else
167 // process msg as usual
168 ChatMngr.setChatMode(CChatGroup::universe);
169 ChatMngr.chat(msg);
174 // handler to manage user entry in 'guild chat' window
175 struct CGuildChatEntryHandler : public IChatWindowListener
177 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
179 if (ClientCfg.Local)
181 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::guild, 0);
183 else
185 ChatMngr.setChatMode(CChatGroup::guild);
186 ChatMngr.chat(msg);
191 // handler to manage user entry in 'team chat' window
192 struct CTeamChatEntryHandler : public IChatWindowListener
194 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
196 if (ClientCfg.Local)
198 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::team, 0);
200 else
202 ChatMngr.setChatMode(CChatGroup::team);
203 ChatMngr.chat(msg, true);
208 // handler to manage user entry in a 'talk with friend' window
209 struct CFriendTalkEntryHandler : public IChatWindowListener
211 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
213 if (ClientCfg.Local)
215 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::player, 0);
217 else
220 // TODO GAMEDEV : send msg to other player
225 // handler to manage user entry in a debug console window
226 struct CDebugConsoleEntryHandler : public IChatWindowListener
228 virtual void msgEntered(const string &msg, CChatWindow * /* chatWindow */)
230 NLMISC::ICommand::execute( msg, g_log );
234 // handler to manager user entry in a Dynamic Chat
235 struct CDynamicChatEntryHandler : public IChatWindowListener
237 public:
238 uint DbIndex;
239 CDynamicChatEntryHandler()
241 DbIndex= 0;
244 virtual void msgEntered(const string &msg, CChatWindow *chatWindow)
246 if (ClientCfg.Local)
248 chatWindow->displayMessage(msg, CRGBA::White, CChatGroup::dyn_chat, DbIndex);
250 else
252 ChatMngr.setChatMode(CChatGroup::dyn_chat, ChatMngr.getDynamicChannelIdFromDbIndex(DbIndex));
253 ChatMngr.chat(msg);
259 // handler instances
260 static CPartyChatEntryHandler PartyChatEntryHandler;
261 static CAroundMeEntryHandler AroundMeEntryHandler;
262 static CRegionEntryHandler RegionEntryHandler;
263 static CUniverseEntryHandler UniverseEntryHandler;
264 static CGuildChatEntryHandler GuildChatEntryHandler;
265 static CTeamChatEntryHandler TeamChatEntryHandler;
266 static CFriendTalkEntryHandler FriendTalkEntryHandler;
267 static CDebugConsoleEntryHandler DebugConsoleEntryHandler;
268 static CDynamicChatEntryHandler DynamicChatEntryHandler[CChatGroup::MaxDynChanPerPlayer];
271 //////////////////////
272 // MEMBER FUNCTIONS //
273 //////////////////////
275 //===========================================================================================================
276 void CChatStdInput::registerListeningWindow(CChatWindow *cw)
278 if (!cw) return;
279 Guild.addListeningWindow(cw);
280 Team.addListeningWindow(cw);
281 Tell.addListeningWindow(cw);
282 AroundMe.addListeningWindow(cw);
283 Region.addListeningWindow(cw);
284 SystemInfo.addListeningWindow(cw);
285 Universe.addListeningWindow(cw);
289 //===========================================================================================================
290 CPeopleInterraction::CPeopleInterraction() : Region(NULL),
291 Universe(NULL),
292 TeamChat(NULL),
293 GuildChat(NULL),
294 SystemInfo(NULL),
295 TellWindow(NULL),
296 DebugInfo(NULL),
297 CurrPartyChatID(0)
299 for(uint i=0;i<CChatGroup::MaxDynChanPerPlayer;i++)
301 DynamicChat[i]= NULL;
306 //===========================================================================================================
307 void CPeopleInterraction::release()
309 ChatInput.Tell.removeListeningPeopleList(&FriendList);
310 ChatInput.Tell.removeListeningPeopleList(&TeamList);
311 ChatInput.Team.removeListeningPeopleList(&TeamList);
313 CChatWindowManager &cwm = getChatWndMgr();
315 AroundMe.release();
316 if (Region) cwm.removeChatWindow(Region);
317 if (Universe) cwm.removeChatWindow(Universe);
318 if (TeamChat) cwm.removeChatWindow(TeamChat);
319 if (GuildChat) cwm.removeChatWindow(GuildChat);
320 if (SystemInfo) cwm.removeChatWindow(SystemInfo);
321 TheUserChat.release();
322 if (DebugInfo) cwm.removeChatWindow(DebugInfo);
323 // if (TellWindow) cwm.removeChatWindow(TellWindow);
324 TeamList.reset();
325 FriendList.reset();
326 IgnoreList.reset();
328 Region = NULL;
329 Universe = NULL;
330 TeamChat = NULL;
331 GuildChat = NULL;
332 SystemInfo = NULL;
333 TellWindow = NULL;
334 DebugInfo = NULL;
335 // TellWindow = NULL;
337 for(uint i=0;i<CChatGroup::MaxDynChanPerPlayer;i++)
339 if(DynamicChat[i]) cwm.removeChatWindow(DynamicChat[i]);
340 DynamicChat[i]= NULL;
343 removeAllPartyChat();
345 ChatGroup.release();
347 for(uint k = 0; k < MaxNumUserChats; ++k)
349 UserChat[k].release();
351 uint numCW = cwm.getNumChatWindow();
352 if (numCW != 0)
354 nlwarning("%d chat windows have not been deleted", (int) numCW);
355 uint numCW = cwm.getNumChatWindow();
356 for(uint k = 0; k < numCW; ++k)
358 nlwarning("Window %d : %s", (int) k, (cwm.getChatWindowByIndex(k)->getTitle()).c_str());
363 //===========================================================================================================
364 void CPeopleInterraction::removeAllPartyChat()
366 CChatWindowManager &cwm = getChatWndMgr();
367 for(std::vector<CPartyChatInfo>::iterator it = PartyChats.begin(); it != PartyChats.end(); ++it)
369 if (it->Window) cwm.removeChatWindow(it->Window);
370 it->Window = NULL;
372 PartyChats.clear();
373 // remove filtered chats
374 //cwm.removeChatWindow(MainChat.Window);
375 //MainChat.Window = NULL;
376 cwm.removeChatWindow(ChatGroup.Window);
377 ChatGroup.Window = NULL;
378 for(uint k = 0; k < MaxNumUserChats; ++k)
380 if (UserChat[k].Window)
382 cwm.removeChatWindow(UserChat[k].Window);
383 UserChat[k].Window = NULL;
389 //===========================================================================================================
390 bool CPeopleInterraction::isUserChat(CChatWindow *cw) const
392 // if (cw == MainChat.Window) return true;
393 if (cw == ChatGroup.Window) return true;
394 for(uint k = 0; k < MaxNumUserChats; ++k)
396 if (UserChat[k].Window == cw) return true;
398 return false;
401 //===========================================================================================================
402 void CPeopleInterraction::init()
404 // create chat windows
405 // todo : internationnalization
406 createAroundMeWindow();
407 createRegionWindow();
408 createUniverseWindow();
409 createTeamChat();
410 createGuildChat();
411 createSystemInfo();
412 createTheUserChat();
413 createDynamicChats();
415 createDebugInfo();
416 //createTellWindow();
418 createTeamList();
419 createFriendList();
420 createIgnoreList();
422 // main chat should be created after other windows, because it relies on them to receive its messages
423 createChatGroup();
425 // init the standard inputs
426 initStdInputs();
430 //===========================================================================================================
431 void CPeopleInterraction::initAfterLoad()
433 /* activate the USER chat per default.
434 Important: we must do it after ChatGroup.Window var init, DB color init etc...
435 because the latest are used in chat_group_filter ActionHandler
437 CChatGroupWindow *pCGW= PeopleInterraction.getChatGroupWindow();
438 if(pCGW)
439 pCGW->setTabIndex(5);
443 //===========================================================================================================
444 void CPeopleInterraction::initStdInputs()
446 uint i;
448 ChatInput.AroundMe.addListeningWindow (ChatGroup.Window);
449 ChatInput.Region.addListeningWindow (ChatGroup.Window);
450 ChatInput.Team.addListeningWindow (ChatGroup.Window);
451 ChatInput.Guild.addListeningWindow (ChatGroup.Window);
452 ChatInput.Tell.addListeningWindow (ChatGroup.Window);
453 ChatInput.SystemInfo.addListeningWindow (ChatGroup.Window);
454 ChatInput.Universe.addListeningWindow (ChatGroup.Window);
456 if (AroundMe.Window)
457 ChatInput.AroundMe.addListeningWindow(AroundMe.Window);
459 if (Region)
460 ChatInput.Region.addListeningWindow(Region);
462 if (Universe)
463 ChatInput.Universe.addListeningWindow(Universe);
465 if (TeamChat)
466 ChatInput.Team.addListeningWindow(TeamChat);
468 if (GuildChat)
469 ChatInput.Guild.addListeningWindow(GuildChat);
471 if (SystemInfo)
472 ChatInput.SystemInfo.addListeningWindow(SystemInfo);
474 if (DebugInfo)
475 ChatInput.DebugInfo.addListeningWindow(DebugInfo);
477 if (TheUserChat.Window)
479 ChatInput.AroundMe.addListeningWindow(TheUserChat.Window);
480 ChatInput.Region.addListeningWindow(TheUserChat.Window);
481 ChatInput.Team.addListeningWindow(TheUserChat.Window);
482 ChatInput.Guild.addListeningWindow(TheUserChat.Window);
483 ChatInput.Universe.addListeningWindow (TheUserChat.Window);
484 // Don't add the system info by default
485 // Dynamic chats
486 for(i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
488 ChatInput.DynamicChat[i].addListeningWindow(TheUserChat.Window);
492 ChatInput.Tell.addListeningPeopleList(&FriendList);
493 ChatInput.Tell.addListeningPeopleList(&TeamList);
494 ChatInput.Team.addListeningPeopleList(&TeamList);
496 // Dynamic chats
497 for(i=0;i<CChatGroup::MaxDynChanPerPlayer;i++)
499 ChatInput.DynamicChat[i].addListeningWindow(ChatGroup.Window);
500 if(DynamicChat[i])
501 ChatInput.DynamicChat[i].addListeningWindow(DynamicChat[i]);
505 //===========================================================================================================
506 void CPeopleInterraction::createTeamList()
508 // temp to test people list before it is connected to the server
509 CPeopleListDesc peopleListDesc;
510 //peopleListDesc.FatherContainer = "ui:interface:communication";
511 peopleListDesc.PeopleListTitle = "uiTeamTitle";
512 peopleListDesc.Id = "team_list";
513 peopleListDesc.ContactType = CPeopleListDesc::Team /* CPeopleListDesc::Contact*/;
514 peopleListDesc.BaseContainerTemplateName = "people_list_container";
515 peopleListDesc.Localize = true;
516 peopleListDesc.Savable = true;
517 peopleListDesc.AHOnActive = "proc";
518 peopleListDesc.AHOnActiveParams = "team_list_proc_active";
519 peopleListDesc.AHOnDeactive = "proc";
520 peopleListDesc.AHOnDeactiveParams = "team_list_proc_deactive";
521 peopleListDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
523 TeamList.create(peopleListDesc, NULL); // &chatDesc // create the team list with a chat box in it
524 TeamList.setMenu("ui:interface:sort_menu");
525 // Special case for team : each entry is connected to the database so we create all team member at once
526 for(uint k = 0; k < MaxNumPeopleInTeam; ++k)
528 TeamList.addPeople(NLMISC::toString(k), k);
531 TeamList.setPeopleMenu("ui:interface:team_member_menu");
532 TeamList.setMenu("ui:interface:team_chat_member_menu");
534 // Open/Close team list when at least one / no team mate
535 // NB: use an intermediate temp var, to avoid show of the window each time a new team member enters
536 string sExpr = "@UI:VARIABLES:IS_TEAM_PRESENT";
537 string sAction = "set";
538 string sCond;
539 string sParams = "target_property=ui:interface:team_list:active|value=@UI:VARIABLES:IS_TEAM_PRESENT";
541 if (TeamChat)
543 CInterfaceLink *il = new CInterfaceLink;
544 vector<CInterfaceLink::CTargetInfo> targets;
545 vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
546 il->init(targets, cdbTargets, sExpr, sAction, sParams, sCond, TeamChat->getContainer());
550 //===========================================================================================================
551 void CPeopleInterraction::createFriendList()
553 // create friend list
554 CPeopleListDesc peopleListDesc;
555 peopleListDesc.FatherContainer = "ui:interface:contact_list";
556 peopleListDesc.PeopleListTitle = "uiFriendList";
557 peopleListDesc.Id = "friend_list";
558 peopleListDesc.BaseContainerTemplateName= "people_list_container_with_add_edit_box";
559 peopleListDesc.ContactType = CPeopleListDesc::Contact;
560 peopleListDesc.Localize = true;
562 FriendList.create(peopleListDesc);
563 FriendList.setPeopleMenuEx("ui:interface:friend_list_menu_offline_unblocked",
564 "ui:interface:friend_list_menu_online_unblocked",
565 "ui:interface:friend_list_menu_online_abroad_unblocked",
566 "ui:interface:friend_list_menu_offline_blocked",
567 "ui:interface:friend_list_menu_online_blocked",
568 "ui:interface:friend_list_menu_online_abroad_blocked"
570 FriendList.setMenu("ui:interface:sort_menu");
574 //===========================================================================================================
575 void CPeopleInterraction::createIgnoreList()
577 // create ignore list
578 CPeopleListDesc peopleListDesc;
579 peopleListDesc.FatherContainer = "ui:interface:contact_list";
580 peopleListDesc.PeopleListTitle = "uiIgnoreList";
581 peopleListDesc.Id = "ignore_list";
582 peopleListDesc.BaseContainerTemplateName = "people_list_container_with_add_edit_box";
583 peopleListDesc.ContactType = CPeopleListDesc::Ignore;
584 peopleListDesc.Localize = true;
586 IgnoreList.create(peopleListDesc);
588 IgnoreList.setPeopleMenu("ui:interface:ignore_list_menu");
589 IgnoreList.setMenu("ui:interface:sort_menu");
592 //===========================================================================================================
593 void CPeopleInterraction::createSystemInfo()
595 CChatWindowDesc chatDesc;
596 chatDesc.FatherContainer = "ui:interface";
597 chatDesc.Title = "uiSystemInfoTitle";
598 chatDesc.Listener = NULL;
599 chatDesc.Savable = true;
600 chatDesc.Localize = true;
601 chatDesc.ChatTemplate ="system_info_id";
602 chatDesc.Id = "system_info";
603 chatDesc.AHOnCloseButton = "proc";
604 chatDesc.AHOnCloseButtonParams = "sysinfo_chat_proc_close";
606 SystemInfo = getChatWndMgr().createChatWindow(chatDesc);
607 if (!SystemInfo) return;
608 SystemInfo->setMenu("ui:interface:base_chat_box_menu");
611 //===========================================================================================================
612 void CPeopleInterraction::createDebugInfo()
614 // can only be used by devs and CSR or in local mode
615 #if FINAL_VERSION
616 if( ClientCfg.Local || hasPrivilegeDEV() || hasPrivilegeSGM() )
617 #endif
619 CChatWindowDesc chatDesc;
620 chatDesc.FatherContainer = "ui:interface";
621 chatDesc.Title = "uiDebugConsole";
622 chatDesc.Listener = NULL;
623 chatDesc.Savable = true;
624 chatDesc.Localize = true;
625 chatDesc.Listener = &DebugConsoleEntryHandler;
626 chatDesc.ChatTemplate ="clearable_chat_id";
627 chatDesc.Id = "debug_info";
629 DebugInfo = getChatWndMgr().createChatWindow(chatDesc);
630 if (!DebugInfo) return;
631 DebugInfo->setMenu("ui:interface:base_chat_box_menu");
635 //===========================================================================================================
636 void CPeopleInterraction::createAroundMeWindow()
638 CChatWindowDesc chatDesc;
639 chatDesc.FatherContainer = "ui:interface";
640 chatDesc.Title = "uiAroundMeTitle";
641 chatDesc.Listener = NULL;
642 chatDesc.Localize = true;
643 chatDesc.Savable = true;
644 //chatDesc.ChatTemplate = "around_me_id";
645 chatDesc.Id = "around_me";
646 chatDesc.AHOnCloseButton = "proc";
647 chatDesc.AHOnCloseButtonParams = "around_me_chat_proc_close";
649 AroundMe.Window = getChatWndMgr().createChatWindow(chatDesc);
650 if (!AroundMe.Window) return;
651 AroundMe.Window->setMenu(STD_CHAT_SOURCE_MENU);
652 // Configure filter for the main chat. By default, it listen to everything (no party chats : none have been created yet)
653 AroundMe.Filter.setTargetGroup(CChatGroup::say);
654 // associate filter with chat window
655 AroundMe.Filter.setChat(AroundMe.Window);
659 //===========================================================================================================
660 void CPeopleInterraction::createRegionWindow()
662 // create region window
663 CChatWindowDesc chatDesc;
664 chatDesc.FatherContainer = "ui:interface";
665 chatDesc.Title = "uiRegionTitle";
666 chatDesc.Listener = &RegionEntryHandler;
667 chatDesc.Localize = true;
668 chatDesc.Savable = true;
669 chatDesc.Id = "region_chat";
670 chatDesc.AHOnCloseButton = "proc";
671 chatDesc.AHOnCloseButtonParams = "region_chat_proc_close";
672 chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
674 Region = getChatWndMgr().createChatWindow(chatDesc);
675 if (!Region) return;
676 Region->setMenu(STD_CHAT_SOURCE_MENU);
680 //===========================================================================================================
681 void CPeopleInterraction::createUniverseWindow()
683 // create universe window
684 CChatWindowDesc chatDesc;
685 chatDesc.FatherContainer = "ui:interface";
686 chatDesc.Title = "uiUniverseTitle";
687 chatDesc.Listener = &UniverseEntryHandler;
688 chatDesc.Localize = true;
689 chatDesc.Savable = true;
690 chatDesc.Id = "universe_chat";
691 chatDesc.AHOnCloseButton = "proc";
692 chatDesc.AHOnCloseButtonParams = "universe_chat_proc_close";
693 chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
695 Universe = getChatWndMgr().createChatWindow(chatDesc);
696 if (!Universe) return;
697 Universe->setMenu(STD_CHAT_SOURCE_MENU);
701 //===========================================================================================================
702 void CPeopleInterraction::createTellWindow()
704 /*CChatWindowDesc chatDesc;
705 chatDesc.FatherContainer = "ui:interface";
706 chatDesc.Title = "uiTellWindow";
707 chatDesc.Listener = NULL;
708 chatDesc.Savable = true;
709 chatDesc.Localize = true;
710 chatDesc.Id = "tell";
711 chatDesc.ChatTemplate ="chat_no_eb_id";
712 chatDesc.AHOnActive = "set";
713 chatDesc.AHOnActiveParams = "dblink=UI:SAVE:ISDETACHED:TELL|value=1";
714 chatDesc.AHOnDeactive = "set";
715 chatDesc.AHOnDeactiveParams = "dblink=UI:SAVE:ISDETACHED:TELL|value=0";
717 TellWindow = getChatWndMgr().createChatWindow(chatDesc);
718 if (!TellWindow) return;
719 TellWindow->setMenu("ui:interface:base_chat_box_menu"); */
722 //===========================================================================================================
723 void CPeopleInterraction::createTeamChat()
725 // create team chat (inserted in team people list)
726 CChatWindowDesc chatDesc;
727 chatDesc.FatherContainer = "ui:interface";
728 chatDesc.Title = "uiTeamChatTitle";
729 chatDesc.Listener = &TeamChatEntryHandler;
730 chatDesc.Localize = true;
731 chatDesc.Savable = true;
732 chatDesc.Id = "team_chat";
733 chatDesc.AHOnCloseButton = "proc";
734 chatDesc.AHOnCloseButtonParams = "team_chat_proc_close";
735 chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
737 TeamChat = getChatWndMgr().createChatWindow(chatDesc);
738 if (!TeamChat) return;
739 TeamChat->setMenu(STD_CHAT_SOURCE_MENU);
742 //===========================================================================================================
743 void CPeopleInterraction::createGuildChat()
745 CChatWindowDesc chatDesc;
746 chatDesc.FatherContainer = "ui:interface";
747 chatDesc.Title = "uiGuildChat";
748 chatDesc.Listener = &GuildChatEntryHandler;
749 chatDesc.Localize = true;
750 chatDesc.Savable = true;
751 chatDesc.Id = "guild_chat";
752 chatDesc.AHOnCloseButton = "proc";
753 chatDesc.AHOnCloseButtonParams = "guild_chat_proc_close";
754 chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
756 GuildChat = getChatWndMgr().createChatWindow(chatDesc);
757 if (!GuildChat) return;
758 GuildChat->setMenu(STD_CHAT_SOURCE_MENU);
761 //=================================================================================================================
762 void CPeopleInterraction::createDynamicChats()
764 for(uint i=0;i<CChatGroup::MaxDynChanPerPlayer;i++)
766 CChatWindowDesc chatDesc;
767 chatDesc.FatherContainer = "ui:interface";
768 chatDesc.Title = toString("dummyDynChatTitle%d",i); // title not used, but still important because create() test uniqueness
769 DynamicChatEntryHandler[i].DbIndex= i;
770 chatDesc.Listener = &DynamicChatEntryHandler[i];
771 chatDesc.Localize = false;
772 chatDesc.Savable = true;
773 chatDesc.ChatTemplate ="dynamic_chat_id";
774 chatDesc.ChatTemplateParams.push_back(make_pair(string("dyn_chat_nb"),toString(i)));
775 chatDesc.Id = string("dynamic_chat") + toString(i);
776 // no active proc because active state is driven by database
777 chatDesc.AHOnCloseButton = "proc";
778 chatDesc.AHOnCloseButtonParams = string("dynamic_chat_proc_close|") + toString(i);
779 chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
781 DynamicChat[i] = getChatWndMgr().createChatWindow(chatDesc);
782 if (!DynamicChat[i]) continue;
783 DynamicChat[i]->setMenu(STD_CHAT_SOURCE_MENU);
788 //=================================================================================================================
789 void CPeopleInterraction::createTheUserChat()
791 CChatWindowDesc chatDesc;
792 chatDesc.FatherContainer = "ui:interface";
793 chatDesc.Title = "uiUserChat";
794 chatDesc.Listener = NULL;
795 chatDesc.Localize = true;
796 chatDesc.Savable = true;
797 chatDesc.Id = "user_chat";
798 chatDesc.ChatTemplate = "filtered_chat_id";
799 chatDesc.AHOnActive = "user_chat_active";
800 chatDesc.AHOnCloseButton = "set";
801 chatDesc.AHOnCloseButtonParams = "dblink=UI:SAVE:ISDETACHED:USER_CHAT|value=0";
803 TheUserChat.Window = getChatWndMgr().createChatWindow(chatDesc);
804 if (!TheUserChat.Window) return;
805 TheUserChat.Window->getContainer()->setup();
806 // Configure filter for the new chat (by default, listen to everything but party chats)
807 TheUserChat.Filter.setTargetGroup(CChatGroup::say);
808 // assoviate filter with chat window
809 TheUserChat.Filter.setChat(TheUserChat.Window);
813 class CHandlerUserChatActive : public IActionHandler
815 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
817 CChatWindow *pCGW = dynamic_cast<CChatWindow*>(PeopleInterraction.TheUserChat.Window);
818 if (pCGW == NULL) return;
819 CCtrlTextButton *pUserBut = dynamic_cast<CCtrlTextButton*>(pCGW->getContainer()->getCtrl("content:target_button"));
820 CInterfaceGroup *pEditBox = dynamic_cast<CInterfaceGroup*>(pCGW->getContainer()->getGroup("content:ebw"));
822 if(!pUserBut)
823 return;
825 CChatGroup::TGroupType m = PeopleInterraction.TheUserChat.Filter.getTargetGroup();
826 switch(m)
828 default:
829 case CChatGroup::arround:
830 case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break;
831 case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break;
832 case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break;
833 case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break;
834 case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break;
836 pUserBut->getParent()->updateCoords();
837 pUserBut->updateCoords();
839 if (pEditBox != NULL) pEditBox->setW(-pUserBut->getWReal()-4);
842 REGISTER_ACTION_HANDLER(CHandlerUserChatActive, "user_chat_active");
844 //===========================================================================================================
845 void CPeopleInterraction::createChatGroup()
847 CChatWindowDesc chatDesc;
848 chatDesc.FatherContainer = "ui:interface";
849 chatDesc.Listener = NULL;
850 chatDesc.Title.clear(); // NB: the chatgroup is the only one that can be not named (because of uniqueness title test)
851 chatDesc.Localize = true;
852 chatDesc.Savable = true;
853 chatDesc.ChatTemplate = "main_chat_group";
854 chatDesc.Id = "main_chat";
855 chatDesc.AHOnActive = "proc";
856 chatDesc.AHOnActiveParams = "main_chat_group_active";
857 chatDesc.AHOnDeactive = "proc";
858 chatDesc.AHOnDeactiveParams = "main_chat_group_deactive";
860 ChatGroup.Window = getChatWndMgr().createChatGroupWindow(chatDesc);
861 if (!ChatGroup.Window) return;
862 // Configure filter for the main chat. By default, it listen to everything (no party chats : none have been created yet)
863 ChatGroup.Filter.setTargetGroup(CChatGroup::say);
864 // associate filter with chat window
865 ChatGroup.Filter.setChat(ChatGroup.Window);
868 class CHandlerChatGroupFilter : public IActionHandler
870 void execute (CCtrlBase *pCaller, const std::string &sParams)
872 CInterfaceManager *pIM= CInterfaceManager::getInstance();
874 const string dynChatId="dyn_chat";
876 bool writeRight= true;
877 bool isDynChat= false;
878 uint32 dynChatDbIndex= 0;
880 // Entry output
881 CChatTargetFilter &rCTF = PeopleInterraction.ChatGroup.Filter;
882 if (sParams == "around") rCTF.setTargetGroup(CChatGroup::say);
883 else if (sParams == "region") rCTF.setTargetGroup(CChatGroup::region);
884 else if (sParams == "universe") rCTF.setTargetGroup(CChatGroup::universe);
885 else if (sParams == "team") rCTF.setTargetGroup(CChatGroup::team);
886 else if (sParams == "guild") rCTF.setTargetGroup(CChatGroup::guild);
887 else if (sParams == "sysinfo")
889 rCTF.setTargetGroup(CChatGroup::system);
890 writeRight= false;
892 else if (sParams.compare(0, dynChatId.size(), dynChatId)==0)
894 // get the number of this tab
895 isDynChat= true;
896 fromString(sParams.substr(dynChatId.size()), dynChatDbIndex);
897 dynChatDbIndex= min(dynChatDbIndex, (uint32)(CChatGroup::MaxDynChanPerPlayer-1));
898 rCTF.setTargetGroup(CChatGroup::dyn_chat, dynChatDbIndex);
901 // inform DB for write right.
902 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MAIN_CHAT:WRITE_RIGHT")->setValue32(writeRight);
903 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MAIN_CHAT:IS_DYN_CHAT")->setValue32(isDynChat);
904 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MAIN_CHAT:INDEX_DYN_CHAT")->setValue32(dynChatDbIndex);
907 // Update Chat Group Window from user chat button
909 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
910 if (!pCGW) return;
911 CCtrlTextButton *pUserBut = dynamic_cast<CCtrlTextButton*>(pCGW->getContainer()->getCtrl("content:but_user"));
912 CCtrlTextButton *pEmoteBut = dynamic_cast<CCtrlTextButton*>(pCGW->getContainer()->getCtrl("content:but_emote"));
913 CInterfaceGroup *pEditBox = dynamic_cast<CInterfaceGroup*>(pCGW->getContainer()->getGroup("content:ebw"));
914 CInterfaceGroup *pTextList = dynamic_cast<CInterfaceGroup*>(pCGW->getContainer()->getGroup("content:cb"));
916 // Target button choose the right filter
919 // Special case of the user defined chat
920 if (sParams == "user")
922 if (pUserBut != NULL)
924 CChatGroup::TGroupType m = PeopleInterraction.TheUserChat.Filter.getTargetGroup();
925 switch(m)
927 default:
928 case CChatGroup::arround:
929 case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break;
930 case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break;
931 case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break;
932 case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break;
933 case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break;
934 case CChatGroup::dyn_chat:
935 uint32 index = PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex();
936 uint32 textId = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:DYN_CHAT:CHANNEL"+toString(index)+":NAME")->getValue32();
937 string title;
938 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
939 if (title.empty())
941 // Dyn channel not available yet, so set to around
942 PeopleInterraction.TheUserChat.Filter.setTargetGroup(CChatGroup::arround);
943 pUserBut->setHardText("uiFilterAround");
945 else
947 pUserBut->setHardText(title);
949 break;
952 pUserBut->setActive(true);
953 pUserBut->getParent()->updateCoords();
954 pUserBut->updateCoords();
956 pEmoteBut->setActive (true);
957 pEmoteBut->updateCoords ();
959 if (pEditBox != NULL)
961 pEditBox->setW(-pUserBut->getWReal()-pEmoteBut->getWReal()-8);
962 pEditBox->setX(pUserBut->getWReal()+4);
967 rCTF.setTargetGroup(PeopleInterraction.TheUserChat.Filter.getTargetGroup(), PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex());
969 else
971 if (pUserBut != NULL) pUserBut->setActive(false);
973 if (pEmoteBut)
975 pEmoteBut->setActive (true);
976 pEmoteBut->updateCoords ();
979 if (pEditBox != NULL)
981 if(pEmoteBut)
982 pEditBox->setW(-pEmoteBut->getWReal()-4);
983 else
984 pEditBox->setW(0);
985 pEditBox->setX(0);
987 if (pTextList != NULL) pTextList->setX(0);
990 // if called from a tab button => force the tab ctrl button to have standard color
991 CCtrlTabButton *pTabButton= dynamic_cast<CCtrlTabButton*>(pCaller);
992 if(pTabButton)
994 CRGBA stdColor= CRGBA::stringToRGBA(CWidgetManager::getInstance()->getParser()->getDefine("chat_group_tab_color_normal").c_str());
995 pTabButton->setTextColorNormal(stdColor);
999 REGISTER_ACTION_HANDLER(CHandlerChatGroupFilter, "chat_group_filter");
1002 //===========================================================================================================
1003 class CHandlerChatGroupUpdatePrompt : public IActionHandler
1005 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
1007 // re set the target group will automatically reset the prompt and prompt color
1008 CChatTargetFilter &rCTF = PeopleInterraction.ChatGroup.Filter;
1009 rCTF.setTargetGroup(rCTF.getTargetGroup(), rCTF.getTargetDynamicChannelDbIndex());
1012 REGISTER_ACTION_HANDLER(CHandlerChatGroupUpdatePrompt, "chat_group_update_prompt");
1015 //===========================================================================================================
1016 CPeopleList *CPeopleInterraction::getPeopleListFromContainerID(const std::string &id)
1018 if (TeamList.getContainerID() == id) return &TeamList;
1019 else if (FriendList.getContainerID() == id) return &FriendList;
1020 else if (IgnoreList.getContainerID() == id) return &IgnoreList;
1021 return NULL;
1025 //===========================================================================================================
1026 bool CPeopleInterraction::getPeopleFromContainerID(const std::string &id, CPeopleList *&peopleList, uint &destIndex)
1028 // get people index
1029 // the name has the form "ui:interface:container_name_people_index"
1030 typedef std::string::size_type TCharPos;
1031 TCharPos index = id.find_last_of("_");
1032 if (index == std::string::npos || index == 0) return false;
1033 TCharPos nextIndex = id.rfind(":", index);
1034 if (nextIndex == std::string::npos) return false;
1035 std::string containerId = id.substr(nextIndex + 1, index - nextIndex - 1);
1036 // search a container with the good name
1037 CPeopleList *pl = getPeopleListFromContainerID(containerId);
1038 if (!pl) return false;
1040 sint peopleIndex = pl->getIndexFromContainerID(id);
1041 if (peopleIndex == -1) return false;
1043 destIndex = (uint) peopleIndex;
1044 peopleList = pl;
1046 return true;
1049 //===========================================================================================================
1050 bool CPeopleInterraction::getPeopleFromCurrentMenu(CPeopleList *&peopleList, uint &index)
1052 CInterfaceManager *im = CInterfaceManager::getInstance();
1053 // the group that launched the modal window (the menu) must be the header of the group container that represent a people entry
1054 CInterfaceGroup *header = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
1055 if (!header) return false;
1056 // get the parent container
1057 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(header->getParent());
1058 if (!gc) return false;
1059 return getPeopleFromContainerID(gc->getId(), peopleList, index);
1062 //===========================================================================================================
1063 CPeopleList *CPeopleInterraction::getPeopleListFromCurrentMenu()
1065 CInterfaceManager *im = CInterfaceManager::getInstance();
1066 // the group that launched the modal window (the menu) must be the header of the group container that represent a people entry
1067 CInterfaceGroup *header = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
1068 if (!header) return NULL;
1069 // get the parent container
1070 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(header->getParent());
1071 if (!gc) return NULL;
1072 std::string::size_type pos = gc->getId().find_last_of(":");
1073 if (pos == std::string::npos) return NULL;
1074 return getPeopleListFromContainerID(gc->getId().substr(pos + 1));
1077 //===========================================================================================================
1078 CFilteredChat *CPeopleInterraction::getFilteredChatFromChatWindow(CChatWindow *cw)
1080 //if (cw == MainChat.Window) return &MainChat;
1081 if (cw == ChatGroup.Window) return &ChatGroup;
1082 if (cw == AroundMe.Window) return &AroundMe;
1083 if (cw == TheUserChat.Window) return &TheUserChat;
1084 for(uint k = 0; k < MaxNumUserChats; ++k)
1086 if (UserChat[k].Window == cw) return &UserChat[k];
1088 return NULL;
1091 //===========================================================================================================
1092 void CPeopleInterraction::askAddContact(const string &contactName, CPeopleList *pl)
1094 if (pl == NULL)
1095 return;
1097 if ((pl != &IgnoreList) && (pl != &FriendList))
1099 nlwarning("<askAddContact> For now, only support friend list & ignore list");
1100 return;
1103 // check that name isn't already in people list
1104 if (pl->getIndexFromName(contactName) != -1)
1106 // people already in list, can't add twice
1107 CInterfaceManager::getInstance()->displaySystemInfo(CI18N::get("uiContactAlreadyInList"));
1108 return;
1111 // add into server (NB: will be added by the server response later)
1112 const char *sMsg = "TEAM:CONTACT_ADD";
1113 CBitMemStream out;
1114 if(GenericMsgHeaderMngr.pushNameToStream(sMsg, out))
1116 uint8 list = 0;
1118 if (pl == &IgnoreList)
1119 list = 1;
1121 if (pl == &FriendList)
1122 list = 0;
1124 ucstring temp = ucstring::makeFromUtf8(contactName); // TODO: UTF-8 (serial)
1125 out.serial(temp);
1126 out.serial(list);
1127 NetMngr.push(out);
1128 //nlinfo("impulseCallBack : %s %s %d sent", sMsg.c_str(), contactName.toString().c_str(), list);
1130 else
1131 nlwarning("impulseCallBack : unknown message name : '%s'.", sMsg);
1133 // NB: no client prediction, will be added by server later
1135 // Fake Local simulation
1136 if (ClientCfg.Local)
1138 sint index = pl->addPeople(contactName);
1139 pl->setOnline(index, ccs_online);
1140 updateAllFreeTellerHeaders();
1144 //=================================================================================================================
1145 void CPeopleInterraction::askMoveContact(uint peopleIndexInSrc, CPeopleList *plSRC, CPeopleList *plDST)
1147 if ((plSRC == NULL) || (plDST == NULL)) return;
1148 if ((plSRC != &IgnoreList) && (plSRC != &FriendList))
1150 nlwarning("<askMoveContact> For now, only support friend list & ignore list");
1151 return;
1153 if ((plDST != &IgnoreList) && (plDST != &FriendList))
1155 nlwarning("<askMoveContact> For now, only support friend list & ignore list");
1156 return;
1158 if ( plDST == plSRC )
1160 // move from list to same => no op
1161 return;
1164 // check that index is already in people list
1165 if (peopleIndexInSrc >= plSRC->getNumPeople()) return;
1168 // Send message to server
1169 uint32 contactId= plSRC->getContactId(peopleIndexInSrc);
1170 uint8 nListSRC;
1172 if (plSRC == &FriendList)
1173 nListSRC = 0;
1175 if (plSRC == &IgnoreList)
1176 nListSRC = 1;
1178 const std::string sMsg = "TEAM:CONTACT_MOVE";
1179 CBitMemStream out;
1180 if(GenericMsgHeaderMngr.pushNameToStream(sMsg, out))
1182 out.serial(contactId);
1183 out.serial(nListSRC);
1184 NetMngr.push(out);
1185 //nlinfo("impulseCallBack : %s %d %d sent", sMsg.c_str(), contactId, nListSRC);
1187 else
1188 nlwarning("impulseCallBack : unknown message name : '%s'.", sMsg.c_str());
1190 // NB: no client prediction, will be added by server later
1192 // Fake Local simulation
1193 if (ClientCfg.Local)
1195 string peopleName= plSRC->getName(peopleIndexInSrc);
1196 plSRC->removePeople(peopleIndexInSrc);
1197 sint dstIndex = plDST->addPeople(peopleName);
1198 plDST->setOnline(dstIndex, ccs_online);
1199 if (getChatGroupWindow())
1201 getChatGroupWindow()->updateAllFreeTellerHeaders();
1203 updateAllFreeTellerHeaders();
1207 //=================================================================================================================
1208 void CPeopleInterraction::askRemoveContact(uint peopleIndex, CPeopleList *pl)
1210 if (pl == NULL) return;
1211 if ((pl != &IgnoreList) && (pl != &FriendList))
1213 nlwarning("<askRemoveContact> For now, only support friend pl & ignore pl");
1214 return;
1216 if (peopleIndex >= pl->getNumPeople())
1218 nlwarning("<askRemoveContact> bad index given");
1219 return;
1222 // send server message
1223 const std::string sMsg = "TEAM:CONTACT_DEL";
1224 CBitMemStream out;
1225 if(GenericMsgHeaderMngr.pushNameToStream(sMsg, out))
1227 uint32 contactId = pl->getContactId(peopleIndex);
1228 out.serial(contactId);
1229 uint8 nList = 0;
1230 if (pl == &PeopleInterraction.FriendList)
1231 nList = 0;
1232 if (pl == &PeopleInterraction.IgnoreList)
1233 nList = 1;
1234 out.serial(nList);
1235 NetMngr.push(out);
1236 //nlinfo("impulseCallBack : %s %d %d sent", sMsg.c_str(), contactId, nList);
1238 else
1239 nlwarning("impulseCallBack : unknown message name : '%s'.", sMsg.c_str());
1241 // NB: no client prediction, let the server delete the contact by message.
1243 // Fake Local simulation
1244 if (ClientCfg.Local)
1246 pl->removePeople(peopleIndex);
1247 updateAllFreeTellerHeaders();
1252 //=================================================================================================================
1253 void CPeopleInterraction::initContactLists( const std::vector<uint32> &vFriendListName,
1254 const std::vector<TCharConnectionState> &vFriendListOnline,
1255 const std::vector<ucstring> &vIgnoreListName ) // TODO: UTF-8 (serial)
1258 // clear the current lists if any
1259 FriendList.removeAllPeoples();
1260 IgnoreList.removeAllPeoples();
1262 // build the contact ids, like server did
1263 uint32 contactIdPool= 0;
1264 for (uint i = 0; i < vFriendListName.size(); ++i)
1265 addContactInList(contactIdPool++, vFriendListName[i], vFriendListOnline[i], 0);
1266 for (uint i = 0; i < vIgnoreListName.size(); ++i)
1267 addContactInList(contactIdPool++, vIgnoreListName[i].toUtf8(), ccs_offline, 1);
1268 updateAllFreeTellerHeaders();
1271 //=================================================================================================================
1272 void CPeopleInterraction::addContactInList(uint32 contactId, const string &nameIn, TCharConnectionState online, uint8 nList)
1274 // select correct people list
1275 CPeopleList &pl= nList==0?FriendList:IgnoreList;
1277 // remove the shard name if possible
1278 string name= CEntityCL::removeShardFromName(nameIn);
1280 // add the contact to this list
1281 sint index = pl.getIndexFromName(name);
1282 // try to create if not found
1283 if (index == -1)
1284 index = pl.addPeople(name);
1286 if (index != -1)
1288 pl.setOnline(index, online);
1289 pl.setContactId(index, contactId);
1292 CInterfaceManager* pIM= CInterfaceManager::getInstance();
1293 CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
1294 FriendList.sortEx(order);
1297 //=================================================================================================================
1298 void CPeopleInterraction::addContactInList(uint32 contactId, uint32 nameID, TCharConnectionState online, uint8 nList)
1300 string name;
1301 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
1302 if (pSMC->getString(nameID, name))
1304 addContactInList(contactId, name, online, nList);
1305 // update free teller header
1306 updateAllFreeTellerHeaders();
1308 else
1310 SWaitingContact w;
1311 w.ContactId= contactId;
1312 w.NameId = nameID;
1313 w.List = nList; // Friend list == 0 // Ignore list == 1
1314 w.Online = online;
1315 WaitingContacts.push_back(w);
1317 CInterfaceManager* pIM= CInterfaceManager::getInstance();
1318 CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
1319 FriendList.sortEx(order);
1323 //=================================================================================================================
1324 bool CPeopleInterraction::isContactInList(const string &nameIn, uint8 nList) const
1326 // select correct people list
1327 const CPeopleList &pl= nList==0?FriendList:IgnoreList;
1328 // remove the shard name if possible
1329 string name= CEntityCL::removeShardFromName(nameIn);
1330 return pl.getIndexFromName(name) != -1;
1333 //=================================================================================================================
1334 void CPeopleInterraction::updateAllFreeTellerHeaders()
1336 CChatGroupWindow *gcw = getChatGroupWindow();
1337 if (gcw)
1339 gcw->updateAllFreeTellerHeaders();
1343 //=================================================================================================================
1344 void CPeopleInterraction::removeAllFreeTellers()
1346 CChatGroupWindow *gcw = getChatGroupWindow();
1347 if (gcw)
1349 gcw->removeAllFreeTellers();
1353 //=================================================================================================================
1354 void CPeopleInterraction::updateWaitingContacts()
1356 bool touched = false;
1357 for (uint32 i = 0; i < WaitingContacts.size();)
1359 SWaitingContact &w = WaitingContacts[i];
1360 string name;
1361 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
1362 if (pSMC->getString(w.NameId, name))
1364 addContactInList(w.ContactId, name, w.Online, w.List);
1365 WaitingContacts.erase(WaitingContacts.begin()+i);
1366 touched = true;
1368 else
1370 ++i;
1373 if (touched)
1375 updateAllFreeTellerHeaders();
1379 //=================================================================================================================
1380 void CPeopleInterraction::updateContactInList(uint32 contactId, TCharConnectionState online, uint nList)
1382 if (nList == 0)
1384 sint index = FriendList.getIndexFromContactId(contactId);
1385 if (index != -1)
1387 // Only do work if online status has changed
1388 if (FriendList.getOnline(index) != online)
1390 CCDBNodeLeaf* node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_ONLINE_OFFLINE_NOTIFICATIONS_CB", false);
1391 if (node && node->getValueBool())
1393 // Only show the message if this player is not in my guild (because then the guild manager will show a message)
1394 std::vector<SGuildMember> GuildMembers = CGuildManager::getInstance()->getGuildMembers();
1395 bool bOnlyFriend = true;
1396 string name = toLower(FriendList.getName(index));
1397 for (uint i = 0; i < GuildMembers.size(); ++i)
1399 if (toLower(GuildMembers[i].Name) == name)
1401 bOnlyFriend = false;
1402 break;
1406 TCharConnectionState prevState = FriendList.getOnline(index);
1407 bool showMsg = bOnlyFriend && (prevState == ccs_offline || online == ccs_offline);
1409 // Player is not in my guild, and the status change is from offline to online/abroad online or vice versa.
1410 if (showMsg)
1412 string msg = (online != ccs_offline) ? CI18N::get("uiPlayerOnline") : CI18N::get("uiPlayerOffline");
1413 strFindReplace(msg, "%s", FriendList.getName(index));
1414 string cat = getStringCategory(msg, msg);
1415 map<string, CClientConfig::SSysInfoParam>::const_iterator it;
1416 NLMISC::CRGBA col = CRGBA::Yellow;
1417 it = ClientCfg.SystemInfoParams.find(toLowerAscii(cat));
1418 if (it != ClientCfg.SystemInfoParams.end())
1420 col = it->second.Color;
1422 bool dummy;
1423 PeopleInterraction.ChatInput.AroundMe.displayMessage(msg, col, 2, &dummy);
1427 FriendList.setOnline(index, online);
1431 else
1433 sint index = IgnoreList.getIndexFromContactId(contactId);
1434 if (index != -1)
1435 IgnoreList.setOnline(index, online);
1439 //=================================================================================================================
1440 void CPeopleInterraction::removeContactFromList(uint32 contactId, uint8 nList)
1442 if (nList == 0)
1444 sint index = FriendList.getIndexFromContactId(contactId);
1445 if (index != -1)
1446 FriendList.removePeople(index);
1448 else
1450 sint index = IgnoreList.getIndexFromContactId(contactId);
1451 if (index != -1)
1452 IgnoreList.removePeople(index);
1454 updateAllFreeTellerHeaders();
1457 //=================================================================================================================
1458 bool CPeopleInterraction::testValidPartyChatName(const string &title)
1460 if (title.empty()) return false;
1461 // shouldn't begin like 'user chat 1-5'
1462 const string &userChatStr = CI18N::get("uiUserChat");
1463 if (NLMISC::startsWith(title, userChatStr)) return false;
1464 // can't match a translation identifier
1465 if (CI18N::hasTranslation(title)) return false;
1466 for(uint k = 0; k < PartyChats.size(); ++k) // there shouldn't be that much party chat simultaneously so a linear search is ok
1468 if (PartyChats[k].Window->getTitle() == title) return false;
1470 // check for other chat window names (local only ?)
1471 if (SystemInfo && title == SystemInfo->getTitle()) return false;
1472 if (AroundMe.Window && title == AroundMe.Window->getTitle()) return false;
1473 if (GuildChat && title == GuildChat->getTitle()) return false;
1474 if (TeamChat && title == TeamChat->getTitle()) return false;
1475 sint index;
1476 index = FriendList.getIndexFromName(title);
1477 if (index != -1) return false;
1478 index = IgnoreList.getIndexFromName(title);
1479 if (index != -1) return false;
1480 // TODO_GAMEDEV server test for the name (not only local), & modify callers of this function
1481 // The party chat should NOT have the name of a player
1482 // A player name is NOT valid if it is the same that a party chat name
1483 return true;
1486 //=================================================================================================================
1487 bool CPeopleInterraction::removePartyChat(CChatWindow *window)
1489 if (!window) return false;
1490 std::vector<CPartyChatInfo>::iterator it;
1491 for(it = PartyChats.begin(); it != PartyChats.end(); ++it)
1493 if (it->Window == window) break;
1495 if (it != PeopleInterraction.PartyChats.end())
1497 PeopleInterraction.PartyChats.erase(it);
1498 getChatWndMgr().removeChatWindow(window->getTitle());
1499 // TODO GAMEDEV : send msg to server to tell that the player has deleted this party chat.
1500 return true;
1502 else
1504 return false;
1508 //=================================================================================================================
1509 void CPeopleInterraction::assignPartyChatMenu(CChatWindow *partyChat)
1511 if (!partyChat) return;
1512 // TODO GAMEDEV : fill the 2 following boolean
1513 bool isTeamLeader = true;
1514 bool isGuildLeader = true;
1516 if (isTeamLeader && isGuildLeader)
1518 partyChat->setMenu("ui:interface:team_and_guild_chief_party_chat_menu");
1520 else if (isTeamLeader)
1522 partyChat->setMenu("ui:interface:team_chief_party_chat_menu");
1524 else if (isGuildLeader)
1526 partyChat->setMenu("ui:interface:guild_chief_party_chat_menu");
1530 //=================================================================================================================
1531 bool CPeopleInterraction::createNewPartyChat(const string &title)
1533 // now there are no party chat windows, party chat phrases must be filtered from the main chat
1535 // create a new party chat and set the focus on it
1536 CChatWindowDesc chatDesc;
1537 //chatDesc.FatherContainer = "ui:interface:communication";
1538 chatDesc.FatherContainer = "ui:interface:contact_list";
1539 chatDesc.Title = title;
1540 chatDesc.Title = title;
1541 chatDesc.Listener = &PartyChatEntryHandler;
1542 chatDesc.Localize = false;
1544 // CChatWindow *newPartyChat = getChatWndMgr().createChatWindow(chatDesc);
1545 CChatWindow *newPartyChat = NULL;
1547 //if (newPartyChat)
1549 // popup the container
1551 newPartyChat->getContainer()->setup();
1552 newPartyChat->getContainer()->setOpen(true);
1553 newPartyChat->getContainer()->popupCurrentPos();
1554 newPartyChat->getContainer()->updateCoords();
1555 newPartyChat->getContainer()->center();
1556 newPartyChat->getContainer()->setX(newPartyChat->getContainer()->getX() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA));
1557 newPartyChat->getContainer()->setY(newPartyChat->getContainer()->getY() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA));
1558 newPartyChat->getContainer()->enableBlink(2);
1561 CPartyChatInfo pci;
1562 pci.Window = newPartyChat;
1563 pci.ID = PeopleInterraction.CurrPartyChatID ++;
1564 pci.Filter = new CChatInputFilter;
1565 pci.Filter->addListeningWindow(pci.Window);
1566 //CPeopleInterraction::assignPartyChatMenu(newPartyChat);
1567 PartyChats.push_back(pci);
1568 //newPartyChat->setKeyboardFocus();
1570 return true;
1572 return false;
1575 //=================================================================================================================
1576 void CPeopleInterraction::buildFilteredChatSummary(const CFilteredChat &src, CFilteredChatSummary &fcs)
1578 // fill src infos
1579 fcs.SrcGuild = ChatInput.Guild.isListeningWindow(src.Window);
1580 fcs.SrcAroundMe = ChatInput.AroundMe.isListeningWindow(src.Window);
1581 fcs.SrcSystemInfo = ChatInput.SystemInfo.isListeningWindow(src.Window);
1582 fcs.SrcTeam = ChatInput.Team.isListeningWindow(src.Window);
1583 fcs.SrcTell = ChatInput.Tell.isListeningWindow(src.Window);
1584 fcs.SrcRegion = ChatInput.Region.isListeningWindow(src.Window);
1585 fcs.SrcUniverse = ChatInput.Universe.isListeningWindow(src.Window);
1587 // fill target infos
1588 if (src.Filter.getTargetPartyChat() != NULL || !src.Filter.getTargetPlayer().empty())
1590 fcs.Target = CChatGroup::say;
1592 else
1594 fcs.Target = src.Filter.getTargetGroup();
1598 //=================================================================================================================
1599 void CPeopleInterraction::buildFilteredDynChatSummary(const CFilteredChat &src, CFilteredDynChatSummary &fcs)
1601 for (uint8 i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
1603 fcs.SrcDynChat[i] = ChatInput.DynamicChat[i].isListeningWindow(src.Window);
1607 //=================================================================================================================
1608 void CPeopleInterraction::saveFilteredChat(NLMISC::IStream &f, const CFilteredChat &src)
1610 bool present;
1611 if (src.Window == NULL)
1613 present = false;
1614 f.serial(present);
1616 else
1618 present = true;
1619 f.serial(present);
1620 CFilteredChatSummary fcs;
1621 buildFilteredChatSummary(src, fcs);
1622 f.serial(fcs);
1626 //=================================================================================================================
1627 void CPeopleInterraction::saveFilteredDynChat(NLMISC::IStream &f, const CFilteredChat &src)
1629 bool present;
1630 if (src.Window == NULL)
1632 present = false;
1633 f.serial(present);
1635 else
1637 present = true;
1638 f.serial(present);
1639 CFilteredDynChatSummary fcs;
1640 buildFilteredDynChatSummary(src, fcs);
1641 f.serial(fcs);
1645 //=================================================================================================================
1646 CChatGroupWindow *CPeopleInterraction::getChatGroupWindow() const
1648 return dynamic_cast<CChatGroupWindow*>(ChatGroup.Window);
1651 #define USER_CHATS_INFO_VERSION 2
1652 #define USER_DYN_CHATS_INFO_VERSION 1
1654 //=================================================================================================================
1655 bool CPeopleInterraction::saveUserChatsInfos(NLMISC::IStream &f)
1657 nlassert(!f.isReading());
1660 sint ver= f.serialVersion(USER_CHATS_INFO_VERSION);
1661 f.serialCheck(NELID("TAHC"));
1662 //saveFilteredChat(f, MainChat);
1663 saveFilteredChat(f, ChatGroup);
1664 for(uint k = 0; k < MaxNumUserChats; ++k)
1666 saveFilteredChat(f, UserChat[k]);
1668 f.serialCheck(NELID("TAHC"));
1669 if (ver>=1)
1671 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
1672 sint32 index = pCGW ? pCGW->getTabIndex() : 0;
1673 f.serial(index);
1674 saveFilteredChat(f, TheUserChat);
1676 // Save the free tellers only if they belongs to friend list to avoid the 'only growing' situation
1677 if (ver>=2)
1679 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
1680 if (pCGW)
1682 pCGW->saveFreeTeller(f);
1686 catch(const NLMISC::EStream &e)
1688 nlwarning("Error while saving user chat infos : %s", e.what());
1689 return false;
1691 return true;
1694 //=================================================================================================================
1695 bool CPeopleInterraction::saveUserDynChatsInfos(NLMISC::IStream &f)
1697 nlassert(!f.isReading());
1700 sint ver = f.serialVersion(USER_DYN_CHATS_INFO_VERSION);
1701 f.serialCheck(NELID("OMGY"));
1702 if (ver >= 1)
1704 saveFilteredDynChat(f, TheUserChat);
1707 catch(const NLMISC::EStream &e)
1709 nlwarning("Error while saving user dyn chat infos : %s", e.what());
1710 return false;
1712 return true;
1715 //=================================================================================================================
1716 bool CPeopleInterraction::loadUserChatsInfos(NLMISC::IStream &f)
1718 removeAllUserChats();
1719 nlassert(f.isReading());
1722 bool present;
1723 sint ver = f.serialVersion(USER_CHATS_INFO_VERSION);
1724 f.serialCheck(NELID("TAHC"));
1725 f.serial(present);
1726 if (!present)
1728 nlwarning("Bad data in user chats infos");
1729 return false;
1731 CFilteredChatSummary fcs;
1732 f.serial(fcs);
1733 //setupUserChatFromSummary(fcs, MainChat);
1734 setupUserChatFromSummary(fcs, ChatGroup);
1736 for(uint k = 0; k < MaxNumUserChats; ++k)
1738 f.serial(present);
1739 if (present)
1741 createUserChat(k);
1742 f.serial(fcs);
1743 setupUserChatFromSummary(fcs, UserChat[k]);
1746 f.serialCheck(NELID("TAHC"));
1747 if (ver>=1)
1749 // CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
1750 sint32 index;
1751 f.serial(index);
1752 /* Yoyo: decide to always start with the default channel (user) activated
1753 because complex (at this time, the buttons are not all active, must wait guild loading, UI:SAVE loading etc...)
1754 Hence this doesn't work for anything but User and Sysinfo (if it is activated....)
1755 NB: must still load the index for file format reason
1756 //if (pCGW) pCGW->setTabIndex(index);
1758 f.serial(present);
1759 if (present)
1761 f.serial(fcs);
1762 setupUserChatFromSummary(fcs, TheUserChat);
1765 // Load the free tellers
1766 if (ver>=2)
1768 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
1769 if (pCGW) pCGW->loadFreeTeller(f);
1772 catch(const NLMISC::EStream &e)
1774 nlwarning("Error while loading user chat infos : %s", e.what());
1775 return false;
1777 return true;
1780 //=================================================================================================================
1781 bool CPeopleInterraction::loadUserDynChatsInfos(NLMISC::IStream &f)
1783 nlassert(f.isReading());
1786 bool present;
1787 sint ver = f.serialVersion(USER_DYN_CHATS_INFO_VERSION);
1788 f.serialCheck(NELID("OMGY"));
1789 f.serial(present);
1790 if (!present)
1792 nlwarning("Bad data in user dyn chats infos");
1793 return false;
1795 CFilteredDynChatSummary fcs;
1796 if (ver >= 1)
1798 f.serial(fcs);
1799 setupUserDynChatFromSummary(fcs, TheUserChat);
1802 catch(const NLMISC::EStream &e)
1804 nlwarning("Error while loading user dyn chat infos : %s", e.what());
1805 return false;
1807 return true;
1811 //=================================================================================================================
1812 void CPeopleInterraction::setupUserChatFromSummary(const CFilteredChatSummary &summary, CFilteredChat &dest)
1814 // User Dest. Do not allow Universe Warning, because do not want a warning open at load (moreover, the UNIVERSE tab should not be activated)
1815 dest.Filter.setTargetGroup(summary.Target, 0, false);
1816 // src
1817 ChatInput.AroundMe.setWindowState(dest.Window, summary.SrcAroundMe);
1818 ChatInput.Guild.setWindowState(dest.Window, summary.SrcGuild);
1819 ChatInput.SystemInfo.setWindowState(dest.Window, summary.SrcSystemInfo);
1820 ChatInput.Team.setWindowState(dest.Window, summary.SrcTeam);
1821 ChatInput.Tell.setWindowState(dest.Window, summary.SrcTell);
1822 ChatInput.Region.setWindowState(dest.Window, summary.SrcRegion);
1823 ChatInput.Universe.setWindowState(dest.Window, summary.SrcUniverse);
1826 //=================================================================================================================
1827 void CPeopleInterraction::setupUserDynChatFromSummary(const CFilteredDynChatSummary &summary, CFilteredChat &dest)
1829 // src
1830 for (uint8 i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
1832 ChatInput.DynamicChat[i].setWindowState(dest.Window, summary.SrcDynChat[i]);
1836 //=================================================================================================================
1837 void CPeopleInterraction::removeAllUserChats()
1839 for(uint k = 0; k < MaxNumUserChats; ++k)
1841 if (UserChat[k].Window)
1843 getChatWndMgr().removeChatWindow(UserChat[k].Window);
1844 UserChat[k].Filter.reset();
1845 UserChat[k].Window = NULL;
1850 //=================================================================================================================
1851 void CPeopleInterraction::createUserChat(uint index)
1853 if (index >= MaxNumUserChats)
1855 nlwarning("Bad index");
1856 return;
1858 CChatWindowDesc chatDesc;
1859 string userChatStr = CI18N::get("uiUserChat");
1860 userChatStr += ' ' + toString(index + 1);
1861 //chatDesc.FatherContainer = "ui:interface:communication";
1862 chatDesc.FatherContainer = "ui:interface:contact_list";
1863 chatDesc.Title = userChatStr;
1864 chatDesc.Listener = NULL;
1865 chatDesc.Localize = false;
1866 chatDesc.Savable = true;
1867 chatDesc.ChatTemplate = "filtered_chat_id";
1868 UserChat[index].Window = getChatWndMgr().createChatWindow(chatDesc);
1869 if (!UserChat[index].Window) return;
1870 UserChat[index].Window->getContainer()->setup();
1871 // Configure filter for the new chat (by default, listen to everything but party chats)
1872 UserChat[index].Filter.setTargetGroup(CChatGroup::say);
1873 // assoviate filter with chat window
1874 UserChat[index].Filter.setChat(UserChat[index].Window);
1877 //=================================================================================================================
1878 void CPeopleInterraction::refreshActiveUserChats()
1880 for(uint k = 0; k < MaxNumUserChats; ++k)
1882 if (UserChat[k].Window)
1884 UserChat[k].Window->getContainer()->setActive(true);
1889 //=================================================================================================================
1890 void CPeopleInterraction::talkInDynamicChannel(uint32 channelNb,string sentence)
1892 if(channelNb<CChatGroup::MaxDynChanPerPlayer)
1894 DynamicChatEntryHandler[channelNb].msgEntered(sentence,DynamicChat[channelNb]);
1898 //=================================================================================================================
1899 void CPeopleInterraction::displayTellInMainChat(const string &playerName)
1901 //CChatWindow *chat = PeopleInterraction.MainChat.Window;
1902 CChatWindow *chat = PeopleInterraction.ChatGroup.Window;
1903 if (!chat) return;
1904 chat->getContainer()->setActive (true);
1905 // make the container blink
1906 chat->getContainer()->enableBlink(2);
1907 // TODO : center the view on the newly created container ?
1908 // display a new command '/name' in the chat. The player must enter a new unique name for the party chat.
1909 chat->setCommand("tell " + playerName + " ", false);
1910 chat->setKeyboardFocus();
1913 /////////////////////////////////////
1914 // ACTION HANDLERS FOR PEOPLE LIST //
1915 /////////////////////////////////////
1917 //=================================================================================================================
1918 // Target a member of the team
1919 // See also CAHTargetTeammateShortcut
1920 class CHandlerTeamTarget : public IActionHandler
1922 void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
1924 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1926 // retrieve the index of the people
1927 uint peopleIndex= 0;
1928 bool ok= false;
1929 // If comes from the button, get direct index
1930 if( !sParams.empty() )
1932 fromString(sParams, peopleIndex);
1933 ok= true;
1935 // else comes from a menu.
1936 else
1938 CPeopleList *list;
1939 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
1941 if (list == &PeopleInterraction.TeamList) // check for good list
1942 ok= true;
1946 // If success to get the team index
1947 if(ok)
1949 // Get the team name id.
1950 CLFECOMMON::TClientDataSetIndex entityId= CLFECOMMON::INVALID_CLIENT_DATASET_INDEX;
1951 CCDBNodeLeaf *prop = NLGUI::CDBManager::getInstance()->getDbProp(toString(TEAM_DB_PATH ":%d:UID", peopleIndex), false);
1952 if (prop)
1953 entityId= prop->getValue32();
1955 if(entityId != CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
1957 // get the entity by its received name
1958 CEntityCL *entity= EntitiesMngr.getEntityByCompressedIndex(entityId);
1959 if(entity)
1960 // Select this entity.
1961 UserEntity->selection(entity->slot());
1962 else
1964 // the entity is not in vision, can't select it
1965 pIM->displaySystemInfo(CI18N::get("uiTeamSelectNotInVision"), "CHK");
1971 REGISTER_ACTION_HANDLER( CHandlerTeamTarget, "team_target" );
1973 //=================================================================================================================
1974 // Dismiss a member from the team
1975 class CHandlerDismissMember : public IActionHandler
1977 public:
1978 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
1980 // retrieve the index of the people
1981 CPeopleList *list;
1982 uint peopleIndex;
1983 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
1985 if (list == &PeopleInterraction.TeamList) // check for good list
1987 const string msgName = "TEAM:KICK";
1988 CBitMemStream out;
1989 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
1991 uint8 teamMember = (uint8) peopleIndex;
1992 out.serial(teamMember);
1993 NetMngr.push(out);
1994 //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember);
1996 else
1997 nlwarning("command 'dismiss_member': unknown message named '%s'.", msgName.c_str());
2002 REGISTER_ACTION_HANDLER( CHandlerDismissMember, "dismiss_member");
2004 //=================================================================================================================
2005 // Set the leader of the team
2006 class CHandlerSetTeamLeader : public IActionHandler
2008 public:
2009 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2011 // retrieve the index of the people
2012 CPeopleList *list;
2013 uint peopleIndex;
2014 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
2016 if (list == &PeopleInterraction.TeamList) // check for good list
2019 const string msgName = "TEAM:SET_LEADER";
2020 CBitMemStream out;
2021 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
2023 uint8 teamMember = (uint8)(peopleIndex);
2024 out.serial(teamMember);
2025 NetMngr.push(out);
2026 //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember);
2028 else
2029 nlwarning("command 'set_leader': unknown message named '%s'.", msgName.c_str());
2031 NLMISC::ICommand::execute("a setTeamLeader " + toString(peopleIndex), g_log);
2036 REGISTER_ACTION_HANDLER( CHandlerSetTeamLeader, "set_team_leader");
2038 //=================================================================================================================
2039 // Set a successor for the team
2040 class CHandlerSetSuccessor : public IActionHandler
2042 public:
2043 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2045 // retrieve the index of the people
2046 CPeopleList *list;
2047 uint peopleIndex;
2048 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
2050 if (list == &PeopleInterraction.TeamList) // check for good list
2052 if (ClientCfg.Local)
2054 NLGUI::CDBManager::getInstance()->getDbProp(TEAM_DB_PATH ":SUCCESSOR_INDEX")->setValue32(peopleIndex);
2056 else
2058 const string msgName = "TEAM:SET_SUCCESSOR";
2059 CBitMemStream out;
2060 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
2062 uint8 teamMember = (uint8) peopleIndex;
2063 out.serial(teamMember);
2064 NetMngr.push(out);
2065 //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember);
2067 else
2068 nlwarning("command 'set_successor': unknown message named '%s'.", msgName.c_str());
2074 REGISTER_ACTION_HANDLER( CHandlerSetSuccessor, "set_successor");
2077 //=================================================================================================================
2078 // player or leader quit the team
2079 class CHandlerQuitTeam : public IActionHandler
2081 public:
2082 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2084 // Create the message for the server to execute a phrase.
2085 const string msgName = "TEAM:LEAVE";
2086 CBitMemStream out;
2087 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
2089 NetMngr.push(out);
2090 //nlinfo("impulseCallBack : %s sent", msgName.c_str());
2092 else
2093 nlwarning("CHandlerContextQuitTeam::execute: unknown message name : '%s'.", msgName.c_str());
2096 REGISTER_ACTION_HANDLER( CHandlerQuitTeam, "quit_team");
2098 //=================================================================================================================
2099 // The leader enable / disbale seeds sharing
2100 class CHandlerShareSeeds : public IActionHandler
2102 public:
2103 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2105 // TODO_GAMEDEV : enable disable seeds sharing
2108 REGISTER_ACTION_HANDLER( CHandlerShareSeeds, "share_seeds");
2110 //////////////////
2111 // CONTACT LIST //
2112 //////////////////
2114 //=================================================================================================================
2115 // Remove a contact from a list
2116 class CHandlerRemoveContact : public IActionHandler
2118 public:
2119 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2121 // retrieve the index of the people
2122 CPeopleList *list;
2123 uint peopleIndex;
2124 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
2126 PeopleInterraction.askRemoveContact(peopleIndex, list);
2130 REGISTER_ACTION_HANDLER( CHandlerRemoveContact, "remove_contact");
2132 //=================================================================================================================
2133 // Invoke the 'tell' command on a contact from its menu
2134 // The tell command is displayed in the 'around me' window
2135 class CHandlerMenuTellContact : public IActionHandler
2137 public:
2138 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2140 // retrieve the index of the people
2141 CPeopleList *list;
2142 uint peopleIndex;
2143 if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
2145 CPeopleInterraction::displayTellInMainChat(list->getName(peopleIndex));
2149 REGISTER_ACTION_HANDLER( CHandlerMenuTellContact, "menu_tell_contact");
2152 //=================================================================================================================
2153 // Invoke the 'tell' command on a contact from a left click
2154 class CHandlerTellContact : public IActionHandler
2156 void execute (CCtrlBase *pCaller, const std::string &/* sParams */)
2158 if (!pCaller) return;
2159 CInterfaceGroup *ig = pCaller->getParent();
2160 if (!ig) return;
2161 CGroupContainer *gc = static_cast< CGroupContainer* >( ig->getEnclosingContainer() );
2162 if (!gc) return;
2163 CPeopleList *list;
2164 uint peopleIndex;
2165 if (PeopleInterraction.getPeopleFromContainerID(gc->getId(), list, peopleIndex))
2167 CPeopleInterraction::displayTellInMainChat(list->getName(peopleIndex));
2172 REGISTER_ACTION_HANDLER( CHandlerTellContact, "tell_contact");
2175 //=================================================================================================================
2176 std::string LastFatherAddContactId;
2177 // Add a contact to the list, first step
2178 class CHandlerAddContactBegin : public IActionHandler
2180 public:
2181 void execute (CCtrlBase *pCaller, const std::string &sParams)
2183 /** This msg may have been triggered from valid button or from the edit box itself, so retrieve
2184 * the edit box from the enclosing group
2186 // Get enclosing container to know in which people list we are
2187 if (pCaller)
2189 // Get header_open
2190 CInterfaceGroup *group = pCaller->getParent();
2191 if (group)
2193 // Get container
2194 group = group->getParent();
2195 if (group)
2197 LastFatherAddContactId = group->getId();
2198 if (!LastFatherAddContactId.empty())
2200 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2201 string groupName= getParam(sParams, "group");
2202 CInterfaceGroup *gc = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getElementFromId(groupName));
2203 if (gc)
2205 CGroupEditBox *geb = dynamic_cast<CGroupEditBox *>(gc->getGroup("add_contact_eb:eb"));
2206 geb->setInputString(std::string());
2208 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, sParams);
2215 REGISTER_ACTION_HANDLER( CHandlerAddContactBegin, "add_contact_begin");
2218 //=================================================================================================================
2219 // Add a contact to the list
2220 class CHandlerAddContact : public IActionHandler
2222 public:
2223 void execute (CCtrlBase *pCaller, const std::string &/* sParams */)
2225 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2227 /** This msg may have been triggered from valid button or from the edit box itself, so retrieve
2228 * the edit box from the enclosing group
2230 // Get enclosing container to know in which people list we are
2231 if (!LastFatherAddContactId.empty() && pCaller)
2233 CInterfaceGroup *fatherGC = pCaller->getParent();
2234 if (fatherGC)
2236 // Look for the root parent
2237 for(;;)
2239 CInterfaceGroup *parent = fatherGC->getParent();
2240 if (!parent || (parent->getId()=="ui:interface"))
2241 break;
2242 fatherGC = parent;
2245 // Get the modal edit box
2246 CGroupEditBox *geb = dynamic_cast<CGroupEditBox *>(fatherGC->getGroup("add_contact_eb:eb"));
2247 if (geb && !geb->getInputString().empty())
2249 std::string::size_type lastIndex = LastFatherAddContactId.rfind(":");
2250 if (lastIndex != std::string::npos)
2252 // Get the people list with the preselected container ID
2253 CPeopleList *peopleList = PeopleInterraction.getPeopleListFromContainerID(LastFatherAddContactId.substr(lastIndex+1));
2254 if (peopleList)
2256 // don't add if it is the player name
2257 if (!ClientCfg.Local && (UserEntity->getEntityName() == geb->getInputString()))
2259 displayVisibleSystemMsg(CI18N::get("uiCantAddYourSelfInContactList"));
2261 else
2263 PeopleInterraction.askAddContact(geb->getInputString(), peopleList);
2264 geb->setInputString(std::string());
2268 geb->setInputString(std::string());
2272 CAHManager::getInstance()->runActionHandler("leave_modal", pCaller, "");
2275 REGISTER_ACTION_HANDLER( CHandlerAddContact, "add_contact");
2278 //=================================================================================================================
2279 class CHandlerMoveContact : public IActionHandler
2281 public:
2282 void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
2284 // retrieve the index of the people
2285 CPeopleList *srcList;
2286 uint peopleIndex;
2287 if (PeopleInterraction.getPeopleFromCurrentMenu(srcList, peopleIndex))
2289 // get the destination list
2290 CPeopleList *destList;
2291 int listIndex;
2292 if (!fromString(getParam(sParams, "list"), listIndex))
2294 nlwarning("Bad list index");
2295 return;
2297 switch(listIndex)
2299 case 0:
2300 destList = &PeopleInterraction.IgnoreList;
2301 break;
2302 case 1:
2303 destList = &PeopleInterraction.FriendList;
2304 break;
2305 default: nlwarning("Bad list index"); return;
2308 PeopleInterraction.askMoveContact(peopleIndex, srcList, destList);
2312 REGISTER_ACTION_HANDLER( CHandlerMoveContact, "move_contact");
2315 //=================================================================================================================
2316 class CHandlerSortContacts : public IActionHandler
2318 public:
2319 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2321 CInterfaceManager* pIM= CInterfaceManager::getInstance();
2322 nlinfo("Load Order : %d", NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
2323 CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
2325 order = (CPeopleList::TSortOrder)(order + 1);
2326 if (order == CPeopleList::END_SORT_ORDER)
2328 order = CPeopleList::START_SORT_ORDER;
2331 nlinfo("Save Order : %d", order);
2332 NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->setValue32((sint32)order);
2333 CPeopleList *pl = PeopleInterraction.getPeopleListFromCurrentMenu();
2334 if (pl)
2335 pl->sortEx(order);
2338 REGISTER_ACTION_HANDLER( CHandlerSortContacts, "sort_contacts");
2341 //=================================================================================================================
2342 // Directly chat with a friend (launch a container chat)
2343 class CHandlerContactDirectChat : public IActionHandler
2345 public:
2346 void execute (CCtrlBase *pCaller, const std::string &/* sParams */)
2348 if (pCaller == NULL)
2349 return;
2351 CInterfaceGroup *fatherGC = pCaller->getParent();
2352 if (fatherGC == NULL)
2353 return;
2354 fatherGC = fatherGC->getParent();
2355 if (fatherGC == NULL)
2356 return;
2357 string str = fatherGC->getId().substr(0,fatherGC->getId().rfind('_'));
2358 str = str.substr(str.rfind(':')+1, str.size());
2359 CPeopleList *peopleList = PeopleInterraction.getPeopleListFromContainerID(str);
2360 if (peopleList == NULL)
2361 return;
2363 sint index = peopleList->getIndexFromContainerID(fatherGC->getId());
2364 if (index == -1)
2365 return;
2367 peopleList->openCloseChat(index, true);
2370 REGISTER_ACTION_HANDLER( CHandlerContactDirectChat, "contact_direct_chat");
2373 ////////////////
2374 // PARTY CHAT //
2375 ////////////////
2377 //=================================================================================================================
2378 /** Menu to create a new party chat
2380 class CHandlerNewPartyChat : public IActionHandler
2382 public:
2383 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2385 nlwarning("Deactivated for now!");
2386 return;
2387 CInterfaceManager *im = CInterfaceManager::getInstance();
2388 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(NEW_PARTY_CHAT_WINDOW));
2389 if (!gc) return;
2390 CWidgetManager::getInstance()->setTopWindow(gc);
2391 // Set the keyboard focus
2392 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(gc->getGroup("eb"));
2393 if (eb)
2395 CWidgetManager::getInstance()->setCaptureKeyboard(eb);
2396 eb->setInputString(std::string());
2399 if (gc->getActive())
2401 gc->enableBlink(1);
2402 return;
2404 gc->setActive(true);
2405 gc->updateCoords();
2406 gc->center();
2409 REGISTER_ACTION_HANDLER( CHandlerNewPartyChat, "new_party_chat");
2411 //=================================================================================================================
2412 /** The name of a party chat has been validated
2414 class CHandlerValidatePartyChatName : public IActionHandler
2416 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2418 CInterfaceManager *im = CInterfaceManager::getInstance();
2419 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(NEW_PARTY_CHAT_WINDOW));
2420 if (!gc) return;
2421 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(gc->getGroup("eb"));
2422 if (!eb) return;
2423 string title = eb->getInputString();
2425 // TODO GAMEDEV : create (or join ?) a new channel. Each channel (party chat) should have a unique name in the game
2426 // moreover, it should not have the name of another available chat window (for example, it shouldn't be named 'Around Me')
2427 // It shouldn't have the name of an existing player, either..
2428 // Maybe this last test can be done in local only
2430 if (!PeopleInterraction.testValidPartyChatName(title))
2432 displayVisibleSystemMsg(title + " : " + CI18N::get("uiInvalidPartyChatName"));
2433 return;
2436 // create the party chat
2437 PeopleInterraction.createNewPartyChat(title);
2438 return;
2441 REGISTER_ACTION_HANDLER(CHandlerValidatePartyChatName, "validate_party_chat_name");
2444 //=================================================================================================================
2445 /** Menu to create a new party chat
2449 //=================================================================================================================
2450 /** Menu to remove a currenlty created party chat
2452 class CHandlerRemovePartyChat : public IActionHandler
2454 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2456 CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2457 if (chat) PeopleInterraction.removePartyChat(chat);
2460 REGISTER_ACTION_HANDLER( CHandlerRemovePartyChat, "remove_party_chat");
2462 //=================================================================================================================
2463 /** TEMP : just create an 'invite' command in the 'around me' edit box
2465 class CHandlerPartyChatInvite : public IActionHandler
2467 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2469 CChatWindow *am = PeopleInterraction.AroundMe.Window;
2470 if (!am) return;
2471 CCtrlBase *cb = am->getContainer();
2472 while (cb)
2474 cb->forceOpen();
2475 cb = cb->getParent();
2477 // make the container blink
2478 am->getContainer()->enableBlink(2);
2479 // TODO : center the view on the newly created container ?
2480 // display a new command '/name' in the chat. The player must enter a new unique name for the party chat.
2481 am->setCommand("invite ", false);
2482 am->setKeyboardFocus();
2485 REGISTER_ACTION_HANDLER( CHandlerPartyChatInvite, "party_chat_invite" );
2488 //=================================================================================================================
2489 /** Add all members of the team to the party chat
2491 class CHandlerAddAllTeamMembersToPartyChat : public IActionHandler
2493 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2495 // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2496 // TODO GAMEDEV : add all team members
2499 REGISTER_ACTION_HANDLER( CHandlerAddAllTeamMembersToPartyChat, "add_all_team_members");
2501 //=================================================================================================================
2502 /** Remove all members of the team to the party chat
2504 class CHandlerRemoveAllTeamMembersToPartyChat : public IActionHandler
2506 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2508 // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2509 // TODO GAMEDEV : remove all team members
2512 REGISTER_ACTION_HANDLER( CHandlerRemoveAllTeamMembersToPartyChat, "remove_all_team_members");
2514 //=================================================================================================================
2515 /** Add all members of the guild to the party chat
2517 class CHandlerAddAllGuildMembersToPartyChat : public IActionHandler
2519 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2521 // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2522 // TODO GAMEDEV : add all guild members
2525 REGISTER_ACTION_HANDLER( CHandlerAddAllGuildMembersToPartyChat, "add_all_guild_members");
2527 //=================================================================================================================
2528 /** Remove all members of the team to the party chat
2530 class CHandlerRemoveAllGuildMembersToPartyChat : public IActionHandler
2532 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2534 // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2535 // TODO_GAMEDEV : remove all guild members
2538 REGISTER_ACTION_HANDLER( CHandlerRemoveAllGuildMembersToPartyChat, "remove_all_guild_members");
2540 /////////////////////////////////////////
2541 // ACTION HANDLERS FOR MAIN/USER CHATS //
2542 /////////////////////////////////////////
2544 //=================================================================================================================
2545 /** Select the target on a filtered chat window
2546 * This create a menu with the standard window (team, around me ...) + the party chat windows
2548 class CHandlerSelectChatTarget : public IActionHandler
2550 public:
2551 void execute (CCtrlBase *pCaller, const std::string &sParams)
2553 CChatWindow *cw = getChatWndMgr().getChatWindowFromCaller(pCaller);
2554 if (!cw) return;
2555 ChatWindowForFilter = cw;
2556 CInterfaceManager *im = CInterfaceManager::getInstance();
2558 std::string menuName = getParam(sParams, "menu");
2559 std::string strPartyChats = getParam(sParams, "party_chats");
2560 bool partyChats = true;
2561 if (!strPartyChats.empty())
2563 partyChats = nlstricmp("true", strPartyChats.c_str()) == 0;
2565 // get the menu
2566 CGroupMenu *menu = dynamic_cast<CGroupMenu *>(CWidgetManager::getInstance()->getElementFromId(menuName));
2567 if (!menu) return;
2568 // remove all party chat from the previous list
2569 uint lastTargetSelectedIndex = 0;
2570 for(uint k = 0; k < menu->getNumLine();)
2572 if (nlstricmp("chat_target_selected", menu->getActionHandler(k)) == 0)
2574 lastTargetSelectedIndex = k;
2575 int dummy;
2576 if (fromString(menu->getActionHandlerParam(k), dummy))
2578 // this is a party chat, removes the entry
2579 menu->deleteLine(k);
2580 -- lastTargetSelectedIndex;
2582 else
2584 ++k;
2587 else
2589 ++k;
2593 CPeopleInterraction &pl = PeopleInterraction;
2594 // add names of the party chats
2595 uint insertionIndex = lastTargetSelectedIndex + 1; // insert after standard options
2596 if (partyChats)
2598 for(uint l = 0; l < pl.PartyChats.size(); ++l)
2600 menu->addLineAtIndex(insertionIndex, pl.PartyChats[l].Window->getTitle(), "chat_target_selected", toString(pl.PartyChats[l].ID));
2601 ++ insertionIndex;
2605 // Case of user chat in grouped chat window
2606 if ((cw == PeopleInterraction.ChatGroup.Window) || (cw = PeopleInterraction.TheUserChat.Window))
2608 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2609 cw = PeopleInterraction.TheUserChat.Window;
2610 // CChatStdInput &ci = PeopleInterraction.ChatInput;
2611 CGroupMenu *pMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_target_menu"));
2612 CViewTextMenu *pMenuAround = dynamic_cast<CViewTextMenu*>(pMenu->getElement("ui:interface:user_chat_target_menu:around"));
2613 CViewTextMenu *pMenuRegion = dynamic_cast<CViewTextMenu*>(pMenu->getElement("ui:interface:user_chat_target_menu:region"));
2614 CViewTextMenu *pMenuUniverse = dynamic_cast<CViewTextMenu*>(pMenu->getElement("ui:interface:user_chat_target_menu:universe"));
2615 CViewTextMenu *pMenuTeam = dynamic_cast<CViewTextMenu*>(pMenu->getElement("ui:interface:user_chat_target_menu:team"));
2616 CViewTextMenu *pMenuGuild = dynamic_cast<CViewTextMenu*>(pMenu->getElement("ui:interface:user_chat_target_menu:guild"));
2617 const bool teamActive = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:GROUP:0:PRESENT")->getValueBool();
2618 const bool guildActive = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:GUILD:NAME")->getValueBool();
2619 if (pMenuAround) pMenuAround->setGrayed (false);
2620 if (pMenuRegion) pMenuRegion->setGrayed (false);
2621 if (pMenuUniverse) pMenuUniverse->setGrayed (false);
2622 if (pMenuTeam) pMenuTeam->setGrayed (!teamActive);
2623 if (pMenuGuild) pMenuGuild->setGrayed (!guildActive);
2625 // Remove existing dynamic chats
2626 while (pMenu->getNumLine() > 5)
2628 pMenu->deleteLine(pMenu->getNumLine()-1);
2631 // Add dynamic chats
2632 uint insertion_index = 0;
2633 for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
2635 string s = toString(i);
2636 uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(i);
2637 bool active = (textId != 0);
2638 if (active)
2640 uint32 canWrite = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:DYN_CHAT:CHANNEL"+s+":WRITE_RIGHT")->getValue32();
2641 if (canWrite != 0)
2643 string title;
2644 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
2646 // replace dynamic channel name and shortcut
2647 string res = CI18N::get("uiFilterMenuDynamic");
2648 strFindReplace(res, "%channel", title);
2649 strFindReplace(res, "%shortcut", s);
2651 pMenu->addLineAtIndex(5 + insertion_index, res, "chat_target_selected", "dyn"+s, "dyn"+s);
2652 insertion_index++;
2658 // activate the menu
2659 CWidgetManager::getInstance()->enableModalWindow(pCaller, menuName);
2662 REGISTER_ACTION_HANDLER( CHandlerSelectChatTarget, "select_chat_target");
2664 //=================================================================================================================
2665 /** A target has been selected for a filtered chat
2667 class CHandlerChatTargetSelected : public IActionHandler
2669 void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
2671 // for now, manage a single filtered chat window
2672 CChatWindow *cw = ChatWindowForFilter;
2673 if (!cw) return;
2674 ChatWindowForFilter = NULL;
2675 CFilteredChat *fc = PeopleInterraction.getFilteredChatFromChatWindow(cw);
2676 if (!fc) return;
2677 CChatTargetFilter &cf = fc->Filter;
2678 // Team
2679 if (nlstricmp(sParams, "team") == 0)
2681 cf.setTargetGroup(CChatGroup::team);
2683 // Guild
2684 else if (nlstricmp(sParams, "guild") == 0)
2686 cf.setTargetGroup(CChatGroup::guild);
2688 // Say
2689 else if (nlstricmp(sParams, "say") == 0)
2691 cf.setTargetGroup(CChatGroup::say);
2693 // Shout
2694 else if (nlstricmp(sParams, "shout") == 0)
2696 cf.setTargetGroup(CChatGroup::shout);
2698 // Region
2699 else if (nlstricmp(sParams, "region") == 0)
2701 cf.setTargetGroup(CChatGroup::region);
2703 // Universe
2704 else if (nlstricmp(sParams, "universe") == 0)
2706 cf.setTargetGroup(CChatGroup::universe);
2708 else
2710 for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
2712 if (nlstricmp(sParams, "dyn"+toString("%d", i)) == 0)
2714 cf.setTargetGroup(CChatGroup::dyn_chat, i);
2719 // Case of user chat in grouped chat window
2720 if (cw == PeopleInterraction.ChatGroup.Window)
2722 PeopleInterraction.TheUserChat.Filter.setTargetGroup(cf.getTargetGroup(), cf.getTargetDynamicChannelDbIndex());
2723 CAHManager::getInstance()->runActionHandler("chat_group_filter", NULL, "user");
2725 if (cw == PeopleInterraction.TheUserChat.Window)
2727 PeopleInterraction.TheUserChat.Filter.setTargetGroup(cf.getTargetGroup(), cf.getTargetDynamicChannelDbIndex());
2728 CAHManager::getInstance()->runActionHandler("user_chat_active", NULL, "");
2731 // The target should be a party chat
2732 int partyChatID;
2733 if (fromString(sParams, partyChatID))
2735 // search party chat in the list
2736 std::vector<CPartyChatInfo> &partyChats = PeopleInterraction.PartyChats;
2737 for(uint k = 0; k < partyChats.size(); ++k)
2739 if (partyChats[k].ID == (uint) partyChatID)
2741 cf.setTargetPartyChat(partyChats[k].Window);
2742 return;
2745 // The party chat has been deleted while the menu was displayed it seems.. -> no-op
2746 return;
2750 REGISTER_ACTION_HANDLER( CHandlerChatTargetSelected, "chat_target_selected");
2753 //=================================================================================================================
2754 /** If no more in team, leave team chat mode
2756 class CHandlerLeaveTeamChat : public IActionHandler
2758 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
2760 if( PeopleInterraction.TheUserChat.Filter.getTargetGroup() == CChatGroup::team )
2762 CInterfaceManager *im = CInterfaceManager::getInstance();
2763 if( im )
2765 if( !NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:IS_TEAM_PRESENT")->getValueBool() )
2767 ChatMngr.updateChatModeAndButton(CChatGroup::say);
2773 REGISTER_ACTION_HANDLER( CHandlerLeaveTeamChat, "leave_team_chat");
2779 /** Create checkbox for a menu.
2781 static CInterfaceGroup *createMenuCheckBox(const std::string &onclickL, const std::string &paramsL, bool checked)
2783 pair<string, string> params [2];
2784 params[0].first = "onclick_l";
2785 params[0].second = onclickL;
2786 params[1].first = "params_l";
2787 params[1].second = paramsL;
2789 CInterfaceManager *im = CInterfaceManager::getInstance();
2790 CInterfaceGroup *ig = CWidgetManager::getInstance()->getParser()->createGroupInstance("menu_checkbox", "", params, sizeof(params) / sizeof(params[0]));
2791 if (!ig) return NULL;
2792 CCtrlBaseButton *cb = dynamic_cast<CCtrlBaseButton *>(ig->getCtrl("b"));
2793 if (!cb) return NULL;
2794 cb->setPushed(checked);
2795 return ig;
2800 //=================================================================================================================
2801 /** Display a menu to select the source on a filtered chat
2803 class CHandlerSelectChatSource : public IActionHandler
2805 void execute (CCtrlBase *pCaller, const std::string &/* sParams */)
2807 static const char *FILTER_TOGGLE = "chat_source_selected";
2808 CPeopleInterraction &pi = PeopleInterraction;
2809 CChatWindow *cw = getChatWndMgr().getChatWindowFromCaller(pCaller);
2810 if (!cw) return;
2811 ChatWindowForFilter = cw;
2812 CInterfaceManager *im = CInterfaceManager::getInstance();
2815 // *** get the main_chat or user_chat menu
2816 CGroupMenu *menu= NULL;
2817 bool addUserChatEntries= false;
2818 // If the current window is the chat group
2819 if (cw == pi.ChatGroup.Window)
2821 // select main chat menu
2822 menu = dynamic_cast<CGroupMenu *>(CWidgetManager::getInstance()->getElementFromId(MAIN_CHAT_SOURCE_MENU));
2824 // Remove all unused dynamic channels and set the names
2825 for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
2827 string s = toString(i);
2828 CViewTextMenu *pVTM = dynamic_cast<CViewTextMenu *>(CWidgetManager::getInstance()->getElementFromId(MAIN_CHAT_SOURCE_MENU+":tab:dyn"+s));
2829 if (pVTM)
2831 uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(i);
2832 bool active = (textId != 0);
2833 pVTM->setActive(active);
2834 if (active)
2836 string title;
2837 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
2838 pVTM->setText("["+s+"] " + title);
2843 // Menu with Filters
2844 CChatGroupWindow *pWin = pi.getChatGroupWindow();
2845 if (pWin->getTabIndex() == 5) // (5 == user) -> complete menu
2847 // get the real user chat setup
2848 cw = pi.TheUserChat.Window;
2849 addUserChatEntries= true;
2851 else
2853 // Don't add user chat since the selected TAB is not the user chat
2854 addUserChatEntries= false;
2857 else
2859 // Menu with Filters
2860 if (cw == pi.TheUserChat.Window)
2862 // select user chat menu
2863 menu = dynamic_cast<CGroupMenu *>(CWidgetManager::getInstance()->getElementFromId(USER_CHAT_SOURCE_MENU));
2864 addUserChatEntries= true;
2866 // Simple menu
2867 else
2869 // This is neither the ChatGroup, nor the UserChat. Should not be here.
2870 // Just open the STD chat menu, and quit
2871 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:GC_POPUP")->setValue64(cw->getContainer()->isPopuped() || cw->getContainer()->getLayerSetup() == 0 ? 1 : 0);
2872 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:GC_HAS_HELP")->setValue64(!cw->getContainer()->getHelpPage().empty());
2873 CWidgetManager::getInstance()->enableModalWindow(pCaller, STD_CHAT_SOURCE_MENU);
2874 return;
2877 if (!menu) return;
2880 // *** remove any previous entries
2881 for(uint k = 0; k < menu->getNumLine();)
2883 if (nlstricmp(FILTER_TOGGLE, menu->getActionHandler(k)) == 0)
2885 menu->deleteLine(k);
2887 else
2889 ++k;
2894 // *** create new entries
2895 if(addUserChatEntries)
2897 uint insertionIndex = 0;
2898 // AROUND ME
2899 menu->addLineAtIndex(insertionIndex, CI18N::get("uiAroundMe"), FILTER_TOGGLE, "am");
2900 // add a checkbox
2901 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "am", pi.ChatInput.AroundMe.isListeningWindow(cw)));
2902 ++ insertionIndex;
2904 // REGION
2905 menu->addLineAtIndex(insertionIndex, CI18N::get("uiREGION"), FILTER_TOGGLE, "region");
2906 // add a checkbox
2907 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "region", pi.ChatInput.Region.isListeningWindow(cw)));
2908 ++ insertionIndex;
2910 // UNIVERSE
2911 menu->addLineAtIndex(insertionIndex, CI18N::get("uiUNIVERSE"), FILTER_TOGGLE, "universe");
2912 // add a checkbox
2913 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "universe", pi.ChatInput.Universe.isListeningWindow(cw)));
2914 ++ insertionIndex;
2916 // TEAM
2917 menu->addLineAtIndex(insertionIndex, CI18N::get("uiTeam"), FILTER_TOGGLE, "team");
2918 // add a checkbox
2919 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "team", pi.ChatInput.Team.isListeningWindow(cw)));
2920 ++insertionIndex;
2922 // GUILD
2923 menu->addLineAtIndex(insertionIndex, CI18N::get("uimGuild"), FILTER_TOGGLE, "guild");
2924 // add a checkbox
2925 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "guild", pi.ChatInput.Guild.isListeningWindow(cw)));
2926 ++ insertionIndex;
2929 // TELL
2930 //menu->addLineAtIndex(insertionIndex, CI18N::get("uiTell"), FILTER_TOGGLE, "tell");
2931 // add a checkbox
2932 //menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "tell", pi.ChatInput.Tell.isListeningWindow(cw)));
2933 //++ insertionIndex;
2935 // SYSTEM INFOS
2936 menu->addLineAtIndex(insertionIndex, CI18N::get("uiSystemInfo"), FILTER_TOGGLE, "si");
2937 // add a checkbox
2938 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "si", pi.ChatInput.SystemInfo.isListeningWindow(cw)));
2939 ++insertionIndex;
2941 // add party chats
2942 std::vector<CPartyChatInfo> &pc = pi.PartyChats;
2943 for(uint l = 0; l < pc.size(); ++l)
2945 if (pc[l].Filter != NULL)
2947 menu->addLineAtIndex(insertionIndex, pc[l].Window->getTitle(), FILTER_TOGGLE, toString(pc[l].ID));
2948 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, toString(pc[l].ID), pc[l].Filter->isListeningWindow(cw)));
2949 ++ insertionIndex;
2953 // Add all existing dynamic channels and set the names
2954 for (uint8 i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
2956 string s = toString(i);
2957 uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(i);
2958 bool active = (textId != 0);
2959 if (active)
2961 string title;
2962 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
2963 menu->addLineAtIndex(insertionIndex, "["+s+"] " + title, FILTER_TOGGLE, "dyn"+s);
2964 menu->setUserGroupLeft(insertionIndex, createMenuCheckBox(FILTER_TOGGLE, "dyn"+s, pi.ChatInput.DynamicChat[i].isListeningWindow(cw)));
2965 ++insertionIndex;
2972 // *** active the menu
2973 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:GC_POPUP")->setValue64(cw->getContainer()->isPopuped() || cw->getContainer()->getLayerSetup() == 0 ? 1 : 0);
2974 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:GC_HAS_HELP")->setValue64(!cw->getContainer()->getHelpPage().empty());
2975 CWidgetManager::getInstance()->enableModalWindow(pCaller, menu);
2978 REGISTER_ACTION_HANDLER(CHandlerSelectChatSource, "select_chat_source");
2982 //=================================================================================================================
2983 /** A new source has been selected / unselected from a filtered chat
2985 class CHandlerChatSourceSelected : public IActionHandler
2987 void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
2989 int partyChatID;
2991 CChatWindow *cw = ChatWindowForFilter;
2992 if (!cw) return;
2994 CChatStdInput &ci = PeopleInterraction.ChatInput;
2997 if (cw == PeopleInterraction.ChatGroup.Window)
2999 CChatGroupWindow *pWin = PeopleInterraction.getChatGroupWindow();
3000 if (pWin->getTabIndex() != 5) // (5 == user)
3001 return; // Nothing to select except if user chat
3003 cw = PeopleInterraction.TheUserChat.Window;
3007 /*CCtrlBaseButton *button = dynamic_cast<CCtrlBaseButton *>(pCaller);
3008 if (button)
3010 button->setPushed(!button->getPushed());
3012 // GUILD
3013 if (nlstricmp(sParams, "guild") == 0)
3015 if (ci.Guild.isListeningWindow(cw)) ci.Guild.removeListeningWindow(cw);
3016 else ci.Guild.addListeningWindow(cw);
3018 else
3019 // TEAM
3020 if (nlstricmp(sParams, "team") == 0)
3022 if (ci.Team.isListeningWindow(cw)) ci.Team.removeListeningWindow(cw);
3023 else ci.Team.addListeningWindow(cw);
3025 else
3026 // AROUND ME
3027 if (nlstricmp(sParams, "am") == 0)
3029 if (ci.AroundMe.isListeningWindow(cw)) ci.AroundMe.removeListeningWindow(cw);
3030 else ci.AroundMe.addListeningWindow(cw);
3032 else
3033 // REGION
3034 if (nlstricmp(sParams, "region") == 0)
3036 if (ci.Region.isListeningWindow(cw)) ci.Region.removeListeningWindow(cw);
3037 else ci.Region.addListeningWindow(cw);
3039 else
3040 // UNIVERSE
3041 if (nlstricmp(sParams, "universe") == 0)
3043 if (ci.Universe.isListeningWindow(cw)) ci.Universe.removeListeningWindow(cw);
3044 else ci.Universe.addListeningWindow(cw);
3046 else
3047 // TELL
3048 if (nlstricmp(sParams, "tell") == 0)
3050 if (ci.Tell.isListeningWindow(cw)) ci.Tell.removeListeningWindow(cw);
3051 else ci.Tell.addListeningWindow(cw);
3053 else
3054 // SYSTEM INFOS
3055 if (nlstricmp(sParams, "si") == 0)
3057 if (ci.SystemInfo.isListeningWindow(cw)) ci.SystemInfo.removeListeningWindow(cw);
3058 else ci.SystemInfo.addListeningWindow(cw);
3060 else
3061 // PARTY CHAT
3062 if (fromString(sParams, partyChatID))
3064 std::vector<CPartyChatInfo> &partyChats = PeopleInterraction.PartyChats;
3065 for(uint k = 0; k < partyChats.size(); ++k)
3067 if (partyChats[k].ID == (uint) partyChatID)
3069 if (partyChats[k].Filter != NULL)
3071 if (partyChats[k].Filter->isListeningWindow(cw)) partyChats[k].Filter->removeListeningWindow(partyChats[k].Window);
3072 else partyChats[k].Filter->addListeningWindow(cw);
3077 else if (nlstricmp(sParams.substr(0, 3), "dyn") == 0)
3079 uint8 i = 0;
3080 fromString(sParams.substr(3), i);
3081 if (ci.DynamicChat[i].isListeningWindow(cw)) ci.DynamicChat[i].removeListeningWindow(cw);
3082 else ci.DynamicChat[i].addListeningWindow(cw);
3086 REGISTER_ACTION_HANDLER( CHandlerChatSourceSelected, "chat_source_selected");
3089 // show / hide the edit/box of a chatbox
3090 class CHandlerToggleChatEBVis : public IActionHandler
3092 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
3094 CCtrlBase *clm = CWidgetManager::getInstance()->getCtrlLaunchingModal();
3095 if (!clm) return;
3096 CInterfaceGroup *ig = clm->getParent();
3099 if (ig->isGroupContainer()) break;
3100 ig = ig->getParent();
3102 while(ig);
3103 if (!ig) return;
3104 CGroupContainer *gc = static_cast<CGroupContainer *>(ig);
3105 CInterfaceGroup *eb = gc->getGroup("ebw");
3106 if (eb)
3108 eb->setActive(!eb->getActive());
3110 CCtrlBase *tb = gc->getCtrl("target_button");
3111 if (tb)
3113 tb->setActive(!tb->getActive());
3117 REGISTER_ACTION_HANDLER( CHandlerToggleChatEBVis, "toggle_chat_eb_vis");
3119 // create a new user chat
3120 class CHandlerNewUserChat : public IActionHandler
3122 void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
3124 CPeopleInterraction &pi = PeopleInterraction;
3125 for(uint k = 0; k < MaxNumUserChats; ++k)
3127 if (pi.UserChat[k].Window == NULL) // not used ?
3129 pi.createUserChat(k);
3130 // add to std listeners
3131 pi.ChatInput.registerListeningWindow(pi.UserChat[k].Window);
3132 CGroupContainer *gc = pi.UserChat[k].Window->getContainer();
3133 gc->setOpen(true);
3134 gc->popupCurrentPos();
3135 gc->updateCoords();
3136 gc->center();
3137 // change pos by a random amount
3138 gc->setX(gc->getX() + rand() % 20 - 10);
3139 gc->setY(gc->getY() + rand() % 20 - 10);
3140 gc->invalidateCoords();
3141 gc->enableBlink(2);
3142 pi.UserChat[k].Window->setKeyboardFocus();
3143 return;
3146 nlwarning("Too much user chats created");
3149 REGISTER_ACTION_HANDLER(CHandlerNewUserChat, "new_user_chat");
3151 class CHandlerRemoveUserChat : public IActionHandler
3153 void execute (CCtrlBase *pCaller, const std::string &/* sParams */)
3155 CPeopleInterraction &pi = PeopleInterraction;
3156 CChatWindow *cw = getChatWndMgr().getChatWindowFromCaller(pCaller);
3157 if (!cw) return;
3158 CFilteredChat *fc = pi.getFilteredChatFromChatWindow(cw);
3159 if (!fc) return;
3160 getChatWndMgr().removeChatWindow(fc->Window);
3161 fc->Filter.reset();
3162 fc->Window = NULL;
3165 REGISTER_ACTION_HANDLER(CHandlerRemoveUserChat, "remove_user_chat");
3167 ////////////////////////////////////////////
3168 // COMMAND RELATED TO PEOPLE INTERRACTION //
3169 ////////////////////////////////////////////
3172 //-----------------------------------------------
3173 // 'ignore'
3174 //-----------------------------------------------
3175 NLMISC_COMMAND(ignore, "add or remove a player from the ignore list", "<player name>")
3177 // Check parameters.
3178 if(args.size() < 1)
3180 return false;
3183 // NB: playernames cannot have special characters
3184 const string &playerName = args[0];
3186 // add to the ignore list
3187 PeopleInterraction.askAddContact(playerName, &PeopleInterraction.IgnoreList);
3189 return true;
3190 } // ignore //
3193 ****
3194 Yoyo: Party chat is not ended: DON'T LET THOSE COMMANDS AVAILABLE!
3195 they made the client crash (cf createNewPartyChat)...
3196 ****
3198 // create a new party chat with the given name
3199 NLMISC_COMMAND(party_chat, "Create a new party chat", "<party_chat_name>")
3201 if (args.size() != 1)
3203 displayVisibleSystemMsg(CI18N::get("uiPartyChatCmd"));
3204 return true;
3206 CPeopleInterraction &pi = PeopleInterraction;
3207 string title = args[0];
3209 if (!pi.testValidPartyChatName(title))
3211 displayVisibleSystemMsg(CI18N::get("uiInvalidPartyChatName"));
3212 return true;
3215 PeopleInterraction.createNewPartyChat(title);
3216 return true;
3219 // Remove the party chat with the given name
3220 NLMISC_COMMAND(remove_party_chat, "Remove a party chat", "<party_chat_name>")
3222 if (args.size() != 1)
3224 displayVisibleSystemMsg(CI18N::get("uiRemovePartyChatCmd"));
3225 return true;
3227 string title = ucstring(args[0]);
3228 CChatWindow *chat = getChatWndMgr().getChatWindow(title);
3229 if (!chat)
3231 displayVisibleSystemMsg(title + " : " + CI18N::get("uiBadPartyChatName"));
3232 return true;
3234 if (!PeopleInterraction.removePartyChat(chat))
3236 displayVisibleSystemMsg(title + " : " + CI18N::get("uiCantRemovePartyChat"));
3237 return true;
3239 return true;
3243 // Join a party chat whose name is known
3244 NLMISC_COMMAND(add_to_party_chat, "Join the given party chat", "<party_chat_name>")
3246 if (args.size() != 1)
3248 displayVisibleSystemMsg(CI18N::get("uiAddPartyChatCmd"));
3249 return true;
3251 // TODO GAMEDEV : join the party chat
3252 return true;
3255 // Invite someone in a party chat
3256 NLMISC_COMMAND(invite, "Invite someone to a party chat", "<people_name> <party_chat_name>")
3258 if (args.size() != 2)
3260 displayVisibleSystemMsg(CI18N::get("uiInviteCmd"));
3261 return true;
3263 // TODO GAMEDEV : Send invite message to the server
3264 // Check that the inviter has created the chat ?
3265 // The people being invited should receive a popup to announce that he is being invited
3266 return true;
3271 // ***************************************************************************
3272 // chatLog
3273 // Arg : none
3274 // log all current chats in the file log_playername.txt saved in save directory
3275 // ***************************************************************************
3276 NLMISC_COMMAND(chatLog, "", "")
3278 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3280 if(args.size() != 0)
3281 return false;
3283 if (pIM->getLogState())
3284 pIM->displaySystemInfo(CI18N::get("uiLogTurnedOff"));
3286 pIM->setLogState(!pIM->getLogState());
3288 if (pIM->getLogState())
3289 pIM->displaySystemInfo(CI18N::get("uiLogTurnedOn"));
3291 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHATLOG_STATE", false);
3292 if (node)
3294 node->setValue32(pIM->getLogState() ? 1 : 0);
3297 return true;
3301 /////////////////////////
3302 // INTERFACE FUNCTIONS //
3303 /////////////////////////
3304 static DECLARE_INTERFACE_USER_FCT(getNumUserChatLeft)
3306 CPeopleInterraction &pi = PeopleInterraction;
3307 uint left = 0;
3308 for(uint k = 0; k < MaxNumUserChats; ++k)
3310 if (pi.UserChat[k].Window == NULL) ++ left;
3312 result.setInteger(left);
3313 return true;
3315 REGISTER_INTERFACE_USER_FCT("getNumUserChatLeft", getNumUserChatLeft)
3318 //////////////////////////////////////
3319 // STATIC FUNCTIONS IMPLEMENTATIONS //
3320 //////////////////////////////////////
3322 static void displayVisibleSystemMsg(const string &msg, const string &cat)
3324 CInterfaceManager *im = CInterfaceManager::getInstance();
3325 im->displaySystemInfo(msg, cat);
3326 if (CChatWindow::getChatWindowLaunchingCommand())
3328 CChatWindow::getChatWindowLaunchingCommand()->displayMessage(msg, im->getSystemInfoColor(cat), CChatGroup::system, 0, 2);
3332 #if !FINAL_VERSION
3333 NLMISC_COMMAND(testSI, "tmp", "tmp")
3335 PeopleInterraction.ChatInput.DebugInfo.displayMessage("test", CRGBA::Red);
3336 return true;
3338 #endif